@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
225 lines (224 loc) • 8.78 kB
JavaScript
"use strict";
import { QuadSopNode } from "./_BaseQuad";
import { Vector3 } from "three";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { SopType } from "../../poly/registers/nodes/types/Sop";
import { QuadPrimitive } from "../../../core/geometry/modules/quad/QuadPrimitive";
import { primitivesFromObject } from "../../../core/geometry/entities/primitive/CorePrimitiveUtils";
import { Attribute } from "../../../core/geometry/Attribute";
import {
quadPrimitivePointPositions,
quadPrimitivePointIndices,
quadPointInset
} from "../../../core/geometry/modules/quad/utils/QuadUtils";
import { InputCloneMode } from "../../poly/InputCloneMode";
const _normal = new Vector3();
const _tmp = new Vector3();
const _primitives = [];
export const _indices = {
i0: 0,
i1: 0,
i2: 0,
i3: 0
};
export const _positions = {
p0: new Vector3(),
p1: new Vector3(),
p2: new Vector3(),
p3: new Vector3()
};
export const _insetPositions = {
p0: new Vector3(),
p1: new Vector3(),
p2: new Vector3(),
p3: new Vector3()
};
const _newPositions = [
new Vector3(),
new Vector3(),
new Vector3(),
new Vector3()
];
class QuadExtrudeSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param amount */
this.amount = ParamConfig.FLOAT(0, {
range: [-1, 1],
rangeLocked: [false, false]
});
/** @param inset */
this.inset = ParamConfig.FLOAT(0, {
range: [-1, 1],
rangeLocked: [false, false]
});
/** @param output side */
this.sides = ParamConfig.BOOLEAN(1);
}
}
const ParamsConfig = new QuadExtrudeSopParamsConfig();
export class QuadExtrudeSopNode extends QuadSopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
}
static type() {
return SopType.QUAD_EXTRUDE;
}
initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE);
}
cook(inputCoreGroups) {
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);
}
_extrudeObject(quadObject) {
primitivesFromObject(quadObject, _primitives);
const originalPrimitivesCount = _primitives.length;
const geometry = quadObject.geometry;
const sides = this.pv.sides;
const indices = geometry.index;
let _newIndicesIndex = indices.length;
indices.length += _primitives.length * 4 * (sides ? 5 : 1);
const positionAttribute = geometry.attributes[Attribute.POSITION];
let newPointIndex = positionAttribute.array.length / 3;
let newIndexValue = newPointIndex;
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 = [...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];
vertexAttribute.array.length += _primitives.length * 4;
}
}
const positionArray = positionAttribute.array;
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);
const _setPrimitiveAttributes = (targetIndex) => {
if (!(primitiveAttributes && primitiveAttributeNames)) {
return;
}
for (const primitiveAttributeName of primitiveAttributeNames) {
const primitiveAttribute = primitiveAttributes[primitiveAttributeName];
const array = primitiveAttribute.array;
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];
}
}
};
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) {
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++;
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++;
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++;
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) => {
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) {
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];
}
}
newPosition.toArray(positionArray, newPointIndex * 3);
newPointIndex++;
i++;
}
newIndexValue += 4;
}
}
}