浏览代码

Merge pull request #7632 from bghgary/lod-fix

Fix dispose code in MSFT_lod loader extension
David Catuhe 5 年之前
父节点
当前提交
dc6eeccf47
共有 2 个文件被更改,包括 41 次插入20 次删除
  1. 1 0
      dist/preview release/what's new.md
  2. 40 20
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

+ 1 - 0
dist/preview release/what's new.md

@@ -148,6 +148,7 @@
 - Added support for animations import from separate files ([noalak](https://github.com/noalak/))
 - Use web workers to validate glTF to avoid blocking the main thread. ([bghgary](https://github.com/bghgary))
 - Update glTF validator to 2.0.0-dev.3.1. ([bghgary](https://github.com/bghgary))
+- Fix an issue with disposing materials and textures too aggressively in MSFT_lod loader extension. ([bghgary](https://github.com/bghgary))
 
 ### Materials
 

+ 40 - 20
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -4,7 +4,7 @@ import { Deferred } from "babylonjs/Misc/deferred";
 import { Material } from "babylonjs/Materials/material";
 import { TransformNode } from "babylonjs/Meshes/transformNode";
 import { Mesh } from "babylonjs/Meshes/mesh";
-
+import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
 import { INode, IMaterial, IBuffer, IScene } from "../glTFLoaderInterfaces";
 import { IGLTFLoaderExtension } from "../glTFLoaderExtension";
 import { GLTFLoader, ArrayItem } from "../glTFLoader";
@@ -75,8 +75,6 @@ export class MSFT_lod implements IGLTFLoaderExtension {
 
     /** @hidden */
     public dispose() {
-        this._disposeUnusedMaterials();
-
         delete this._loader;
 
         this._nodeIndexLOD = null;
@@ -174,9 +172,8 @@ export class MSFT_lod implements IGLTFLoaderExtension {
                         // TODO: should not rely on _babylonTransformNode
                         const previousNodeLOD = nodeLODs[indexLOD - 1];
                         if (previousNodeLOD._babylonTransformNode) {
-                            previousNodeLOD._babylonTransformNode.dispose();
+                            this._disposeTransformNode(previousNodeLOD._babylonTransformNode);
                             delete previousNodeLOD._babylonTransformNode;
-                            this._disposeUnusedMaterials();
                         }
                     }
 
@@ -235,7 +232,7 @@ export class MSFT_lod implements IGLTFLoaderExtension {
                         // TODO: should not rely on _data
                         const previousDataLOD = materialLODs[indexLOD - 1]._data!;
                         if (previousDataLOD[babylonDrawMode]) {
-                            previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
+                            this._disposeMaterials([previousDataLOD[babylonDrawMode].babylonMaterial]);
                             delete previousDataLOD[babylonDrawMode];
                         }
                     }
@@ -344,23 +341,46 @@ export class MSFT_lod implements IGLTFLoaderExtension {
         return properties;
     }
 
-    private _disposeUnusedMaterials(): void {
-        // TODO: should not rely on _data
-        const materials = this._loader.gltf.materials;
-        if (materials) {
-            for (const material of materials) {
-                if (material._data) {
-                    for (const drawMode in material._data) {
-                        const data = material._data[drawMode];
-                        if (data.babylonMeshes.every((babylonMesh) => babylonMesh.material !== data.babylonMaterial)) {
-                            // TODO: check if texture is in use instead of force disposing textures
-                            data.babylonMaterial.dispose(false, true);
-                            delete material._data[drawMode];
-                        }
-                    }
+    private _disposeTransformNode(babylonTransformNode: TransformNode): void {
+        const babylonMaterials = new Array<Material>();
+        const babylonMaterial = (babylonTransformNode as Mesh).material;
+        if (babylonMaterial) {
+            babylonMaterials.push(babylonMaterial);
+        }
+        for (const babylonMesh of babylonTransformNode.getChildMeshes()) {
+            if (babylonMesh.material) {
+                babylonMaterials.push(babylonMesh.material);
+            }
+        }
+
+        babylonTransformNode.dispose();
+
+        const babylonMaterialsToDispose = babylonMaterials.filter((babylonMaterial) => this._loader.babylonScene.meshes.every((mesh) => mesh.material != babylonMaterial));
+        this._disposeMaterials(babylonMaterialsToDispose);
+    }
+
+    private _disposeMaterials(babylonMaterials: Material[]): void {
+        const babylonTextures: { [uniqueId: number]: BaseTexture } = {};
+
+        for (const babylonMaterial of babylonMaterials) {
+            for (const babylonTexture of babylonMaterial.getActiveTextures()) {
+                babylonTextures[babylonTexture.uniqueId] = babylonTexture;
+            }
+
+            babylonMaterial.dispose();
+        }
+
+        for (const uniqueId in babylonTextures) {
+            for (const babylonMaterial of this._loader.babylonScene.materials) {
+                if (babylonMaterial.hasTexture(babylonTextures[uniqueId])) {
+                    delete babylonTextures[uniqueId];
                 }
             }
         }
+
+        for (const uniqueId in babylonTextures) {
+            babylonTextures[uniqueId].dispose();
+        }
     }
 }