Sebastien Vandenberghe 7 年之前
父節點
當前提交
2981acfbf8

+ 62 - 12
src/Engine/babylon.engine.ts

@@ -220,12 +220,14 @@
      * Define options used to create a depth texture
      */
     export class DepthTextureCreationOptions {
-        /** Specifies wether or not a stencil should be allocated in the texture */
+        /** Specifies whether or not a stencil should be allocated in the texture */
         generateStencil?: boolean;
-        /** Specifies wether or not bilinear filtering is enable on the texture */
+        /** Specifies whether or not bilinear filtering is enable on the texture */
         bilinearFiltering?: boolean;
         /** Specifies the comparison function to set on the texture. If 0 or undefined, the texture is not in comparison mode */
         comparisonFunction?: number;
+        /** Specifies if the created texture is a cube texture */
+        isCube?: boolean;
     }
 
     /**
@@ -1965,10 +1967,10 @@
 
                 if (depthStencilTexture) {
                     if (depthStencilTexture._generateStencilBuffer) {
-                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture, 0);
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, 0);
                     }
                     else {
-                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture, 0);
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, 0);
                     }
                 }
             }
@@ -3727,7 +3729,7 @@
             internalTexture.generateMipMaps = false;
             internalTexture._generateDepthBuffer = true;
             internalTexture._generateStencilBuffer = generateStencil;
-            internalTexture.samplingMode = bilinearFiltering ? Texture.NEAREST_SAMPLINGMODE : Texture.BILINEAR_SAMPLINGMODE;
+            internalTexture.samplingMode = bilinearFiltering ? Texture.BILINEAR_SAMPLINGMODE : Texture.NEAREST_SAMPLINGMODE;
             internalTexture.type = Engine.TEXTURETYPE_UNSIGNED_INT;
             internalTexture._comparisonFunction = comparisonFunction;
 
@@ -3757,6 +3759,22 @@
          * @returns The texture
          */
         public createDepthStencilTexture(size: number | { width: number, height: number }, options: DepthTextureCreationOptions) : InternalTexture {
+            if (options.isCube) {
+                return this._createDepthStencilCubeTexture(size.width || size, options);
+            }
+            else {
+                return this._createDepthStencilTexture(size, options);
+            }
+        }
+
+        /**
+         * Creates a depth stencil texture.
+         * This is only available in WebGL 2 or with the depth texture extension available.
+         * @param size The size of face edge in the texture.
+         * @param options The options defining the texture.
+         * @returns The texture
+         */
+        private _createDepthStencilTexture(size: number | { width: number, height: number }, options: DepthTextureCreationOptions) : InternalTexture {
             var internalTexture = new InternalTexture(this, InternalTexture.DATASOURCE_DEPTHTEXTURE);
 
             if (!this._caps.depthTextureExtension) {
@@ -3805,7 +3823,7 @@
          * @param options The options defining the cube texture.
          * @returns The cube texture
          */
-        public createDepthStencilCubeTexture(size: number, options: DepthTextureCreationOptions) : InternalTexture {
+        private _createDepthStencilCubeTexture(size: number, options: DepthTextureCreationOptions) : InternalTexture {
             var internalTexture = new InternalTexture(this, InternalTexture.DATASOURCE_UNKNOWN);
             internalTexture.isCube = true;
 
@@ -3858,18 +3876,18 @@
             this.bindUnboundFramebuffer(internalTexture._framebuffer);
             if (depthStencilTexture.isCube) {
                 if (depthStencilTexture._generateStencilBuffer) {
-                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture, 0);
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture._webGLTexture, 0);
                 }
                 else {
-                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture, 0);
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture._webGLTexture, 0);
                 }
             }
             else {
                 if (depthStencilTexture._generateStencilBuffer) {
-                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture, 0);
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture._webGLTexture, 0);
                 }
                 else {
-                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture, 0);
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture._webGLTexture, 0);
                 }
             }
             this.bindUnboundFramebuffer(null);
@@ -5216,6 +5234,12 @@
             }
         }
 
