diff --git a/packages/dev/core/src/Meshes/mesh.ts b/packages/dev/core/src/Meshes/mesh.ts index 1fa80c07e62..794633880f6 100644 --- a/packages/dev/core/src/Meshes/mesh.ts +++ b/packages/dev/core/src/Meshes/mesh.ts @@ -156,6 +156,39 @@ class _InternalMeshDataInfo { public _sideOrientation: number; } +/** + * Options used to clone a mesh + */ +export interface MeshCloneOptions { + /** The parent of the mesh, if it has one */ + parent?: Nullable; + + /** Skips cloning child meshes of source (default: false. When false, achieved by calling a clone(), also passing False. This will make creation of children, recursive. */ + doNotCloneChildren?: boolean; + + /** Includes cloning mesh physics impostor (default: true) */ + clonePhysicsImpostor?: boolean; + + /** Includes cloning thin instances (default: false) */ + cloneThinInstances?: boolean; +} + +/** + * Options used to create a mesh + */ +export interface MeshCreationOptions extends MeshCloneOptions { + /** An optional Mesh from which the new mesh will be cloned from (geometry will be shared) */ + source?: Nullable; +} + +const meshCreationOptions: MeshCreationOptions = { + source: null, + parent: null, + doNotCloneChildren: false, + clonePhysicsImpostor: true, + cloneThinInstances: false, +}; + /** * Class used to represent renderable models */ @@ -575,7 +608,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { this._instanceDataStorage.forceMatrixUpdates = value; } - protected _copySource(source: Mesh, doNotCloneChildren?: boolean, clonePhysicsImpostor: boolean = true) { + protected _copySource(source: Mesh, doNotCloneChildren?: boolean, clonePhysicsImpostor: boolean = true, cloneThinInstances: boolean = false): void { const scene = this.getScene(); // Geometry if (source._geometry) { @@ -693,7 +726,13 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { for (let index = 0; index < directDescendants.length; index++) { const child = directDescendants[index]; - if ((child).clone) { + if ((child)._isMesh) { + meshCreationOptions.parent = this; + meshCreationOptions.doNotCloneChildren = doNotCloneChildren; + meshCreationOptions.clonePhysicsImpostor = clonePhysicsImpostor; + meshCreationOptions.cloneThinInstances = cloneThinInstances; + (child).clone(this.name + "." + child.name, meshCreationOptions); + } else if ((child).clone) { (child).clone(this.name + "." + child.name, this); } } @@ -734,24 +773,31 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { this.skeleton = source.skeleton; // Thin instances - if (source._thinInstanceDataStorage.matrixData) { - this.thinInstanceSetBuffer("matrix", new Float32Array(source._thinInstanceDataStorage.matrixData), 16, !source._thinInstanceDataStorage.matrixBuffer!.isUpdatable()); - this._thinInstanceDataStorage.matrixBufferSize = source._thinInstanceDataStorage.matrixBufferSize; - this._thinInstanceDataStorage.instancesCount = source._thinInstanceDataStorage.instancesCount; - } else { - this._thinInstanceDataStorage.matrixBufferSize = source._thinInstanceDataStorage.matrixBufferSize; - } - - if (source._userThinInstanceBuffersStorage) { - const userThinInstance = source._userThinInstanceBuffersStorage; - for (const kind in userThinInstance.data) { + if (cloneThinInstances) { + if (source._thinInstanceDataStorage.matrixData) { this.thinInstanceSetBuffer( - kind, - new Float32Array(userThinInstance.data[kind]), - userThinInstance.strides[kind], - !userThinInstance.vertexBuffers?.[kind]?.isUpdatable() + "matrix", + new Float32Array(source._thinInstanceDataStorage.matrixData), + 16, + !source._thinInstanceDataStorage.matrixBuffer!.isUpdatable() ); - this._userThinInstanceBuffersStorage.sizes[kind] = userThinInstance.sizes[kind]; + this._thinInstanceDataStorage.matrixBufferSize = source._thinInstanceDataStorage.matrixBufferSize; + this._thinInstanceDataStorage.instancesCount = source._thinInstanceDataStorage.instancesCount; + } else { + this._thinInstanceDataStorage.matrixBufferSize = source._thinInstanceDataStorage.matrixBufferSize; + } + + if (source._userThinInstanceBuffersStorage) { + const userThinInstance = source._userThinInstanceBuffersStorage; + for (const kind in userThinInstance.data) { + this.thinInstanceSetBuffer( + kind, + new Float32Array(userThinInstance.data[kind]), + userThinInstance.strides[kind], + !userThinInstance.vertexBuffers?.[kind]?.isUpdatable() + ); + this._userThinInstanceBuffersStorage.sizes[kind] = userThinInstance.sizes[kind]; + } } } @@ -759,6 +805,14 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { this.computeWorldMatrix(true); } + /** + * Constructor + * @param name The value used by scene.getMeshByName() to do a lookup. + * @param scene The scene to add this mesh to. + * @param options Options used to create the mesh + */ + constructor(name: string, scene?: Nullable, options?: MeshCreationOptions); + /** * Constructor * @param name The value used by scene.getMeshByName() to do a lookup. @@ -770,10 +824,13 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { * This will make creation of children, recursive. * @param clonePhysicsImpostor When cloning, include cloning mesh physics impostor, default True. */ + constructor(name: string, scene?: Nullable, parent?: Nullable, source?: Nullable, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean); + + /** @internal */ constructor( name: string, scene: Nullable = null, - parent: Nullable = null, + parentOrOptions: Nullable | MeshCreationOptions = null, source: Nullable = null, doNotCloneChildren?: boolean, clonePhysicsImpostor: boolean = true @@ -798,8 +855,23 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { } }; + let parent: Nullable = null; + let cloneThinInstances = false; + + if (parentOrOptions && (parentOrOptions as Node)._addToSceneRootNodes === undefined) { + const options = parentOrOptions as MeshCreationOptions; + + parent = options.parent ?? null; + source = options.source ?? null; + doNotCloneChildren = options.doNotCloneChildren ?? false; + clonePhysicsImpostor = options.clonePhysicsImpostor ?? true; + cloneThinInstances = options.cloneThinInstances ?? false; + } else { + parent = parentOrOptions as Nullable; + } + if (source) { - this._copySource(source, doNotCloneChildren, clonePhysicsImpostor); + this._copySource(source, doNotCloneChildren, clonePhysicsImpostor, cloneThinInstances); } // Parent @@ -2974,13 +3046,24 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { * Returns a new Mesh object generated from the current mesh properties. * This method must not get confused with createInstance() * @param name is a string, the name given to the new mesh - * @param newParent can be any Node object (default `null`) + * @param newParent can be any Node object (default `null`) or an instance of MeshCloneOptions. If the latter, doNotCloneChildren and clonePhysicsImpostor are unused. * @param doNotCloneChildren allows/denies the recursive cloning of the original mesh children if any (default `false`) * @param clonePhysicsImpostor allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any (default `true`) * @returns a new mesh */ - public override clone(name: string = "", newParent: Nullable = null, doNotCloneChildren?: boolean, clonePhysicsImpostor: boolean = true): Mesh { - return new Mesh(name, this.getScene(), newParent, this, doNotCloneChildren, clonePhysicsImpostor); + public override clone(name: string = "", newParent: Nullable | MeshCloneOptions = null, doNotCloneChildren?: boolean, clonePhysicsImpostor: boolean = true): Mesh { + if (newParent && (newParent as Node)._addToSceneRootNodes === undefined) { + const cloneOptions = newParent as MeshCloneOptions; + + meshCreationOptions.source = this; + meshCreationOptions.doNotCloneChildren = cloneOptions.doNotCloneChildren; + meshCreationOptions.clonePhysicsImpostor = cloneOptions.clonePhysicsImpostor; + meshCreationOptions.cloneThinInstances = cloneOptions.cloneThinInstances; + + return new Mesh(name, this.getScene(), meshCreationOptions); + } + + return new Mesh(name, this.getScene(), newParent as Nullable, this, doNotCloneChildren, clonePhysicsImpostor); } /**