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

Merge pull request #1058 from julien-moreau/master

Improved Volumetric Light Scattering Post Process
David Catuhe пре 9 година
родитељ
комит
cdd95e47f0

+ 87 - 55
src/PostProcess/babylon.volumetricLightScatteringPostProcess.js

@@ -3,6 +3,12 @@ var __extends = (this && this.__extends) || function (d, b) {
     function __() { this.constructor = d; }
     d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
 };
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
 var BABYLON;
 (function (BABYLON) {
     // Inspired by http://http.developer.nvidia.com/GPUGems3/gpugems3_ch13.html
@@ -27,6 +33,11 @@ var BABYLON;
             _super.call(this, name, "volumetricLightScattering", ["decay", "exposure", "weight", "meshPositionOnScreen", "density"], ["lightScatteringSampler"], ratio.postProcessRatio || ratio, camera, samplingMode, engine, reusable, "#define NUM_SAMPLES " + samples);
             this._screenCoordinates = BABYLON.Vector2.Zero();
             /**
+            * Custom position of the mesh. Used if "useCustomMeshPosition" is set to "true"
+            * @type {Vector3}
+            */
+            this.customMeshPosition = BABYLON.Vector3.Zero();
+            /**
             * Set if the post-process should use a custom position for the light source (true) or the internal mesh position (false)
             * @type {boolean}
             */
@@ -37,11 +48,6 @@ var BABYLON;
             */
             this.invert = true;
             /**
-            * Set to true to use the diffuseColor instead of the diffuseTexture
-            * @type {boolean}
-            */
-            this.useDiffuseColor = false;
-            /**
             * Array containing the excluded meshes not rendered in the internal pass
             */
             this.excludedMeshes = new Array();
@@ -88,42 +94,32 @@ var BABYLON;
                 effect.setVector2("meshPositionOnScreen", _this._screenCoordinates);
             };
         }
+        Object.defineProperty(VolumetricLightScatteringPostProcess.prototype, "useDiffuseColor", {
+            get: function () {
+                BABYLON.Tools.Warn("VolumetricLightScatteringPostProcess.useDiffuseColor is no longer used, use the mesh material directly instead");
+                return false;
+            },
+            set: function (useDiffuseColor) {
+                BABYLON.Tools.Warn("VolumetricLightScatteringPostProcess.useDiffuseColor is no longer used, use the mesh material directly instead");
+            },
+            enumerable: true,
+            configurable: true
+        });
         VolumetricLightScatteringPostProcess.prototype.isReady = function (subMesh, useInstances) {
             var mesh = subMesh.getMesh();
+            // Render this.mesh as default
+            if (mesh === this.mesh) {
+                return mesh.material.isReady(mesh);
+            }
             var defines = [];
             var attribs = [BABYLON.VertexBuffer.PositionKind];
             var material = subMesh.getMaterial();
             var needUV = false;
-            // Render this.mesh as default
-            if (mesh === this.mesh) {
-                if (this.useDiffuseColor) {
-                    defines.push("#define DIFFUSE_COLOR_RENDER");
-                }
-                else if (material) {
-                    if (material.diffuseTexture !== undefined) {
-                        defines.push("#define BASIC_RENDER");
-                    }
-                    else {
-                        defines.push("#define DIFFUSE_COLOR_RENDER");
-                    }
-                }
-                defines.push("#define NEED_UV");
-                needUV = true;
-            }
             // Alpha test
             if (material) {
                 if (material.needAlphaTesting()) {
                     defines.push("#define ALPHATEST");
                 }
-                if (material.opacityTexture !== undefined) {
-                    defines.push("#define OPACITY");
-                    if (material.opacityTexture.getAlphaFromRGB) {
-                        defines.push("#define OPACITYRGB");
-                    }
-                    if (!needUV) {
-                        defines.push("#define NEED_UV");
-                    }
-                }
                 if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
                     attribs.push(BABYLON.VertexBuffer.UVKind);
                     defines.push("#define UV1");
@@ -155,7 +151,7 @@ var BABYLON;
             var join = defines.join("\n");
             if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
-                this._volumetricLightScatteringPass = mesh.getScene().getEngine().createEffect({ vertexElement: "depth", fragmentElement: "volumetricLightScatteringPass" }, attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "opacityLevel", "color"], ["diffuseSampler", "opacitySampler"], join);
+                this._volumetricLightScatteringPass = mesh.getScene().getEngine().createEffect({ vertexElement: "depth", fragmentElement: "volumetricLightScatteringPass" }, attribs, ["world", "mBones", "viewProjection", "diffuseMatrix"], ["diffuseSampler"], join);
             }
             return this._volumetricLightScatteringPass.isReady();
         };