+        /**
+         * Sets a texture to the according uniform.
+         * @param channel The texture channel
+         * @param uniform The uniform to set
+         * @param texture The texture to apply
+         */
         public setTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<BaseTexture>): void {
             if (channel < 0) {
                 return;
@@ -5228,6 +5252,29 @@
             this._setTexture(channel, texture);
         }
 
+        /**
+         * Sets a depth stencil texture from a render target to the according uniform.
+         * @param channel The texture channel
+         * @param uniform The uniform to set
+         * @param texture The render target texture containing the depth stencil texture to apply
+         */
+        public setDepthStencilTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<RenderTargetTexture>): void {
+            if (channel < 0) {
+                return;
+            }
+
+            if (uniform) {
+                this._boundUniforms[channel] = uniform;
+            }
+
+            if (!texture || !texture.depthStencilTexture) {
+                this._setTexture(channel, null);
+            }
+            else {
+                this._setTexture(channel, texture, false, true);
+            }
+        }
+
         private _bindSamplerUniformToChannel(sourceSlot: number, destination: number) {
             let uniform = this._boundUniforms[sourceSlot];
             if (uniform._currentState === destination) {
@@ -5237,7 +5284,7 @@
             uniform._currentState = destination;
         }
 
-        private _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false): boolean {
+        private _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false, depthStencilTexture = false): boolean {
             // Not ready?
             if (!texture) {
                 if (this._boundTexturesCache[channel] != null) {
@@ -5261,7 +5308,10 @@
             }
 
             let internalTexture: InternalTexture;
-            if (texture.isReady()) {
+            if (depthStencilTexture) {
+                internalTexture = (<RenderTargetTexture>texture).depthStencilTexture;
+            }
+            else if (texture.isReady()) {
                 internalTexture = <InternalTexture>texture.getInternalTexture();
             }
             else if (texture.isCube) {

+ 50 - 9
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -553,6 +553,7 @@
         private _currentFaceIndexCache = 0;
         private _textureType: number;
         private _defaultTextureMatrix = Matrix.Identity();
+        private _useDepthStencilTexture = false;
 
         /**
          * Creates a ShadowGenerator object.
@@ -595,6 +596,7 @@
             }
 
             this._initializeGenerator();
+            this._applyFilterValues();
         }
 
         private _initializeGenerator(): void {
@@ -604,7 +606,14 @@
 
         private _initializeShadowMap(): void {
             // Render target
-            this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube());
+            let engine = this._scene.getEngine();
+            if (engine.webGLVersion > 1) {
+                this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube(), undefined, false, false);
+                this._shadowMap.createDepthStencilTexture(Engine.LESS, true);
+            }
+            else {
+                this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube());
+            }
             this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.anisotropicFilteringLevel = 1;
@@ -615,6 +624,9 @@
             // Record Face Index before render.
             this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
                 this._currentFaceIndex = faceIndex;
+                if (this._useDepthStencilTexture) {
+                    //engine.setColorWrite(false);
+                }
             });
 
             // Custom render function.
@@ -622,6 +634,9 @@
 
             // Blur if required afer render.
             this._shadowMap.onAfterUnbindObservable.add(() => {
+                if (this._useDepthStencilTexture) {
+                    engine.setColorWrite(true);
+                }
                 if (!this.useBlurExponentialShadowMap && !this.useBlurCloseExponentialShadowMap) {
                     return;
                 }
@@ -632,13 +647,19 @@
                 }
             });
 
+            var clearZero = new Color4(0, 0, 0, 0);
+            var clearOne = new Color4(1.0, 1.0, 1.0, 1.0);
+
             // Clear according to the chosen filter.
             this._shadowMap.onClearObservable.add((engine: Engine) => {
-                if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
-                    engine.clear(new Color4(0, 0, 0, 0), true, true, true);
+                if (this._useDepthStencilTexture) {
+                    engine.clear(clearOne, false, true, false);
+                }
+                else if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
+                    engine.clear(clearZero, true, true, false);
                 }
                 else {
-                    engine.clear(new Color4(1.0, 1.0, 1.0, 1.0), true, true, true);
+                    engine.clear(clearOne, true, true, false);
                 }
             });
         }
@@ -785,10 +806,22 @@
                 return;
             }
 
-            if (this.filter === ShadowGenerator.FILTER_NONE) {
-                this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
-            } else {
-                this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
+            this._useDepthStencilTexture = false;
+            if (this._scene.getEngine().webGLVersion > 1) {
+                if (this.filter === ShadowGenerator.FILTER_NONE) {
+                    this._useDepthStencilTexture = true;
+                }
+                else {
+                    this._useDepthStencilTexture = false;
+                    this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
+                }
+            }
+            else {
+                if (this.filter === ShadowGenerator.FILTER_NONE) {
+                    this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
+                } else {
+                    this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
+                }
             }
         }
 
@@ -974,6 +1007,8 @@
                 return;
             }
 
+            defines["USEDEPTHSTENCILTEXTURE"] = defines["USEDEPTHSTENCILTEXTURE"] || this._useDepthStencilTexture;
+            defines["USEDEPTHSTENCILTEXTURE" + lightIndex] = this._useDepthStencilTexture;
             defines["SHADOW" + lightIndex] = true;
 
             if (this.usePoissonSampling) {
@@ -1019,7 +1054,13 @@
             if (!light.needCube()) {
                 effect.setMatrix("lightMatrix" + lightIndex, this.getTransformMatrix());
             }
-            effect.setTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
+
+            if (this._useDepthStencilTexture) {
+                effect.setDepthStencilTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
+            }
+            else {
+                effect.setTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
+            }
             light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), this.blurScale / shadowMap.getSize().width, this.depthScale, this.frustumEdgeFalloff, lightIndex);
             light._uniformBuffer.updateFloat2("depthValues", this.getLight().getDepthMinZ(camera), this.getLight().getDepthMinZ(camera) + this.getLight().getDepthMaxZ(camera), lightIndex);
         }

+ 22 - 0
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -229,6 +229,28 @@
 
         }
 
+        /**
+         * Creates a depth stencil texture.
+         * This is only available in WebGL 2 or with the depth texture extension available.
+         * @param comparisonFunction Specifies the comparison function to set on the texture. If 0 or undefined, the texture is not in comparison mode
+         * @param bilinearFiltering Specifies whether or not bilinear filtering is enable on the texture
+         * @param generateStencil Specifies whether or not a stencil should be allocated in the texture
+         */
+        public createDepthStencilTexture(comparisonFunction: number = 0, bilinearFiltering: boolean = true, generateStencil: boolean = false) : void {
+            if (!this.getScene()) {
+                return;
+            }
+
+            var engine = this.getScene()!.getEngine();
+            this.depthStencilTexture = engine.createDepthStencilTexture(this._size, {
+                bilinearFiltering,
+                comparisonFunction,
+                generateStencil,
+                isCube: this.isCube
+            });
+            engine.setFrameBufferDepthStencilTexture(this);
+        }
+
         private _processSizeParameter(size: number | {width: number, height: number} | {ratio: number}): void {
             if ((<{ratio: number}>size).ratio) {
                 this._sizeRatio = (<{ratio: number}>size).ratio;

+ 10 - 0
src/Materials/babylon.effect.ts

@@ -867,6 +867,16 @@
         public setTexture(channel: string, texture: Nullable<BaseTexture>): void {
             this._engine.setTexture(this._samplers.indexOf(channel), this.getUniform(channel), texture);
         }
+
+        /**
+         * Sets a depth stencil texture from a render target on the engine to be used in the shader.
+         * @param channel Name of the sampler variable.
+         * @param texture Texture to set.
+         */
+        public setDepthStencilTexture(channel: string, texture: Nullable<RenderTargetTexture>): void {
+            this._engine.setDepthStencilTexture(this._samplers.indexOf(channel), this.getUniform(channel), texture);
+        }
+
         /**
          * Sets an array of textures on the engine to be used in the shader.
          * @param channel Name of the variable.

+ 11 - 3
src/Shaders/ShadersInclude/lightFragment.fx

@@ -49,10 +49,18 @@
 						shadow = computeShadowWithPCF(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
 					#endif
 				#else
-					#if defined(SHADOWCUBE{X})
-						shadow = computeShadowCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.depthValues);
+					#if defined(USEDEPTHSTENCILTEXTURE{X})
+						#if defined(SHADOWCUBE{X})
+							shadow = computeShadowFromDepthTextureCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.depthValues);
+						#else
+							shadow = computeShadowFromDepthTexture(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+						#endif
 					#else
-						shadow = computeShadow(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+						#if defined(SHADOWCUBE{X})
+							shadow = computeShadowCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.depthValues);
+						#else
+							shadow = computeShadow(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+						#endif
 					#endif
 				#endif
 			#endif

+ 10 - 2
src/Shaders/ShadersInclude/lightFragmentDeclaration.fx

@@ -8,12 +8,20 @@
 	#endif
 	#ifdef SHADOW{X}
 		#if defined(SHADOWCUBE{X})
-			uniform samplerCube shadowSampler{X};
+			#if defined(USEDEPTHSTENCILTEXTURE{X})
+				uniform highp samplerCubeShadow shadowSampler{X};
+			#else
+				uniform samplerCube shadowSampler{X};
+			#endif
 		#else
 			varying vec4 vPositionFromLight{X};
 			varying float vDepthMetric{X};
 
-			uniform sampler2D shadowSampler{X};
+			#if defined(USEDEPTHSTENCILTEXTURE{X})
+				uniform highp sampler2DShadow shadowSampler{X};
+			#else
+				uniform sampler2D shadowSampler{X};
+			#endif
 			uniform mat4 lightMatrix{X};
 		#endif
 		uniform vec4 shadowsInfo{X};

+ 10 - 2
src/Shaders/ShadersInclude/lightUboDeclaration.fx

@@ -19,12 +19,20 @@
 #endif
 #ifdef SHADOW{X}
 	#if defined(SHADOWCUBE{X})
-		uniform samplerCube shadowSampler{X};
+		#if defined(USEDEPTHSTENCILTEXTURE{X})
+			uniform highp samplerCubeShadow shadowSampler{X};
+		#else
+			uniform samplerCube shadowSampler{X};
+		#endif
 	#else
 		varying vec4 vPositionFromLight{X};
 		varying float vDepthMetric{X};
 
-		uniform sampler2D shadowSampler{X};
+		#if defined(USEDEPTHSTENCILTEXTURE{X})
+			uniform highp sampler2DShadow shadowSampler{X};
+		#else
+			uniform sampler2D shadowSampler{X};
+		#endif
 		uniform mat4 lightMatrix{X};
 	#endif
 #endif

+ 20 - 0
src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx

@@ -106,6 +106,26 @@
 		return esm;
 	}
 
+#ifdef USEDEPTHSTENCILTEXTURE
+	float computeShadowFromDepthTexture(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, float darkness, float frustumEdgeFalloff)
+	{
+		vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+		vec3 uvDepth = vec3(0.5 * clipSpace.xy + vec2(0.5), 0.9);
+
+		if (uvDepth.x < 0. || uvDepth.x > 1.0 || uvDepth.y < 0. || uvDepth.y > 1.0)
+		{
+			return 1.0;
+		}
+
+		float shadow = texture2D(shadowSampler, uvDepth);
+		// if (shadow < 1.0)
+		// {
+		// 	return computeFallOff((1. - shadow) * darkness, clipSpace.xy, frustumEdgeFalloff);
+		// }
+		return shadow;
+	}
+#endif
+
 	float computeShadow(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float frustumEdgeFalloff)
 	{
 		vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;

+ 1 - 1
src/Shaders/ShadersInclude/shadowsVertex.fx

@@ -1,6 +1,6 @@
 #ifdef SHADOWS
 	#if defined(SHADOW{X}) && !defined(SHADOWCUBE{X})
 		vPositionFromLight{X} = lightMatrix{X} * worldPos;
-		vDepthMetric{X} =  ((vPositionFromLight{X}.z + light{X}.depthValues.x) / (light{X}.depthValues.y));
+		vDepthMetric{X} = ((vPositionFromLight{X}.z + light{X}.depthValues.x) / (light{X}.depthValues.y));
 	#endif
 #endif

+ 5 - 0
src/Shaders/shadowMap.vertex.fx

@@ -30,8 +30,13 @@ void main(void)
 
 vec4 worldPos = finalWorld * vec4(position, 1.0);
 gl_Position = viewProjection * worldPos;
+
+
 vDepthMetric = ((gl_Position.z + depthValues.x) / (depthValues.y)) + biasAndScale.x;
 
+ gl_Position.z = vDepthMetric;
+// gl_Position.w = 1.0;
+
 #ifdef ALPHATEST
 	#ifdef UV1
 		vUV = vec2(diffuseMatrix * vec4(uv, 1.0, 0.0));