Преглед изворни кода

Add options to compile shaders and LOD fixes for glTF loader

Gary Hsu пре 7 година
родитељ
комит
cbdd411e70

+ 1 - 0
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts

@@ -20,6 +20,7 @@ module BABYLON.GLTF2.Extensions {
                 loader._loadMaterialBaseProperties(context, material);
                 this._loadSpecularGlossinessProperties(loader, context, material, extension);
                 assign(material.babylonMaterial, true);
+                onComplete();
             });
         }
 

+ 22 - 16
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -10,7 +10,7 @@ module BABYLON.GLTF2.Extensions {
         /**
          * Specify the minimal delay between LODs in ms (default = 250)
          */
-        public static MinimalLODDelay = 250;
+        public Delay = 250;
 
         public get name() {
             return "MSFT_lod";
@@ -70,7 +70,7 @@ module BABYLON.GLTF2.Extensions {
                     loader._tryCatchOnError(() => {
                         this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
                     });
-                }, MSFTLOD.MinimalLODDelay);
+                }, this.Delay);
             });
         }
 
@@ -96,24 +96,30 @@ module BABYLON.GLTF2.Extensions {
 
         private _loadMaterialLOD(loader: GLTFLoader, context: string, materials: IGLTFMaterial[], index: number, assign: (babylonMaterial: Material, isNew: boolean) => void, onComplete: () => void): void {
             loader._loadMaterial(context, materials[index], (babylonMaterial, isNew) => {
-                assign(babylonMaterial, isNew);
+                if (index === materials.length - 1) {
+                    assign(babylonMaterial, isNew);
 
-                if (index === 0) {
-                    onComplete();
-                    return;
+                    // Load the next LOD when the loader is ready to render.
+                    loader._executeWhenRenderReady(() => {
+                        this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                    });
                 }
-
-                // Load the next LOD when the loader is ready to render and
-                // all active material textures of the current LOD are loaded.
-                loader._executeWhenRenderReady(() => {
+                else {
                     BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), () => {
-                        setTimeout(() => {
-                            loader._tryCatchOnError(() => {
-                                this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
-                            });
-                        }, MSFTLOD.MinimalLODDelay);
+                        assign(babylonMaterial, isNew);
+
+                        if (index === 0) {
+                            onComplete();
+                        }
+                        else {
+                            setTimeout(() => {
+                                loader._tryCatchOnError(() => {
+                                    this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                                });
+                            }, this.Delay);
+                        }
                     });
-                });
+                }
             });
         }
     }

+ 109 - 13
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -298,6 +298,10 @@ module BABYLON.GLTF2 {
                 }
             }
 
+            if (this._parent.onMeshLoaded) {
+                this._parent.onMeshLoaded(this._rootNode.babylonMesh);
+            }
+
             let nodeIndices = scene.nodes;
 
             this._traverseNodes(context, nodeIndices, (node, parentNode) => {
@@ -385,6 +389,10 @@ module BABYLON.GLTF2 {
                     this._loadNode("#/nodes/" + index, childNode);
                 }
             }
+
+            if (this._parent.onMeshLoaded) {
+                this._parent.onMeshLoaded(node.babylonMesh);
+            }
         }
 
         private _loadMesh(context: string, node: IGLTFNode, mesh: IGLTFMesh): void {
@@ -441,17 +449,7 @@ module BABYLON.GLTF2 {
                             this._parent.onMaterialLoaded(babylonMaterial);
                         }
 
-                        if (this._parent.onBeforeMaterialReadyAsync) {
-                            this._addLoaderPendingData(material);
-                            this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, subMaterials[index] != null, () => {
-                                this._tryCatchOnError(() => {
-                                    subMaterials[index] = babylonMaterial;
-                                    this._removeLoaderPendingData(material);
-                                });
-                            });
-                        } else {
-                            subMaterials[index] = babylonMaterial;
-                        }
+                        subMaterials[index] = babylonMaterial;
                     });
                 }
             };
