UNPKG

@polygonjs/polygonjs

Version:

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

236 lines (235 loc) 8.71 kB
"use strict"; import { CorePhysicsJoinAttribute, PhysicsJointType, PHYSICS_JOINT_TYPE_MENU_ENTRIES, PHYSICS_JOINT_TYPES } from "../../../core/physics/PhysicsJoint"; import { CorePhysicsAttribute } from "../../../core/physics/PhysicsAttribute"; import { TypedSopNode } from "./_Base"; import { addToSetAtEntry, mapIncrementAtEntry } from "../../../core/MapUtils"; import { isBooleanTrue } from "../../../core/Type"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { InputCloneMode } from "../../poly/InputCloneMode"; import { Vector4, Vector3, Group, Box3, Matrix4, Quaternion } from "three"; import { CoreMask } from "../../../core/geometry/Mask"; import { SopType } from "../../poly/registers/nodes/types/Sop"; const center = new Vector3(); const tmpV3_1 = new Vector3(); const tmpV3_2 = new Vector3(); const tmpQuat = new Quaternion(); const frame1 = new Vector4(); const frame2 = new Vector4(); const axis = new Vector3(); const bbox = new Box3(); const _mat = new Matrix4(); function quaternionToVector4(quaternion, target) { target.x = quaternion.x; target.y = quaternion.y; target.z = quaternion.z; target.w = quaternion.w; } const checkedPair = /* @__PURE__ */ new Map(); const jointsCountByKey = /* @__PURE__ */ new Map(); class PhysicsRBDJointsSopParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); /** @param group to assign the material to */ this.group = ParamConfig.STRING("", { objectMask: true }); /** @param maxDistance */ this.maxDistance = ParamConfig.FLOAT(1, { range: [0, 10] }); /** @param max number of joints per object */ this.maxJointsCount = ParamConfig.INTEGER(2, { range: [0, 10] }); /** @param joint type */ this.jointType = ParamConfig.INTEGER(PHYSICS_JOINT_TYPES.indexOf(PhysicsJointType.SPHERICAL), { menu: { entries: PHYSICS_JOINT_TYPE_MENU_ENTRIES } }); /** @param limit */ this.limit = ParamConfig.VECTOR2([-1, 1], { separatorBefore: true, visibleIf: [ { jointType: PHYSICS_JOINT_TYPES.indexOf(PhysicsJointType.REVOLUT) }, { jointType: PHYSICS_JOINT_TYPES.indexOf(PhysicsJointType.PRISMATIC) } ] }); /** @param up */ this.up = ParamConfig.VECTOR3([0, 1, 0], { visibleIf: [ { jointType: PHYSICS_JOINT_TYPES.indexOf(PhysicsJointType.REVOLUT) } ] }); /** @param center */ this.center = ParamConfig.FLOAT(0.5, { separatorBefore: true, visibleIf: [ { jointType: PHYSICS_JOINT_TYPES.indexOf(PhysicsJointType.SPHERICAL) }, { jointType: PHYSICS_JOINT_TYPES.indexOf(PhysicsJointType.REVOLUT) } ] }); /** @param anchors at objects center */ this.anchorsAtCenter = ParamConfig.BOOLEAN(1, {}); /** @param anchor position 1 */ this.anchorsPos1 = ParamConfig.VECTOR3([0.5, 0.5, 0.5], { visibleIf: { anchorsAtCenter: 0 } }); /** @param anchor position 2 */ this.anchorsPos2 = ParamConfig.VECTOR3([0.5, 0.5, 0.5], { visibleIf: { anchorsAtCenter: 0 } }); /** @param do not output input RBDs with joints */ this.ouputsJointsOnly = ParamConfig.BOOLEAN(0, { separatorBefore: true }); } } const ParamsConfig = new PhysicsRBDJointsSopParamsConfig(); export class PhysicsRBDJointsSopNode extends TypedSopNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; } static type() { return SopType.PHYSICS_RBD_JOINTS; } initializeNode() { this.io.inputs.setCount(1); this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE); } setJointType(RBDtype) { this.p.jointType.set(PHYSICS_JOINT_TYPES.indexOf(RBDtype)); } jointType() { return PHYSICS_JOINT_TYPES[this.pv.jointType]; } cook(inputCoreGroups) { const coreGroup = inputCoreGroups[0]; const inputObjects = coreGroup.allObjects(); const selectedObjects = CoreMask.filterThreejsObjects(coreGroup, this.pv); const candidateObjects = selectedObjects.filter((object) => CorePhysicsAttribute.getRBDId(object) != null); const joinObjects = []; const maxDistance = this.pv.maxDistance; const maxJointsCount = this.pv.maxJointsCount; checkedPair.clear(); jointsCountByKey.clear(); let maxJointsCountReached = false; let maxJointsCountReached1 = false; let maxJointsCountReached2 = false; let jointsCount1; let jointsCount2; let jointIndex = 0; let existingSet; for (let i1 = 0; i1 < candidateObjects.length; i1++) { const object1 = candidateObjects[i1]; for (let i2 = 0; i2 < candidateObjects.length; i2++) { const object2 = candidateObjects[i2]; if (i1 != i2) { jointsCount1 = jointsCountByKey.get(i1); jointsCount2 = jointsCountByKey.get(i2); maxJointsCountReached1 = jointsCount1 != null && jointsCount1 >= maxJointsCount; maxJointsCountReached2 = jointsCount2 != null && jointsCount2 >= maxJointsCount; maxJointsCountReached = maxJointsCountReached1 || maxJointsCountReached2; if (!maxJointsCountReached) { if (object1.position.distanceTo(object2.position) < maxDistance) { let key = i1 < i2 ? i1 : i2; let idInSet = i1 < i2 ? i2 : i1; existingSet = checkedPair.get(key); if (existingSet == null || !existingSet.has(idInSet)) { addToSetAtEntry(checkedPair, key, idInSet); const jointObject = this._createJoint(object1, object2); jointObject.name = `${this.name()}_${jointIndex}`; jointIndex++; joinObjects.push(jointObject); mapIncrementAtEntry(jointsCountByKey, i1, 0); mapIncrementAtEntry(jointsCountByKey, i2, 0); } } } } } } const allObjects = isBooleanTrue(this.pv.ouputsJointsOnly) ? joinObjects : [...inputObjects, ...joinObjects]; this.setObjects(allObjects); } _createJoint(object1, object2) { const group = new Group(); group.matrixAutoUpdate = false; CorePhysicsJoinAttribute.setRBDId1(group, CorePhysicsAttribute.getRBDId(object1)); CorePhysicsJoinAttribute.setRBDId2(group, CorePhysicsAttribute.getRBDId(object2)); const getAnchorPos = (object, paramValue, target) => { object.updateMatrix(); if (isBooleanTrue(this.pv.anchorsAtCenter)) { target.set(0, 0, 0); target.applyMatrix4(object.matrix); } else { _mat.copy(object.matrix); object.matrix.identity(); bbox.setFromObject(object); target.x = paramValue.x * bbox.max.x + (1 - paramValue.x) * bbox.min.x; target.y = paramValue.y * bbox.max.y + (1 - paramValue.y) * bbox.min.y; target.z = paramValue.z * bbox.max.z + (1 - paramValue.z) * bbox.min.z; object.matrix.copy(_mat); target.applyMatrix4(object.matrix); } }; getAnchorPos(object1, this.pv.anchorsPos1, tmpV3_1); getAnchorPos(object2, this.pv.anchorsPos2, tmpV3_2); center.copy(tmpV3_1).lerp(tmpV3_2, this.pv.center); axis.copy(tmpV3_2).sub(tmpV3_1).normalize(); const makeLocal = (object, target) => { _mat.copy(object.matrix).invert(); target.copy(center); target.applyMatrix4(_mat); }; makeLocal(object1, tmpV3_1); makeLocal(object2, tmpV3_2); CorePhysicsJoinAttribute.setAnchor1(group, tmpV3_1); CorePhysicsJoinAttribute.setAnchor2(group, tmpV3_2); const jointType = this.jointType(); CorePhysicsJoinAttribute.setJoinType(group, jointType); switch (jointType) { case PhysicsJointType.FIXED: { tmpQuat.copy(object1.quaternion); tmpQuat.slerp(object2.quaternion, 0.5); tmpQuat.invert(); quaternionToVector4(tmpQuat, frame1); tmpQuat.copy(object2.quaternion); tmpQuat.slerp(object1.quaternion, 0.5); tmpQuat.invert(); quaternionToVector4(tmpQuat, frame2); CorePhysicsJoinAttribute.setFrame1(group, frame1); CorePhysicsJoinAttribute.setFrame2(group, frame2); break; } case PhysicsJointType.PRISMATIC: { CorePhysicsJoinAttribute.setLimit(group, this.pv.limit); CorePhysicsJoinAttribute.setAxis(group, axis); break; } case PhysicsJointType.REVOLUT: { CorePhysicsJoinAttribute.setLimit(group, this.pv.limit); axis.cross(this.pv.up).normalize(); CorePhysicsJoinAttribute.setAxis(group, axis); break; } } return group; } }