UNPKG

@polygonjs/polygonjs

Version:

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

71 lines (62 loc) 2.63 kB
import {Mesh, Object3D} from 'three'; import type {InstancedMesh} from 'three'; import {BaseSopOperation} from './_Base'; import {CoreGroup} from '../../../core/geometry/Group'; import {InputCloneMode} from '../../../engine/poly/InputCloneMode'; import {DefaultOperationParams} from '../../../core/operations/_Base'; import {SopType} from '../../poly/registers/nodes/types/Sop'; import {copyObjectAllProperties} from '../../../core/geometry/modules/three/ThreejsObjectUtils'; import {isArray} from '../../../core/Type'; interface InstancedMeshToMeshSopParams extends DefaultOperationParams { cloneGeometry: boolean; } export class InstancedMeshToMeshSopOperation extends BaseSopOperation { static override readonly DEFAULT_PARAMS: InstancedMeshToMeshSopParams = { cloneGeometry: true, }; static override readonly INPUT_CLONED_STATE = [InputCloneMode.ALWAYS, InputCloneMode.NEVER]; static override type(): Readonly<SopType.INSTANCED_MESH_TO_MESH> { return SopType.INSTANCED_MESH_TO_MESH; } override async cook(coreGroups: CoreGroup[], params: InstancedMeshToMeshSopParams) { const coreGroup = coreGroups[0]; const inputObjects = coreGroup.threejsObjects(); const newObjects: Object3D[] = []; const childrenToRemove: Object3D[] = []; for (const inputObject of inputObjects) { inputObject.traverse((child) => { // in the editor, when importing a plugin, // we can end up with multiple threejs imported, // in which case instanceof would not work. // it is therefore preferable to check using .isInstancedMesh if ((child as InstancedMesh).isInstancedMesh) { childrenToRemove.push(child); const count = (child as InstancedMesh).count; const geometry = (child as InstancedMesh).geometry; const material = (child as InstancedMesh).material; for (let i = 0; i < count; i++) { const newMesh = copyObjectAllProperties(child, new Mesh()); (newMesh as Mesh).geometry = params.cloneGeometry ? geometry.clone() : geometry; (newMesh as Mesh).material = isArray(material) ? material[0] : material; (child as InstancedMesh).getMatrixAt(i, newMesh.matrix); newMesh.matrix.decompose(newMesh.position, newMesh.quaternion, newMesh.scale); const parent = child.parent; if (parent) { parent.add(newMesh); } else { newObjects.push(newMesh); } } } else { if (child === inputObject) { newObjects.push(child); } } }); } for (const childToRemove of childrenToRemove) { childToRemove.parent?.remove(childToRemove); } return this.createCoreGroupFromObjects(newObjects); } }