UNPKG

@polygonjs/polygonjs

Version:

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

103 lines (102 loc) 3.81 kB
"use strict"; 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); } }