@@ -164,14 +160,14 @@ var BABYLON;
          * @param {BABYLON.Vector3} The new custom light position
          */
         VolumetricLightScatteringPostProcess.prototype.setCustomMeshPosition = function (position) {
-            this._customMeshPosition = position;
+            this.customMeshPosition = position;
         };
         /**
          * Returns the light position for light scattering effect
          * @return {BABYLON.Vector3} The custom light position
          */
         VolumetricLightScatteringPostProcess.prototype.getCustomMeshPosition = function () {
-            return this._customMeshPosition;
+            return this.customMeshPosition;
         };
         /**
          * Disposes the internal assets and detaches the post-process from the camera
@@ -224,33 +220,33 @@ var BABYLON;
                 }
                 var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
                 if (_this.isReady(subMesh, hardwareInstancedRendering)) {
-                    engine.enableEffect(_this._volumetricLightScatteringPass);
-                    mesh._bind(subMesh, _this._volumetricLightScatteringPass, BABYLON.Material.TriangleFillMode);
-                    var material = subMesh.getMaterial();
-                    _this._volumetricLightScatteringPass.setMatrix("viewProjection", scene.getTransformMatrix());
-                    // Alpha test
-                    if (material && (mesh === _this.mesh || material.needAlphaTesting() || material.opacityTexture !== undefined)) {
-                        var alphaTexture = material.getAlphaTestTexture();
-                        if ((_this.useDiffuseColor || alphaTexture === undefined) && mesh === _this.mesh) {
-                            _this._volumetricLightScatteringPass.setColor3("color", material.diffuseColor);
-                        }
-                        if (material.needAlphaTesting() || (mesh === _this.mesh && alphaTexture && !_this.useDiffuseColor)) {
+                    var effect = _this._volumetricLightScatteringPass;
+                    if (mesh === _this.mesh) {
+                        effect = subMesh.getMaterial().getEffect();
+                    }
+                    engine.enableEffect(effect);
+                    mesh._bind(subMesh, effect, BABYLON.Material.TriangleFillMode);
+                    if (mesh === _this.mesh) {
+                        subMesh.getMaterial().bind(mesh.getWorldMatrix(), mesh);
+                    }
+                    else {
+                        var material = subMesh.getMaterial();
+                        _this._volumetricLightScatteringPass.setMatrix("viewProjection", scene.getTransformMatrix());
+                        // Alpha test
+                        if (material && material.needAlphaTesting()) {
+                            var alphaTexture = material.getAlphaTestTexture();
                             _this._volumetricLightScatteringPass.setTexture("diffuseSampler", alphaTexture);
                             if (alphaTexture) {
                                 _this._volumetricLightScatteringPass.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
                             }
                         }
-                        if (material.opacityTexture !== undefined) {
-                            _this._volumetricLightScatteringPass.setTexture("opacitySampler", material.opacityTexture);
-                            _this._volumetricLightScatteringPass.setFloat("opacityLevel", material.opacityTexture.level);
+                        // Bones
+                        if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                            _this._volumetricLightScatteringPass.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
                         }
                     }
-                    // Bones
-                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                        _this._volumetricLightScatteringPass.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
-                    }
                     // Draw
-                    mesh._processRendering(subMesh, _this._volumetricLightScatteringPass, BABYLON.Material.TriangleFillMode, batch, hardwareInstancedRendering, function (isInstance, world) { return _this._volumetricLightScatteringPass.setMatrix("world", world); });
+                    mesh._processRendering(subMesh, _this._volumetricLightScatteringPass, BABYLON.Material.TriangleFillMode, batch, hardwareInstancedRendering, function (isInstance, world) { return effect.setMatrix("world", world); });
                 }
             };
             // Render target texture callbacks
@@ -310,8 +306,17 @@ var BABYLON;
         };
         VolumetricLightScatteringPostProcess.prototype._updateMeshScreenCoordinates = function (scene) {
             var transform = scene.getTransformMatrix();
-            var meshPosition = this.mesh.parent ? this.mesh.getAbsolutePosition() : this.mesh.position;
-            var pos = BABYLON.Vector3.Project(this.useCustomMeshPosition ? this._customMeshPosition : meshPosition, BABYLON.Matrix.Identity(), transform, this._viewPort);
+            var meshPosition;
+            if (this.useCustomMeshPosition) {
+                meshPosition = this.customMeshPosition;
+            }
+            else if (this.attachedNode) {
+                meshPosition = this.attachedNode.position;
+            }
+            else {
+                meshPosition = this.mesh.parent ? this.mesh.getAbsolutePosition() : this.mesh.position;
+            }
+            var pos = BABYLON.Vector3.Project(meshPosition, BABYLON.Matrix.Identity(), transform, this._viewPort);
             this._screenCoordinates.x = pos.x / this._viewPort.width;
             this._screenCoordinates.y = pos.y / this._viewPort.height;
             if (this.invert)
@@ -330,7 +335,34 @@ var BABYLON;
             mesh.material = new BABYLON.StandardMaterial(name + "Material", scene);
             return mesh;
         };
+        __decorate([
+            BABYLON.serializeAsVector3()
+        ], VolumetricLightScatteringPostProcess.prototype, "customMeshPosition", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], VolumetricLightScatteringPostProcess.prototype, "useCustomMeshPosition", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], VolumetricLightScatteringPostProcess.prototype, "invert", void 0);
+        __decorate([
+            BABYLON.serializeAsMeshReference()
+        ], VolumetricLightScatteringPostProcess.prototype, "mesh", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], VolumetricLightScatteringPostProcess.prototype, "excludedMeshes", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], VolumetricLightScatteringPostProcess.prototype, "exposure", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], VolumetricLightScatteringPostProcess.prototype, "decay", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], VolumetricLightScatteringPostProcess.prototype, "weight", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], VolumetricLightScatteringPostProcess.prototype, "density", void 0);
         return VolumetricLightScatteringPostProcess;
-    })(BABYLON.PostProcess);
+    }(BABYLON.PostProcess));
     BABYLON.VolumetricLightScatteringPostProcess = VolumetricLightScatteringPostProcess;
 })(BABYLON || (BABYLON = {}));

+ 81 - 59
src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts

@@ -7,53 +7,83 @@
         private _viewPort: Viewport;
         private _screenCoordinates: Vector2 = Vector2.Zero();
         private _cachedDefines: string;
-        private _customMeshPosition: Vector3;
+
+        /**
+        * If not undefined, the mesh position is computed from the attached node position
+        * @type {{position: Vector3}}
+        */
+        public attachedNode: { position: Vector3 };
+
+        /**
+        * Custom position of the mesh. Used if "useCustomMeshPosition" is set to "true"
+        * @type {Vector3}
+        */
+        @serializeAsVector3()
+        public customMeshPosition: Vector3 = Vector3.Zero();
 
         /**
         * Set if the post-process should use a custom position for the light source (true) or the internal mesh position (false)
         * @type {boolean}
         */
