UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

264 lines (245 loc) 9.18 kB
/** * Extrudes quads. * * */ import {QuadSopNode} from './_BaseQuad'; import {Vector3} from 'three'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {CoreGroup} from '../../../core/geometry/Group'; import {SopType} from '../../poly/registers/nodes/types/Sop'; import {QuadGeometry} from '../../../core/geometry/modules/quad/QuadGeometry'; import {QuadObject} from '../../../core/geometry/modules/quad/QuadObject'; import {QuadPrimitive} from '../../../core/geometry/modules/quad/QuadPrimitive'; import {primitivesFromObject} from '../../../core/geometry/entities/primitive/CorePrimitiveUtils'; import {Attribute} from '../../../core/geometry/Attribute'; import { QuadPrimitivePointPositions, quadPrimitivePointPositions, QuadPrimitivePointIndices, quadPrimitivePointIndices, quadPointInset, } from '../../../core/geometry/modules/quad/utils/QuadUtils'; import {InputCloneMode} from '../../poly/InputCloneMode'; const _normal = new Vector3(); const _tmp = new Vector3(); const _primitives: QuadPrimitive[] = []; export const _indices: QuadPrimitivePointIndices = { i0: 0, i1: 0, i2: 0, i3: 0, }; export const _positions: QuadPrimitivePointPositions = { p0: new Vector3(), p1: new Vector3(), p2: new Vector3(), p3: new Vector3(), }; export const _insetPositions: QuadPrimitivePointPositions = { p0: new Vector3(), p1: new Vector3(), p2: new Vector3(), p3: new Vector3(), }; const _newPositions: [Vector3, Vector3, Vector3, Vector3] = [ new Vector3(), new Vector3(), new Vector3(), new Vector3(), ]; class QuadExtrudeSopParamsConfig extends NodeParamsConfig { /** @param amount */ amount = ParamConfig.FLOAT(0, { range: [-1, 1], rangeLocked: [false, false], }); /** @param inset */ inset = ParamConfig.FLOAT(0, { range: [-1, 1], rangeLocked: [false, false], }); /** @param output side */ sides = ParamConfig.BOOLEAN(1); } const ParamsConfig = new QuadExtrudeSopParamsConfig(); export class QuadExtrudeSopNode extends QuadSopNode<QuadExtrudeSopParamsConfig> { override paramsConfig = ParamsConfig; static override type() { return SopType.QUAD_EXTRUDE; } protected override initializeNode() { this.io.inputs.setCount(1); this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE); } override cook(inputCoreGroups: CoreGroup[]) { const coreGroup = inputCoreGroups[0]; const objects = coreGroup.quadObjects(); if (!objects) { this.states.error.set(`no quad objects found`); return; } for (const object of objects) { this._extrudeObject(object); } this.setQuadObjects(objects); } private _extrudeObject(quadObject: QuadObject) { primitivesFromObject(quadObject, _primitives); const originalPrimitivesCount = _primitives.length; const geometry: QuadGeometry = quadObject.geometry; const sides: boolean = this.pv.sides; // index const indices = geometry.index; // we add 5 new quad for each current quad let _newIndicesIndex = indices.length; indices.length += _primitives.length * 4 * (sides ? 5 : 1); // position const positionAttribute = geometry.attributes[Attribute.POSITION]; let newPointIndex = positionAttribute.array.length / 3; let newIndexValue = newPointIndex; // update attribute array lengths const pointAttributeNames = Object.keys(geometry.attributes); const additionalPointsCount = _primitives.length * 4; for (const pointAttributeName of pointAttributeNames) { const attribute = geometry.attributes[pointAttributeName]; const array = attribute.array; const additionalPointAttributeItemsCount = additionalPointsCount * attribute.itemSize; attribute.count += additionalPointsCount; const newValues: number[] = [...array]; newValues.length += additionalPointAttributeItemsCount; attribute.array = new Float32Array(newValues); } const primitiveAttributes = QuadPrimitive.attributesFromGeometry(geometry); const primitiveAttributeNames = primitiveAttributes ? Object.keys(primitiveAttributes) : null; if (primitiveAttributes && primitiveAttributeNames) { for (const primitiveAttributeName of primitiveAttributeNames) { const primitiveAttribute = primitiveAttributes[primitiveAttributeName]; primitiveAttribute.array.length += _primitives.length; } } const vertexAttributes = QuadPrimitive.attributesFromGeometry(geometry); const vertexAttributeNames = vertexAttributes ? Object.keys(vertexAttributes) : null; if (vertexAttributes && vertexAttributeNames) { for (const vertexAttributeName of vertexAttributeNames) { const vertexAttribute = vertexAttributes[vertexAttributeName]; // TODO: we currently add 4 new vertices per new primitive, // but that will change when we merge adjacent quads vertexAttribute.array.length += _primitives.length * 4; } } // ensure we have the new positionArray const positionArray = positionAttribute.array; // add primitives let newPrimitivesCount = 0; for (const primitive of _primitives) { primitive.normal(_normal); const primitiveIndex = primitive.index(); quadPrimitivePointIndices(quadObject, primitiveIndex, _indices); quadPrimitivePointPositions(quadObject, primitiveIndex, _positions); quadPointInset(_positions, this.pv.inset, _insetPositions); _tmp.copy(_normal).multiplyScalar(this.pv.amount); _newPositions[0].copy(_insetPositions.p0).add(_tmp); _newPositions[1].copy(_insetPositions.p1).add(_tmp); _newPositions[2].copy(_insetPositions.p2).add(_tmp); _newPositions[3].copy(_insetPositions.p3).add(_tmp); // TODO: set vertex attributes // primitive attributes const _setPrimitiveAttributes = (targetIndex: number) => { if (!(primitiveAttributes && primitiveAttributeNames)) { return; } for (const primitiveAttributeName of primitiveAttributeNames) { const primitiveAttribute = primitiveAttributes[primitiveAttributeName]; const array = primitiveAttribute.array as number[]; const itemSize = primitiveAttribute.itemSize; for (let k = 0; k < itemSize; k++) { const srcIndex = primitiveIndex * itemSize + k; const destIndex = targetIndex * itemSize + k; array[destIndex] = array[srcIndex]; } } }; // index // - extruded face const currentPrimitiveIndex = _newIndicesIndex; indices[_newIndicesIndex] = newIndexValue; indices[_newIndicesIndex + 1] = newIndexValue + 1; indices[_newIndicesIndex + 2] = newIndexValue + 2; indices[_newIndicesIndex + 3] = newIndexValue + 3; _setPrimitiveAttributes(originalPrimitivesCount + newPrimitivesCount); _newIndicesIndex += 4; newPrimitivesCount++; if (sides == true) { // - side face 0 indices[_newIndicesIndex] = _indices.i0; indices[_newIndicesIndex + 1] = _indices.i1; indices[_newIndicesIndex + 2] = indices[currentPrimitiveIndex + 1]; indices[_newIndicesIndex + 3] = indices[currentPrimitiveIndex]; _setPrimitiveAttributes(originalPrimitivesCount + newPrimitivesCount); _newIndicesIndex += 4; newPrimitivesCount++; // - side face 1 indices[_newIndicesIndex] = _indices.i1; indices[_newIndicesIndex + 1] = _indices.i2; indices[_newIndicesIndex + 2] = indices[currentPrimitiveIndex + 2]; indices[_newIndicesIndex + 3] = indices[currentPrimitiveIndex + 1]; _setPrimitiveAttributes(originalPrimitivesCount + newPrimitivesCount); _newIndicesIndex += 4; newPrimitivesCount++; // - side face 2 indices[_newIndicesIndex] = _indices.i2; indices[_newIndicesIndex + 1] = _indices.i3; indices[_newIndicesIndex + 2] = indices[currentPrimitiveIndex + 3]; indices[_newIndicesIndex + 3] = indices[currentPrimitiveIndex + 2]; _setPrimitiveAttributes(originalPrimitivesCount + newPrimitivesCount); _newIndicesIndex += 4; newPrimitivesCount++; // - side face 3 indices[_newIndicesIndex] = _indices.i3; indices[_newIndicesIndex + 1] = _indices.i0; indices[_newIndicesIndex + 2] = indices[currentPrimitiveIndex]; indices[_newIndicesIndex + 3] = indices[currentPrimitiveIndex + 3]; _setPrimitiveAttributes(originalPrimitivesCount + newPrimitivesCount); _newIndicesIndex += 4; newPrimitivesCount++; } const _pointIndex = (_i: number) => { switch (_i) { case 0: return _indices.i0; case 1: return _indices.i1; case 2: return _indices.i2; case 3: return _indices.i3; } return -1; }; let i = 0; for (const newPosition of _newPositions) { // point attributes for (const pointAttributeName of pointAttributeNames) { if (pointAttributeName == Attribute.POSITION) { continue; } const attribute = geometry.attributes[pointAttributeName]; const array = attribute.array; const itemSize = attribute.itemSize; for (let k = 0; k < itemSize; k++) { const pointIndex = _pointIndex(i); const srcIndex = pointIndex * itemSize + k; const destIndex = newPointIndex * itemSize + k; array[destIndex] = array[srcIndex]; } } // position newPosition.toArray(positionArray, newPointIndex * 3); newPointIndex++; i++; } newIndexValue += 4; } } }