Kaynağa Gözat

Merge pull request #8213 from Popov72/gltf-optimize-instance

EXT_mesh_gpu_instancing: Use thin instances when possible
David Catuhe 5 yıl önce
ebeveyn
işleme
0ee2e42663

+ 23 - 30
loaders/src/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.ts

@@ -1,13 +1,11 @@
-import { Vector3, Quaternion } from 'babylonjs/Maths/math.vector';
-import { InstancedMesh } from 'babylonjs/Meshes/instancedMesh';
+import { Vector3, Quaternion, Matrix } from 'babylonjs/Maths/math.vector';
 import { Mesh } from 'babylonjs/Meshes/mesh';
 import { TransformNode } from "babylonjs/Meshes/transformNode";
-import { StringTools } from 'babylonjs/Misc/stringTools';
 import { Nullable } from "babylonjs/types";
 import { GLTFLoader, ArrayItem } from "../glTFLoader";
 import { IGLTFLoaderExtension } from "../glTFLoaderExtension";
 import { INode } from "../glTFLoaderInterfaces";
-import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+import { TmpVectors } from 'babylonjs/Maths/math.vector';
 
 const NAME = "EXT_mesh_gpu_instancing";
 
@@ -48,17 +46,16 @@ export class EXT_mesh_gpu_instancing implements IGLTFLoaderExtension {
     /** @hidden */
     public loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>> {
         return GLTFLoader.LoadExtensionAsync<IEXTMeshGpuInstancing, TransformNode>(context, node, this.name, (extensionContext, extension) => {
+            this._loader._disableInstancedMesh++;
+
             const promise = this._loader.loadNodeAsync(`#/nodes/${node.index}`, node, assign);
 
+            this._loader._disableInstancedMesh--;
+
             if (!node._primitiveBabylonMeshes) {
                 return promise;
             }
 
-            // Hide the source meshes.
-            for (const babylonMesh of node._primitiveBabylonMeshes) {
-                babylonMesh.isVisible = false;
-            }
-
             const promises = new Array<Promise<Nullable<Float32Array>>>();
             let instanceCount = 0;
 
@@ -82,30 +79,26 @@ export class EXT_mesh_gpu_instancing implements IGLTFLoaderExtension {
             loadAttribute("ROTATION");
             loadAttribute("SCALE");
 
-            if (instanceCount == 0) {
-                return promise;
-            }
-
-            const digitLength = instanceCount.toString().length;
-            for (let i = 0; i < instanceCount; ++i) {
-                for (const babylonMesh of node._primitiveBabylonMeshes!) {
-                    const instanceName = `${babylonMesh.name || babylonMesh.id}_${StringTools.PadNumber(i, digitLength)}`;
-                    const babylonInstancedMesh = (babylonMesh as (InstancedMesh | Mesh)).createInstance(instanceName);
-                    babylonInstancedMesh.setParent(babylonMesh);
-                }
-            }
-
             return promise.then((babylonTransformNode) => {
                 return Promise.all(promises).then(([translationBuffer, rotationBuffer, scaleBuffer]) => {
+                    const matrices = new Float32Array(instanceCount * 16);
+
+                    TmpVectors.Vector3[0].copyFromFloats(0, 0, 0); // translation
+                    TmpVectors.Quaternion[0].copyFromFloats(0, 0, 0, 1); // rotation
+                    TmpVectors.Vector3[1].copyFromFloats(1, 1, 1); // scale
+
+                    for (let i = 0; i < instanceCount; ++i) {
+                        translationBuffer && Vector3.FromArrayToRef(translationBuffer, i * 3, TmpVectors.Vector3[0]);
+                        rotationBuffer && Quaternion.FromArrayToRef(rotationBuffer, i * 4, TmpVectors.Quaternion[0]);
+                        scaleBuffer && Vector3.FromArrayToRef(scaleBuffer, i * 3, TmpVectors.Vector3[1]);
+
+                        Matrix.ComposeToRef(TmpVectors.Vector3[1], TmpVectors.Quaternion[0], TmpVectors.Vector3[0], TmpVectors.Matrix[0]);
+
+                        TmpVectors.Matrix[0].copyToArray(matrices, i * 16);
+                    }
+
                     for (const babylonMesh of node._primitiveBabylonMeshes!) {
-                        const babylonInstancedMeshes = babylonMesh.getChildMeshes(true, (node) => (node as AbstractMesh).isAnInstance);
-                        for (let i = 0; i < instanceCount; ++i) {
-                            const babylonInstancedMesh = babylonInstancedMeshes[i];
-                            translationBuffer && Vector3.FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
-                            rotationBuffer && Quaternion.FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion!);
-                            scaleBuffer && Vector3.FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
-                            babylonInstancedMesh.refreshBoundingInfo();
-                        }
+                            (babylonMesh as Mesh).thinInstanceSetBuffer("matrix", matrices, 16, true);
                     }
 
                     return babylonTransformNode;

+ 4 - 1
loaders/src/glTF/2.0/glTFLoader.ts

@@ -106,6 +106,9 @@ export class GLTFLoader implements IGLTFLoader {
     /** Storage */
     public _babylonLights: Light[] = [];
 
+    /** @hidden */
+    public _disableInstancedMesh = 0;
+
     private _disposed = false;
     private _parent: GLTFFileLoader;
     private _state: Nullable<GLTFLoaderState> = null;
@@ -777,7 +780,7 @@ export class GLTFLoader implements IGLTFLoader {
 
         this.logOpen(`${context}`);
 
-        const shouldInstance = this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
+        const shouldInstance = (this._disableInstancedMesh === 0) && this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
 
         let babylonAbstractMesh: AbstractMesh;
         let promise: Promise<any>;

+ 7 - 0
src/Meshes/thinInstanceMesh.ts

@@ -250,8 +250,10 @@ Mesh.prototype.thinInstanceRefreshBoundingInfo = function(forceRefreshParentInfo
     const matrixData = this._thinInstanceDataStorage.matrixData;
 
     if (vectors.length === 0) {
+        const worldMatrix = this.getWorldMatrix();
         for (let v = 0; v < boundingInfo.boundingBox.vectors.length; ++v) {
             vectors.push(boundingInfo.boundingBox.vectors[v].clone());
+            Vector3.TransformCoordinatesToRef(vectors[v], worldMatrix, vectors[v]);
         }
     }
 
@@ -341,3 +343,8 @@ Mesh.prototype._disposeThinInstanceSpecificData = function() {
         this._thinInstanceDataStorage.matrixBuffer = null;
     }
 };
+
+/**
+ * @hidden
+ */
+export var _IDoNeedToBeInTheBuild2 = 42;