+        @serialize()
         public useCustomMeshPosition: boolean = false;
+
         /**
         * If the post-process should inverse the light scattering direction
         * @type {boolean}
         */
+        @serialize()
         public invert: boolean = true;
+
         /**
         * The internal mesh used by the post-process
         * @type {boolean}
         */
+        @serializeAsMeshReference()
         public mesh: Mesh;
-        /**
-        * Set to true to use the diffuseColor instead of the diffuseTexture
-        * @type {boolean}
-        */
-        public useDiffuseColor: boolean = false;
+
+        
+        public get useDiffuseColor(): boolean {
+            Tools.Warn("VolumetricLightScatteringPostProcess.useDiffuseColor is no longer used, use the mesh material directly instead");
+            return false;
+        }
+
+        public set useDiffuseColor(useDiffuseColor: boolean) {
+            Tools.Warn("VolumetricLightScatteringPostProcess.useDiffuseColor is no longer used, use the mesh material directly instead");
+        }
 
         /**
         * Array containing the excluded meshes not rendered in the internal pass
         */
+        @serialize()
         public excludedMeshes = new Array<AbstractMesh>();
 
         /**
         * Controls the overall intensity of the post-process
         * @type {number}
         */
+        @serialize()
         public exposure = 0.3;
+
         /**
         * Dissipates each sample's contribution in range [0, 1]
         * @type {number}
         */
+        @serialize()
         public decay = 0.96815;
