@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
71 lines (62 loc) • 2.63 kB
text/typescript
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);
}
}