Browse Source

Merge pull request #9865 from Popov72/fix-gltf-transmission

KHR_materials_transmission: fixes and improvements
David Catuhe 4 years ago
parent
commit
a1e6874a1d
1 changed files with 43 additions and 45 deletions
  1. 43 45
      loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts

+ 43 - 45
loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts

@@ -11,7 +11,8 @@ import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
 import { Mesh } from "babylonjs/Meshes/mesh";
 import { Texture } from "babylonjs/Materials/Textures/texture";
 import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
-import { Observable } from "babylonjs/Misc/observable";
+import { Observable, Observer } from "babylonjs/Misc/observable";
+import { Constants } from "babylonjs/Engines/constants";
 
 interface ITransmissionHelperHolder {
     /**
@@ -22,9 +23,29 @@ interface ITransmissionHelperHolder {
 
 interface ITransmissionHelperOptions {
     /**
-     * The size of the render buffers
+     * The size of the render buffers (default: 1024)
      */
     renderSize: number;
+
+    /**
+     * The number of samples to use when generating the render target texture for opaque meshes (default: 4)
+     */
+    samples: number;
+
+    /**
+     * Scale to apply when selecting the LOD level to sample the refraction texture (default: 1)
+     */
+    lodGenerationScale: number;
+
+    /**
+     * Offset to apply when selecting the LOD level to sample the refraction texture (default: -4)
+     */
+    lodGenerationOffset: number;
+
+    /**
+     * Type of the refraction render target texture (default: TEXTURETYPE_UNSIGNED_INT)
+     */
+    renderTargetTextureType: number;
 }
 
 /**
@@ -37,7 +58,11 @@ class TransmissionHelper {
      */
     private static _getDefaultOptions(): ITransmissionHelperOptions {
         return {
-            renderSize: 1024
+            renderSize: 1024,
+            samples: 4,
+            lodGenerationScale: 1,
+            lodGenerationOffset: -4,
+            renderTargetTextureType: Constants.TEXTURETYPE_UNSIGNED_INT
         };
     }
 
@@ -51,6 +76,7 @@ class TransmissionHelper {
     private _opaqueRenderTarget: Nullable<RenderTargetTexture> = null;
     private _opaqueMeshesCache: Mesh[] = [];
     private _transparentMeshesCache: Mesh[] = [];
+    private _materialObservers: { [id: string]: Nullable<Observer<AbstractMesh>> } = {};
 
     /**
      * This observable will be notified with any error during the creation of the environment,
@@ -100,8 +126,12 @@ class TransmissionHelper {
         this._options = newOptions;
 
         // If size changes, recreate everything
-        if (newOptions.renderSize !== oldOptions.renderSize) {
+        if (newOptions.renderSize !== oldOptions.renderSize || newOptions.renderTargetTextureType !== oldOptions.renderTargetTextureType || !this._opaqueRenderTarget) {
             this._setupRenderTargets();
+        } else {
+            this._opaqueRenderTarget.samples = newOptions.samples;
+            this._opaqueRenderTarget.lodGenerationScale = newOptions.lodGenerationScale;
+            this._opaqueRenderTarget.lodGenerationOffset = newOptions.lodGenerationOffset;
         }
     }
 
@@ -121,7 +151,7 @@ class TransmissionHelper {
 
     private _addMesh(mesh: AbstractMesh): void {
         if (mesh instanceof Mesh) {
-            mesh.onMaterialChangedObservable.add(this.onMeshMaterialChanged.bind(this));
+            this._materialObservers[mesh.uniqueId] = mesh.onMaterialChangedObservable.add(this.onMeshMaterialChanged.bind(this));
             if (this.shouldRenderAsTransmission(mesh.material)) {
                 this._transparentMeshesCache.push(mesh);
             } else {
@@ -132,7 +162,8 @@ class TransmissionHelper {
 
     private _removeMesh(mesh: AbstractMesh): void {
         if (mesh instanceof Mesh) {
-            mesh.onMaterialChangedObservable.remove(this.onMeshMaterialChanged.bind(this));
+            mesh.onMaterialChangedObservable.remove(this._materialObservers[mesh.uniqueId]);
+            delete this._materialObservers[mesh.uniqueId];
             let idx = this._transparentMeshesCache.indexOf(mesh);
             if (idx !== -1) {
                 this._transparentMeshesCache.splice(idx, 1);
@@ -186,50 +217,17 @@ class TransmissionHelper {
      * Setup the render targets according to the specified options.
      */
     private _setupRenderTargets(): void {
-
-        let opaqueRTIndex = -1;
-
-        // Remove any layers rendering to the opaque scene.
-        if (this._scene.layers && this._opaqueRenderTarget) {
-            for (let layer of this._scene.layers) {
-                const idx = layer.renderTargetTextures.indexOf(this._opaqueRenderTarget);
-                if (idx >= 0) {
-                    layer.renderTargetTextures.splice(idx, 1);
-                }
-            }
-        }
-
-        // Remove opaque render target
-        if (this._opaqueRenderTarget) {
-            opaqueRTIndex = this._scene.customRenderTargets.indexOf(this._opaqueRenderTarget);
-            this._opaqueRenderTarget.dispose();
-        }
-
-        this._opaqueRenderTarget = new RenderTargetTexture("opaqueSceneTexture", this._options.renderSize, this._scene, true);
+        this._opaqueRenderTarget = new RenderTargetTexture("opaqueSceneTexture", this._options.renderSize, this._scene, true, undefined, this._options.renderTargetTextureType);
         this._opaqueRenderTarget.renderList = this._opaqueMeshesCache;
         // this._opaqueRenderTarget.clearColor = new Color4(0.0, 0.0, 0.0, 0.0);
         this._opaqueRenderTarget.gammaSpace = true;
-        this._opaqueRenderTarget.lodGenerationScale = 1;
-        this._opaqueRenderTarget.lodGenerationOffset = -4;
-        this._opaqueRenderTarget.samples = 4;
-
-        if (opaqueRTIndex >= 0) {
-            this._scene.customRenderTargets.splice(opaqueRTIndex, 0, this._opaqueRenderTarget);
-        } else {
-            opaqueRTIndex = this._scene.customRenderTargets.length;
-            this._scene.customRenderTargets.push(this._opaqueRenderTarget);
-        }
-
-        // If there are other layers, they should be included in the render of the opaque background.
-        if (this._scene.layers && this._opaqueRenderTarget) {
-            for (let layer of this._scene.layers) {
-                layer.renderTargetTextures.push(this._opaqueRenderTarget);
-            }
-        }
+        this._opaqueRenderTarget.lodGenerationScale = this._options.lodGenerationScale;
+        this._opaqueRenderTarget.lodGenerationOffset = this._options.lodGenerationOffset;
+        this._opaqueRenderTarget.samples = this._options.samples;
 
         this._transparentMeshesCache.forEach((mesh: AbstractMesh) => {
-            if (this.shouldRenderAsTransmission(mesh.material) && mesh.material instanceof PBRMaterial) {
-                mesh.material.refractionTexture = this._opaqueRenderTarget;
+            if (this.shouldRenderAsTransmission(mesh.material)) {
+                (mesh.material as PBRMaterial).refractionTexture = this._opaqueRenderTarget;
             }
         });
     }