+
         /**
         * Controls the overall intensity of each sample
         * @type {number}
         */
+        @serialize()
         public weight = 0.58767;
+
         /**
         * Controls the density of each sample
         * @type {number}
         */
+        @serialize()
         public density = 0.926;
 
         /**
@@ -104,43 +134,22 @@
         public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
             var mesh = subMesh.getMesh();
 
+            // Render this.mesh as default
+            if (mesh === this.mesh) {
+                return mesh.material.isReady(mesh);
+            }
+
             var defines = [];
             var attribs = [VertexBuffer.PositionKind];
             var material: any = subMesh.getMaterial();
             var needUV: boolean = false;
 
-            // Render this.mesh as default
-            if (mesh === this.mesh) {
-                if (this.useDiffuseColor) {
-                    defines.push("#define DIFFUSE_COLOR_RENDER");
-                }
-                else if (material) {
-                    if (material.diffuseTexture !== undefined) {
-                        defines.push("#define BASIC_RENDER");
-                    } else {
-                        defines.push("#define DIFFUSE_COLOR_RENDER");
-                    }
-                }
-                defines.push("#define NEED_UV");
-                needUV = true;
-            }
-
             // Alpha test
             if (material) {
                 if (material.needAlphaTesting()) {
                     defines.push("#define ALPHATEST");
                 }
 
-                if (material.opacityTexture !== undefined) {
-                    defines.push("#define OPACITY");
-                    if (material.opacityTexture.getAlphaFromRGB) {
-                        defines.push("#define OPACITYRGB");
-                    }
-                    if (!needUV) {
-                        defines.push("#define NEED_UV");
-                    }
-                }
-
                 if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
                     attribs.push(VertexBuffer.UVKind);
                     defines.push("#define UV1");
@@ -178,8 +187,8 @@
                 this._volumetricLightScatteringPass = mesh.getScene().getEngine().createEffect(
                     { vertexElement: "depth", fragmentElement: "volumetricLightScatteringPass" },
                     attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "opacityLevel", "color"],
-                    ["diffuseSampler", "opacitySampler"], join);
+                    ["world", "mBones", "viewProjection", "diffuseMatrix"],
+                    ["diffuseSampler"], join);
             }
 
             return this._volumetricLightScatteringPass.isReady();
@@ -190,7 +199,7 @@
          * @param {BABYLON.Vector3} The new custom light position
          */
         public setCustomMeshPosition(position: Vector3): void {
-            this._customMeshPosition = position;
+            this.customMeshPosition = position;
         }
 
         /**
@@ -198,7 +207,7 @@
          * @return {BABYLON.Vector3} The custom light position
          */
         public getCustomMeshPosition(): Vector3 {
-            return this._customMeshPosition;
+            return this.customMeshPosition;
         }
 
         /**
@@ -262,42 +271,44 @@
                 }
 
                 var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
-
+                
                 if (this.isReady(subMesh, hardwareInstancedRendering)) {
-                    engine.enableEffect(this._volumetricLightScatteringPass);
-                    mesh._bind(subMesh, this._volumetricLightScatteringPass, Material.TriangleFillMode);
-                    var material: any = subMesh.getMaterial();
+                    var effect: Effect = this._volumetricLightScatteringPass;
+                    if (mesh === this.mesh) {
+                        effect = subMesh.getMaterial().getEffect();
+                    }
 
-                    this._volumetricLightScatteringPass.setMatrix("viewProjection", scene.getTransformMatrix());
+                    engine.enableEffect(effect);
+                    mesh._bind(subMesh, effect, Material.TriangleFillMode);
 
-                    // Alpha test
-                    if (material && (mesh === this.mesh || material.needAlphaTesting() || material.opacityTexture !== undefined)) {
-                        var alphaTexture = material.getAlphaTestTexture();
+                    if (mesh === this.mesh) {
+                        subMesh.getMaterial().bind(mesh.getWorldMatrix(), mesh);
+                    }
+                    else {
+                        var material: any = subMesh.getMaterial();
 
-                        if ((this.useDiffuseColor || alphaTexture === undefined) && mesh === this.mesh) {
-                            this._volumetricLightScatteringPass.setColor3("color", material.diffuseColor);
-                        }
-                        if (material.needAlphaTesting() || (mesh === this.mesh && alphaTexture && !this.useDiffuseColor)) {
+                        this._volumetricLightScatteringPass.setMatrix("viewProjection", scene.getTransformMatrix());
+
+                        // Alpha test
+                        if (material && material.needAlphaTesting()) {
+                            var alphaTexture = material.getAlphaTestTexture();
+                            
                             this._volumetricLightScatteringPass.setTexture("diffuseSampler", alphaTexture);
+
                             if (alphaTexture) {
                                 this._volumetricLightScatteringPass.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
                             }
                         }
 
-                        if (material.opacityTexture !== undefined) {
-                            this._volumetricLightScatteringPass.setTexture("opacitySampler", material.opacityTexture);
-                            this._volumetricLightScatteringPass.setFloat("opacityLevel", material.opacityTexture.level);
+                        // Bones
+                        if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                            this._volumetricLightScatteringPass.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
                         }
                     }
 
-                    // Bones
-                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                        this._volumetricLightScatteringPass.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
-                    }
-
                     // Draw
                     mesh._processRendering(subMesh, this._volumetricLightScatteringPass, Material.TriangleFillMode, batch, hardwareInstancedRendering,
-                        (isInstance, world) => this._volumetricLightScatteringPass.setMatrix("world", world));
+                        (isInstance, world) => effect.setMatrix("world", world));
                 }
             };
 
@@ -369,8 +380,19 @@
 
         private _updateMeshScreenCoordinates(scene: Scene): void {
             var transform = scene.getTransformMatrix();
-            var meshPosition = this.mesh.parent ? this.mesh.getAbsolutePosition() : this.mesh.position;
-            var pos = Vector3.Project(this.useCustomMeshPosition ? this._customMeshPosition : meshPosition, Matrix.Identity(), transform, this._viewPort);
+            var meshPosition: Vector3;
+
+            if (this.useCustomMeshPosition) {
+                meshPosition = this.customMeshPosition;
+            }
+            else if (this.attachedNode) {
+                meshPosition = this.attachedNode.position;
+            }
+            else {
+                meshPosition = this.mesh.parent ? this.mesh.getAbsolutePosition() : this.mesh.position;
+            }
+
+            var pos = Vector3.Project(meshPosition, Matrix.Identity(), transform, this._viewPort);
 
             this._screenCoordinates.x = pos.x / this._viewPort.width;
             this._screenCoordinates.y = pos.y / this._viewPort.height;

+ 2 - 43
src/Shaders/volumetricLightScatteringPass.fragment.fx

@@ -2,59 +2,18 @@
 varying vec2 vUV;
 #endif
 
-#if defined(ALPHATEST) || defined(BASIC_RENDER)
+#if defined(ALPHATEST)
 uniform sampler2D diffuseSampler;
 #endif
 
-#if defined(DIFFUSE_COLOR_RENDER)
-uniform vec3 color;
-#endif
-
-#if defined(OPACITY)
-uniform sampler2D opacitySampler;
-uniform float opacityLevel;
-#endif
-
 void main(void)
 {
-#if defined(ALPHATEST) || defined(BASIC_RENDER)
+#if defined(ALPHATEST)
 	vec4 diffuseColor = texture2D(diffuseSampler, vUV);
-#endif
 
-#ifdef ALPHATEST
 	if (diffuseColor.a < 0.4)
 		discard;
 #endif
 
-#ifdef OPACITY
-	vec4 opacityColor = texture2D(opacitySampler, vUV);
-	float alpha = 1.0;
-
-	#ifdef OPACITYRGB
-	opacityColor.rgb = opacityColor.rgb * vec3(0.3, 0.59, 0.11);
-	alpha *= (opacityColor.x + opacityColor.y + opacityColor.z) * opacityLevel;
-	#else
-	alpha *= opacityColor.a * opacityLevel;
-	#endif
-
-	#if defined(BASIC_RENDER)
-	gl_FragColor = vec4(diffuseColor.rgb, alpha);
-	#elif defined(DIFFUSE_COLOR_RENDER)
-	gl_FragColor = vec4(color.rgb, alpha);
-	#else
-	gl_FragColor = vec4(0.0, 0.0, 0.0, alpha);
-	#endif
-
-	gl_FragColor.a = alpha;
-#else
-
-	#if defined(BASIC_RENDER)
-	gl_FragColor = diffuseColor;
-	#elif defined(DIFFUSE_COLOR_RENDER)
-	gl_FragColor = vec4(color.rgb, 1.0);
-	#else
 	gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
-	#endif
-#endif
-
 }