@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
103 lines (102 loc) • 3.81 kB
JavaScript
;
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { InputCloneMode } from "../../poly/InputCloneMode";
import { SopType } from "../../poly/registers/nodes/types/Sop";
import { ClothGeometryAttributeName } from "../../../core/cloth/ClothAttribute";
import { TypedSopNode } from "./_Base";
import { mergeFaces } from "../../../core/geometry/operation/Fuse";
import { BufferAttribute } from "three";
import { Attribute } from "../../../core/geometry/Attribute";
import { populateAdjacency3, POPULATE_ADJACENCY_DEFAULT } from "../../../core/geometry/operation/Adjacency";
import { corePointClassFactory } from "../../../core/geometry/CoreObjectFactory";
import { pointsFromObject } from "../../../core/geometry/entities/point/CorePointUtils";
class ClothPrepareSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
this.fuseDist = ParamConfig.FLOAT(1e-3);
this.viscosity = ParamConfig.FLOAT(0.1, {
range: [0, 1],
rangeLocked: [true, false],
expression: { forEntities: true }
});
this.spring = ParamConfig.FLOAT(2, {
range: [0, 5],
rangeLocked: [true, false],
expression: { forEntities: true }
});
}
}
const ParamsConfig = new ClothPrepareSopParamsConfig();
export class ClothPrepareSopNode extends TypedSopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
}
static type() {
return SopType.CLOTH_PREPARE;
}
initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE);
}
async cook(inputCoreGroups) {
const coreGroup = inputCoreGroups[0];
const inputMeshes = coreGroup.threejsObjectsWithGeo();
for (const inputMesh of inputMeshes) {
const geometry = inputMesh.geometry;
if (!geometry) {
return;
}
this._applyFuse(inputMesh);
this._addIdAttribute(inputMesh);
this._addViscosityAttribute(inputMesh);
this._addSpringAttribute(inputMesh);
this._addAdjacencyAttributes(inputMesh);
}
this.setCoreGroup(coreGroup);
}
_applyFuse(mesh) {
mergeFaces(mesh.geometry, this.pv.fuseDist);
}
async _addIdAttribute(mesh) {
const geometry = mesh.geometry;
const positionAttrib = geometry.getAttribute(Attribute.POSITION);
if (!positionAttrib) {
return;
}
const pointsCount = positionAttrib.count;
const idValues = new Array(pointsCount);
for (let i = 0; i < pointsCount; i++) {
idValues[i] = i;
}
const idArray = new Float32Array(idValues);
geometry.setAttribute(Attribute.ID, new BufferAttribute(idArray, 1));
}
async _addViscosityAttribute(mesh) {
await this._addFloatAttribute(mesh, this.p.viscosity, ClothGeometryAttributeName.VISCOSITY);
}
async _addSpringAttribute(mesh) {
await this._addFloatAttribute(mesh, this.p.spring, ClothGeometryAttributeName.SPRING);
}
async _addFloatAttribute(mesh, param, attribName) {
const corePointClass = corePointClassFactory(mesh);
if (param.hasExpression() && param.expressionController) {
if (!corePointClass.hasAttribute(mesh, attribName)) {
corePointClass.addNumericAttribute(mesh, attribName, 1, param.value);
}
const attrib = corePointClass.attribute(mesh, attribName);
attrib.needsUpdate = true;
const array = attrib.array;
const points = [];
pointsFromObject(mesh, points);
await param.expressionController.computeExpressionForPoints(points, (point, value) => {
array[point.index()] = value;
});
} else {
corePointClass.addNumericAttribute(mesh, attribName, 1, param.value);
}
}
_addAdjacencyAttributes(mesh) {
populateAdjacency3(mesh, POPULATE_ADJACENCY_DEFAULT);
}
}