@@ -1225,8 +1223,14 @@ module BABYLON.GLTF2 {
         public _removePendingData(data: any): void {
             if (!this._renderReady) {
                 if (--this._renderPendingCount === 0) {
-                    this._renderReady = true;
-                    this._onRenderReady();
+                    this._addLoaderPendingData(this);
+                    this._compileMaterialsAsync(() => {
+                        this._compileShadowGeneratorsAsync(() => {
+                            this._removeLoaderPendingData(this);
+                            this._renderReady = true;
+                            this._onRenderReady();
+                        });
+                    });
                 }
             }
 
@@ -1644,6 +1648,98 @@ module BABYLON.GLTF2 {
 
             return 0;
         }
+
+        private _compileMaterialAsync(babylonMaterial: Material, babylonMesh: AbstractMesh, onSuccess: () => void): void {
+            if (!this._parent.compileMaterials) {
+                onSuccess();
+                return;
+            }
+
+            if (this._parent.useClipPlane) {
+                babylonMaterial.forceCompilation(babylonMesh, () => {
+                    babylonMaterial.forceCompilation(babylonMesh, () => {
+                        this._tryCatchOnError(onSuccess);
+                    }, { clipPlane: true });
+                });
+            }
+            else {
+                babylonMaterial.forceCompilation(babylonMesh, () => {
+                    this._tryCatchOnError(onSuccess);
+                });
+            }
+        }
+
+        private _compileMaterialsAsync(onSuccess: () => void): void {
+            if (!this._parent.compileMaterials || !this._gltf.materials) {
+                onSuccess();
+                return;
+            }
+
+            let meshes = this._getMeshes();
+
+            let remaining = 0;
+            for (let mesh of meshes) {
+                if (mesh.material instanceof MultiMaterial) {
+                    for (let subMaterial of mesh.material.subMaterials) {
+                        if (subMaterial) {
+                            remaining++;
+                        }
+                    }
+                }
+            }
+
+            if (remaining === 0) {
+                onSuccess();
+                return;
+            }
+
+            for (let mesh of meshes) {
+                if (mesh.material instanceof MultiMaterial) {
+                    for (let subMaterial of mesh.material.subMaterials) {
+                        if (subMaterial) {
+                            this._compileMaterialAsync(subMaterial, mesh, () => {
+                                if (--remaining === 0) {
+                                    onSuccess();
+                                }
+                            });
+                        }
+                    }
+                }
+            }
+        }
+
+        private _compileShadowGeneratorsAsync(onSuccess: () => void): void {
+            if (!this._parent.compileShadowGenerators) {
+                onSuccess();
+                return;
+            }
+
+            let lights = this._babylonScene.lights;
+
+            let remaining = 0;
+            for (let light of lights) {
+                let generator = light.getShadowGenerator();
+                if (generator) {
+                    remaining++;
+                }
+            }
+
+            if (remaining === 0) {
+                onSuccess();
+                return;
+            }
+
+            for (let light of lights) {
+                let generator = light.getShadowGenerator();
+                if (generator) {
+                    generator.forceCompilation(() => {
+                        if (--remaining === 0) {
+                            this._tryCatchOnError(onSuccess);
+                        }
+                    });
+                }
+            }
+        }
     }
 
     BABYLON.GLTFFileLoader.CreateGLTFLoaderV2 = parent => new GLTFLoader(parent);

+ 7 - 8
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -31,20 +31,19 @@ module BABYLON {
         public onParsed: (data: IGLTFLoaderData) => void;
 
         // V1 options
-        public static HomogeneousCoordinates: boolean = false;
-        public static IncrementalLoading: boolean = true;
+        public static HomogeneousCoordinates = false;
+        public static IncrementalLoading = true;
 
         // V2 options
-        public coordinateSystemMode: GLTFLoaderCoordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
+        public coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
+        public compileMaterials = false;
+        public compileShadowGenerators = false;
+        public useClipPlane = false;
+        public onMeshLoaded: (mesh: AbstractMesh) => void;
         public onTextureLoaded: (texture: BaseTexture) => void;
         public onMaterialLoaded: (material: Material) => void;
 
         /**
-         * Let the user decides if he needs to process the material (like precompilation) before affecting it to meshes
-         */
-        public onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
-
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete just after onSuccess.

+ 2 - 7
sandbox/index.js

@@ -38,13 +38,8 @@ if (BABYLON.Engine.isSupported()) {
         if (plugin.name !== "gltf") {
             return;
         }
-        plugin.onBeforeMaterialReadyAsync = function(material, mesh, isLOD, callback) {
-            if (!isLOD) {
-                callback();
-                return;
-            }
-            material.forceCompilation(mesh, callback);
-        }
+
+        plugin.compileMaterials = true;
     });
 
     // Resize

+ 24 - 10
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -14,7 +14,7 @@
 
         recreateShadowMap(): void;
 
-        forceCompilation(onCompiled: (generator: ShadowGenerator) => void, options?: { useInstances: boolean }): void;
+        forceCompilation(onCompiled?: (generator: ShadowGenerator) => void, options?: Partial<{ useInstances: boolean }>): void;
 
         serialize(): any;
         dispose(): void;
@@ -602,31 +602,47 @@
         /**
          * Force shader compilation including textures ready check
          */
-        public forceCompilation(onCompiled: (generator: ShadowGenerator) => void, options?: { useInstances: boolean }): void {
+        public forceCompilation(onCompiled?: (generator: ShadowGenerator) => void, options?: Partial<{ useInstances: boolean }>): void {
+            let localOptions = {
+                useInstances: false,
+                ...options
+            };
+
             let shadowMap = this.getShadowMap();
             if (!shadowMap) {
+                if (onCompiled) {
+                    onCompiled(this);
+                }
                 return;
             }
 
-            var subMeshes = new Array<SubMesh>();
-            var currentIndex = 0;
-
             let renderList = shadowMap.renderList;
-
             if (!renderList) {
+                if (onCompiled) {
+                    onCompiled(this);
+                }
                 return;
             }
 
+            var subMeshes = new Array<SubMesh>();
             for (var mesh of renderList) {
                 subMeshes.push(...mesh.subMeshes);
             }
+            if (subMeshes.length === 0) {
+                if (onCompiled) {
+                    onCompiled(this);
+                }
+                return;
+            }
+
+            var currentIndex = 0;
 
             var checkReady = () => {
                 if (!this._scene || !this._scene.getEngine()) {
                     return;
                 }
 
-                while (this.isReady(subMeshes[currentIndex], options ? options.useInstances : false)) {
+                while (this.isReady(subMeshes[currentIndex], localOptions.useInstances)) {
                     currentIndex++;
                     if (currentIndex >= subMeshes.length) {
                         if (onCompiled) {
@@ -638,9 +654,7 @@
                 setTimeout(checkReady, 16);
             };
 
-            if (subMeshes.length > 0) {
-                checkReady();
-            }
+            checkReady();
         }
 
         /**

+ 9 - 3
src/Materials/babylon.material.ts

@@ -565,7 +565,13 @@
         /**
          * Force shader compilation including textures ready check
          */
-        public forceCompilation(mesh: AbstractMesh, onCompiled: (material: Material) => void, options?: { alphaTest: boolean, clipPlane: boolean }): void {
+        public forceCompilation(mesh: AbstractMesh, onCompiled?: (material: Material) => void, options?: Partial<{ alphaTest: Nullable<boolean>, clipPlane: boolean }>): void {
+            let localOptions = {
+                alphaTest: null,
+                clipPlane: false,
+                ...options
+            };
+
             var subMesh = new BaseSubMesh();
             var scene = this.getScene();
             var engine = scene.getEngine();
@@ -582,9 +588,9 @@
                 var alphaTestState = engine.getAlphaTesting();
                 var clipPlaneState = scene.clipPlane;
 
-                engine.setAlphaTesting(options ? options.alphaTest : this.needAlphaTesting());
+                engine.setAlphaTesting(localOptions.alphaTest || (!this.needAlphaBlendingForMesh(mesh) && this.needAlphaTesting()));
 
-                if (options && options.clipPlane) {
+                if (localOptions.clipPlane) {
                     scene.clipPlane = new Plane(0, 0, 0, 1);
                 }