Browse Source

ssao shader refactored

Benjamin Guignabert 8 năm trước cách đây
mục cha
commit
fcee023128

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1207 - 1216
dist/preview release/babylon.d.ts


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1207 - 1216
dist/preview release/babylon.module.d.ts


+ 2 - 3
src/PostProcess/babylon.postProcess.ts

@@ -181,8 +181,7 @@
                 let textureOptions = { 
                     generateMipMaps: false, 
                     generateDepthBuffer: camera._postProcesses.indexOf(this) === 0, 
-                    generateStencilBuffer: 
-                    camera._postProcesses.indexOf(this) === 0 && this._engine.isStencilEnable,
+                    generateStencilBuffer: camera._postProcesses.indexOf(this) === 0 && this._engine.isStencilEnable,
                     samplingMode: this.renderTargetSamplingMode, 
                     type: this._textureType 
                 };
@@ -192,7 +191,7 @@
                 if (this._reusable) {
                     this._textures.push(this._engine.createRenderTargetTexture(textureSize, textureOptions));
                 }
- 
+
                 this.onSizeChangedObservable.notifyObservers(this);
             }
 

+ 46 - 35
src/PostProcess/babylon.ssaoRenderingPipeline.ts

@@ -35,32 +35,39 @@
         @serialize()
         public totalStrength: number = 1.0;
 
-        public samples: number = 16.0;
-
         /**
-        * The radius around the analyzed pixel used by the SSAO post-process. Default value is 0.0006
+        * Number of samples used for the SSAO calculations. Default value is 8
         * @type {number}
         */
         @serialize()
-        public radius: number = 0.0001;
+        private _samples: number = 8;
 
-        /**
-        * Related to fallOff, used to interpolate SSAO samples (first interpolate function input) based on the occlusion difference of each pixel
-        * Must not be equal to fallOff and superior to fallOff.
-        * Default value is 0.975
-        * @type {number}
-        */
-        @serialize()
-        public area: number = 0.0075;
+        public set samples(n: number) {
+            this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
+
+            this._samples = n;
+            for (var i = 0; i < this._scene.cameras.length; i++) {
+                var camera = this._scene.cameras[i];
+                this._ssaoPostProcess.dispose(camera);
+            }
+
+            this._createSSAOPostProcess(this._ratio.ssaoRatio);
+            this.addEffect(new PostProcessRenderEffect(this._scene.getEngine(), this.SSAORenderEffect, () => { return this._ssaoPostProcess; }, true));
+
+            if (this._cameras)
+                this._scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(this._name, this._cameras);
+        }
+
+        public get samples(): number {
+            return this._samples;
+        }
 
         /**
-        * Related to area, used to interpolate SSAO samples (second interpolate function input) based on the occlusion difference of each pixel
-        * Must not be equal to area and inferior to area.
-        * Default value is 0.0
+        * The radius around the analyzed pixel used by the SSAO post-process. Default value is 2.0
         * @type {number}
         */
         @serialize()
-        public fallOff: number = 0.000001;
+        public radius: number = 2.0;
 
         /**
         * The base color of the SSAO post-process
@@ -98,11 +105,6 @@
 
             this._scene = scene;
 
-            // Set up assets
-            this._createRandomTexture();
-            this._depthTexture = scene.enableGeometryRenderer().getGBuffer().depthTexture; 
-            this._normalTexture = scene.enableGeometryRenderer().getGBuffer().textures[1];
-
             var ssaoRatio = ratio.ssaoRatio || ratio;
             var combineRatio = ratio.combineRatio || ratio;
             this._ratio = {
@@ -110,6 +112,11 @@
                 combineRatio: combineRatio
             };
 
+            // Set up assets
+            this._createRandomTexture();
+            this._depthTexture = scene.enableGeometryRenderer(this._ratio.ssaoRatio).getGBuffer().depthTexture; 
+            this._normalTexture = scene.enableGeometryRenderer(this._ratio.ssaoRatio).getGBuffer().textures[1];
+
             this._originalColorPostProcess = new PassPostProcess("SSAOOriginalSceneColor", combineRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
             this._createSSAOPostProcess(ssaoRatio);
             this._createBlurPostProcess(ssaoRatio);
@@ -118,8 +125,8 @@
             // Set up pipeline
             this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOOriginalSceneColorEffect, () => { return this._originalColorPostProcess; }, true));
             this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAORenderEffect, () => { return this._ssaoPostProcess; }, true));
-            // this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOBlurHRenderEffect, () => { return this._blurHPostProcess; }, true));
-            // this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOBlurVRenderEffect, () => { return this._blurVPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOBlurHRenderEffect, () => { return this._blurHPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOBlurVRenderEffect, () => { return this._blurVPostProcess; }, true));
             this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOCombineRenderEffect, () => { return this._ssaoCombinePostProcess; }, true));
 
             // Finish
@@ -133,7 +140,7 @@
         /**
          * Removes the internal pipeline assets and detatches the pipeline from the scene cameras
          */
-        public dispose(disableDepthRender: boolean = false): void {
+        public dispose(disableGeometryRenderer: boolean = false): void {
             for (var i = 0; i < this._scene.cameras.length; i++) {
                 var camera = this._scene.cameras[i];
 
@@ -146,8 +153,8 @@
 
             this._randomTexture.dispose();
 
-            if (disableDepthRender)
-                this._scene.disableDepthRenderer();
+            if (disableGeometryRenderer)
+                this._scene.disableGeometryRenderer();
 
             this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
 
@@ -163,9 +170,12 @@
                 samplerOffsets.push(i * 2);
             }
 
-            this._blurHPostProcess = new PostProcess("BlurH", "ssao", ["outSize", "samplerOffsets"], ["depthSampler"], ratio, null, Texture.TRILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, "#define BILATERAL_BLUR\n#define BILATERAL_BLUR_H\n#define SAMPLES 16");
+            this._blurHPostProcess = new PostProcess("BlurH", "ssao", ["outSize", "samplerOffsets", "near", "far", "radius"], ["depthSampler"], ratio, null, Texture.TRILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, "#define BILATERAL_BLUR\n#define BILATERAL_BLUR_H\n#define SAMPLES 16");
             this._blurHPostProcess.onApply = (effect: Effect) => {
                 effect.setFloat("outSize", this._ssaoCombinePostProcess.width);
+                effect.setFloat("near", this._scene.activeCamera.minZ);
+                effect.setFloat("far", this._scene.activeCamera.maxZ);
+                effect.setFloat("radius", this.radius);
                 effect.setTexture("depthSampler", this._depthTexture);
 
                 if (this._firstUpdate) {
@@ -173,9 +183,12 @@
                 }
             };
 
-            this._blurVPostProcess = new PostProcess("BlurV", "ssao", ["outSize", "samplerOffsets"], ["depthSampler"], ratio, null, Texture.TRILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, "#define BILATERAL_BLUR\n#define SAMPLES 16");
+            this._blurVPostProcess = new PostProcess("BlurV", "ssao", ["outSize", "samplerOffsets", "near", "far", "radius"], ["depthSampler"], ratio, null, Texture.TRILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, "#define BILATERAL_BLUR\n#define SAMPLES 16");
             this._blurVPostProcess.onApply = (effect: Effect) => {
                 effect.setFloat("outSize", this._ssaoCombinePostProcess.height);
+                effect.setFloat("near", this._scene.activeCamera.minZ);
+                effect.setFloat("far", this._scene.activeCamera.maxZ);
+                effect.setFloat("radius", this.radius);
                 effect.setTexture("depthSampler", this._depthTexture);
 
                 if (this._firstUpdate) {
@@ -185,7 +198,7 @@
             };
         }
 
-        private generateHemisphere(): number[] {
+        private _generateHemisphere(): number[] {
             var numSamples = this.samples;
             var result = [];
             var vector, scale;
@@ -224,13 +237,13 @@
         private _createSSAOPostProcess(ratio: number): void {
             var numSamples = this.samples;
 
-            var sampleSphere = this.generateHemisphere();
+            var sampleSphere = this._generateHemisphere();
             var samplesFactor = 1.0 / numSamples;
 
             this._ssaoPostProcess = new PostProcess("ssao", "ssao",
                                                     [
                                                         "sampleSphere", "samplesFactor", "randTextureTiles", "totalStrength", "radius",
-                                                        "area", "fallOff", "base", "range", "viewport", "width", "height", "projection",
+                                                        "base", "range", "viewport", "projection", "near", "far",
                                                         "xViewport", "yViewport"
                                                     ],
                                                     ["randomSampler", "normalSampler"],
@@ -249,11 +262,9 @@
 
                 effect.setFloat("totalStrength", this.totalStrength);
                 effect.setFloat("radius", this.radius);
-                effect.setFloat("area", this.area);
-                effect.setFloat("fallOff", this.fallOff);
                 effect.setFloat("base", this.base);
-                effect.setFloat("width", this._scene.getEngine().getRenderWidth());
-                effect.setFloat("height", this._scene.getEngine().getRenderHeight());
+                effect.setFloat("near", this._scene.activeCamera.minZ);
+                effect.setFloat("far", this._scene.activeCamera.maxZ);
                 effect.setFloat("xViewport", Math.tan(this._scene.activeCamera.fov / 2) * this._scene.activeCamera.minZ * this._scene.getEngine().getAspectRatio(this._scene.activeCamera, true));
                 effect.setFloat("yViewport", Math.tan(this._scene.activeCamera.fov / 2) * this._scene.activeCamera.minZ );
                 effect.setMatrix("projection", this._scene.getProjectionMatrix());

+ 2 - 2
src/Rendering/babylon.geometryRenderer.ts

@@ -11,12 +11,12 @@ module BABYLON {
 
         private _cachedDefines: string;
 
-        constructor(scene: Scene, type: number = Engine.TEXTURETYPE_FLOAT) {
+        constructor(scene: Scene, ratio: number = 1) {
             this._scene = scene;
             var engine = scene.getEngine();
 
             // Render target
-            this._multiRenderTarget = new MultiRenderTarget("gBuffer", { width: engine.getRenderWidth(), height: engine.getRenderHeight() }, 2, this._scene, { generateMipMaps : true, generateDepthTexture: true });
+            this._multiRenderTarget = new MultiRenderTarget("gBuffer", { width: engine.getRenderWidth() * ratio, height: engine.getRenderHeight() * ratio }, 2, this._scene, { generateMipMaps : true, generateDepthTexture: true });
             this._multiRenderTarget.wrapU = Texture.CLAMP_ADDRESSMODE;
             this._multiRenderTarget.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._multiRenderTarget.refreshRate = 1;

+ 20 - 60
src/Shaders/ssao.fragment.fx

@@ -1,6 +1,9 @@
 // SSAO Shader
 precision highp float;
 uniform sampler2D textureSampler;
+uniform float near;
+uniform float far;
+uniform float radius;
 
 varying vec2 vUV;
 
@@ -8,6 +11,10 @@ float perspectiveDepthToViewZ( const in float invClipZ, const in float near, con
 	return ( near * far ) / ( ( far - near ) * invClipZ - far );
 }
 
+float viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {
+	return ( near * far / viewZ + far) / ( far - near );
+}
+
 float viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {
 	return ( viewZ + near ) / ( near - far );
 }
@@ -21,74 +28,36 @@ uniform float samplesFactor;
 uniform vec3 sampleSphere[SAMPLES];
 
 uniform float totalStrength;
-uniform float radius;
-uniform float area;
-uniform float fallOff;
 uniform float base;
 uniform float xViewport;
 uniform float yViewport;
 
 uniform mat4 projection;
 
-vec3 normalFromDepth(float depth, vec2 coords)
-{	
-	vec2 offset1 = vec2(0.0, radius);
-	vec2 offset2 = vec2(radius, 0.0);
-
-	float depth1 = texture2D(textureSampler, coords + offset1).r;
-	float depth2 = texture2D(textureSampler, coords + offset2).r;
-
-	vec3 p1 = vec3(offset1, depth1 - depth);
-	vec3 p2 = vec3(offset2, depth2 - depth);
-
-	vec3 normal = cross(p1, p2);
-	normal.z = -normal.z;
-
-	return normalize(normal);
-}
-
 void main()
 {
-	vec3 random = normalize(texture2D(randomSampler, vUV * randTextureTiles).rgb);
+	vec3 random = texture2D(randomSampler, vUV * randTextureTiles).rgb;
 	float depth = texture2D(textureSampler, vUV).r;
-	float n = 1.0;                                // the near plane
-	float f = 100.0;
-	float linearDepth = - perspectiveDepthToViewZ(depth, n, f);
-	vec3 position = vec3(vUV, linearDepth);
+	float linearDepth = - perspectiveDepthToViewZ(depth, near, far);
 	vec3 normal = texture2D(normalSampler, vUV).rgb; 
-	float radiusDepth = radius; //linearDepth / radius;
 	float occlusion = 0.0;
 
 	vec3 vViewRay = vec3((vUV.x * 2.0 - 1.0)*xViewport, (vUV.y * 2.0 - 1.0)*yViewport, 1.0);
 	vec3 origin = vViewRay * linearDepth;
 	vec3 rvec = random * 2.0 - 1.0;
+	rvec.z = 0.0;
 	vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
 	vec3 bitangent = cross(normal, tangent);
 	mat3 tbn = mat3(tangent, bitangent, normal);
 
-	vec3 ray;
-	vec3 hemiRay;
-	float occlusionDepth;
 	float difference;
 
-	// for (int i = 0; i < SAMPLES; i++)
-	// {
-	// 	ray = 0.02 * reflect(sampleSphere[i], random);
-	// 	hemiRay = position + sign(dot(ray, normal)) * ray;
-
-	// 	occlusionDepth = texture2D(textureSampler, clamp(hemiRay.xy, vec2(0.001, 0.001), vec2(0.999, 0.999))).r;
-	// 	difference = linearDepth - occlusionDepth;
-
-	// 	occlusion += step(fallOff, difference) * (1.0 - smoothstep(fallOff, area, difference));
-	// }
-
 	for (int i = 0; i < SAMPLES; ++i) {
 		// get sample position:
 	   vec3 samplePosition = tbn * sampleSphere[i];
-	   samplePosition = samplePosition * radiusDepth + origin;
+	   samplePosition = samplePosition * radius + origin;
 	  
 		// project sample position:
-		// vec2 offset = vec2(n / samplePosition.z * samplePosition.x,  n / samplePosition.z * samplePosition.y) * 0.5 + 0.5;
 	   vec4 offset = vec4(samplePosition, 1.0);
 	   offset = projection * offset;
 	   offset.xyz /= offset.w;
@@ -96,26 +65,21 @@ void main()
 	  
 		// get sample linearDepth:
 	   float sampleDepth = texture(textureSampler, offset.xy).r;
-	   float linearSampleDepth = - perspectiveDepthToViewZ(texture(textureSampler, offset.xy).r, n, f);
+	   float linearSampleDepth = - perspectiveDepthToViewZ(texture(textureSampler, offset.xy).r, near, far);
 		// range check & accumulate:
-	   float rangeCheck = abs(linearDepth - linearSampleDepth) < radiusDepth ? 1.0 : 0.0;
-	   // occlusion += (sampleDepth <= samplePosition.z ? 1.0 : 0.0) * rangeCheck;
+	   float rangeCheck = abs(linearDepth - linearSampleDepth) < radius ? 1.0 : 0.0;
 	  	difference = samplePosition.z - linearSampleDepth;
 	  	//occlusion += step(fallOff, difference) * (1.0 - smoothstep(fallOff, area, difference)) * rangeCheck;
-	  	occlusion += (difference > 0.00000005 ? 1.0 : 0.0) * rangeCheck;
+	  	occlusion += (difference > 0.0 ? 1.0 : 0.0) * rangeCheck;
 
 	}
 
 
+	// float screenEdgeFactor = clamp(vUV.x * 10.0, 0.0, 1.0) * clamp(vUV.y * 10.0, 0.0, 1.0) * clamp((1.0 - vUV.x) * 10.0, 0.0, 1.0) * clamp((1.0 - vUV.y) * 10.0, 0.0, 1.0);
+
 	float ao = 1.0 - totalStrength * occlusion * samplesFactor;
 	float result = clamp(ao + base, 0.0, 1.0);
-
-	// gl_FragColor.r = result;
-	// gl_FragColor.g = result;
-	// gl_FragColor.b = result;
-	// gl_FragColor.a = 1.0;
-	ao = 1.0 - totalStrength * occlusion * samplesFactor;
-	gl_FragColor = vec4(ao, ao, ao, 1.0);
+	gl_FragColor = vec4(result, result, result, 1.0);
 }
 #endif
 
@@ -126,13 +90,9 @@ uniform float samplerOffsets[SAMPLES];
 
 void main()
 {
-
-	// TODO change
-	float n = 1.0;
-	float f = 100.0;
 	float texelsize = 1.0 / outSize;
 	float compareDepth = texture2D(depthSampler, vUV).r;
-	float linearDepth = - perspectiveDepthToViewZ(compareDepth, n, f);
+	float linearDepth = - perspectiveDepthToViewZ(compareDepth, near, far);
 	float result = 0.0;
 	float weightSum = 0.0;
 
@@ -146,8 +106,8 @@ void main()
 		vec2 samplePos = vUV + sampleOffset;
 
 		float sampleDepth = texture2D(depthSampler, samplePos).r;
-		float linearSampleDepth = - perspectiveDepthToViewZ(sampleDepth, n, f);
-		float weight = (1.0 / (0.0005 + abs(linearDepth - linearSampleDepth)));
+		float linearSampleDepth = - perspectiveDepthToViewZ(sampleDepth, near, far);
+		float weight = abs(linearDepth - linearSampleDepth) < radius ? 1.0 : 0.0;
 
 		result += texture2D(textureSampler, samplePos).r * weight;
 		weightSum += weight;

+ 2 - 2
src/babylon.scene.ts

@@ -3111,12 +3111,12 @@
             this._depthRenderer = null;
         }
 
-        public enableGeometryRenderer(): GeometryRenderer {
+        public enableGeometryRenderer(ratio: number = 1): GeometryRenderer {
             if (this._geometryRenderer) {
                 return this._geometryRenderer;
             }
 
-            this._geometryRenderer = new GeometryRenderer(this);
+            this._geometryRenderer = new GeometryRenderer(this, ratio);
 
             return this._geometryRenderer;
         }