فهرست منبع

fixing SSAO2 with hammersley sequence, using 4 samples per texture

Benjamin Guignabert 7 سال پیش
والد
کامیت
d6a48bf24a

+ 37 - 10
src/PostProcess/RenderPipeline/Pipelines/babylon.ssao2RenderingPipeline.ts

@@ -158,6 +158,7 @@
             this._normalTexture = geometryBufferRenderer.getGBuffer().textures[1];
 
             this._originalColorPostProcess = new PassPostProcess("SSAOOriginalSceneColor", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            this._originalColorPostProcess.samples = 4;
             this._createSSAOPostProcess(1.0);
             this._createBlurPostProcess(ssaoRatio, blurRatio);
             this._createSSAOCombinePostProcess(blurRatio);
@@ -245,6 +246,9 @@
                     this._firstUpdate = false;
                 }
             };
+
+            this._blurHPostProcess.samples =4;
+            this._blurVPostProcess.samples =4;
         }
 
         /** @hidden */
@@ -254,27 +258,48 @@
             super._rebuild();
         }
 
+        private _bits = new Uint32Array(1);
+
+        //Van der Corput radical inverse
+        private _radicalInverse_VdC(i: number) {
+            this._bits[0] = i;
+            this._bits[0] = ((this._bits[0] << 16) | (this._bits[0] >> 16))>>>0;
+            this._bits[0] = ((this._bits[0] & 0x55555555) << 1) | ((this._bits[0] & 0xAAAAAAAA) >>> 1) >>>0;
+            this._bits[0] = ((this._bits[0] & 0x33333333) << 2) | ((this._bits[0] & 0xCCCCCCCC) >>> 2) >>>0;
+            this._bits[0] = ((this._bits[0] & 0x0F0F0F0F) << 4) | ((this._bits[0] & 0xF0F0F0F0) >>> 4) >>>0;
+            this._bits[0] = ((this._bits[0] & 0x00FF00FF) << 8) | ((this._bits[0] & 0xFF00FF00) >>> 8) >>>0;
+            return this._bits[0] * 2.3283064365386963e-10; // / 0x100000000 or / 4294967296
+        }
+
+        private _hammersley(i : number, n : number) {
+            return [i/n, this._radicalInverse_VdC(i)];
+        }
+
+        private _hemisphereSample_uniform(u: number, v: number) : Vector3 {
+            var phi = v * 2.0 * Math.PI;
+            var cosTheta = 1.0 - u;
+            var sinTheta = Math.sqrt(1.0 - cosTheta * cosTheta);
+            return new Vector3(Math.cos(phi) * sinTheta, Math.sin(phi) * sinTheta, Math.max(0.35, cosTheta)).normalize();
+         }
+
         private _generateHemisphere(): number[] {
             var numSamples = this.samples;
             var result = [];
             var vector, scale;
 
-            var rand = (min: number, max: number) => {
-                return Math.random() * (max - min) + min;
-            }
+            // var rand = (min: number, max: number) => {
+            //     return Math.random() * (max - min) + min;
+            // }
 
             var i = 0;
             while (i < numSamples) {
-                vector = new Vector3(
-                    rand(-1.0, 1.0),
-                    rand(-1.0, 1.0),
-                    rand(0.30, 1.0));
+                var rand = this._hammersley(i, numSamples);
+                vector = this._hemisphereSample_uniform(rand[0], rand[1]);
                 vector.normalize();
                 scale = i / numSamples;
-                scale = Scalar.Lerp(0.1, 1.0, scale * scale);
+                scale = Scalar.Lerp(0.05, 1.0, scale * scale);
                 vector.scaleInPlace(scale);
 
-
                 result.push(vector.x, vector.y, vector.z);
                 i++;
             }
@@ -325,6 +350,7 @@
                 effect.setTexture("normalSampler", this._normalTexture);
                 effect.setTexture("randomSampler", this._randomTexture);
             };
+            this._ssaoPostProcess.samples =4;
         }
 
         private _createSSAOCombinePostProcess(ratio: number): void {
@@ -337,12 +363,13 @@
                 effect.setVector4("viewport", Tmp.Vector4[0].copyFromFloats(viewport.x, viewport.y, viewport.width, viewport.height));
                 effect.setTextureFromPostProcess("originalColor", this._originalColorPostProcess);
             };
+            this._ssaoCombinePostProcess.samples =4;
         }
 
         private _createRandomTexture(): void {
             var size = 512;
 
-            this._randomTexture = new DynamicTexture("SSAORandomTexture", size, this._scene, false, Texture.TRILINEAR_SAMPLINGMODE);
+            this._randomTexture = new DynamicTexture("SSAORandomTexture", size, this._scene, false, Texture.NEAREST_SAMPLINGMODE);
             this._randomTexture.wrapU = Texture.WRAP_ADDRESSMODE;
             this._randomTexture.wrapV = Texture.WRAP_ADDRESSMODE;
 

+ 0 - 1
src/Rendering/babylon.geometryBufferRenderer.ts

@@ -202,7 +202,6 @@ module BABYLON {
             this._multiRenderTarget.onClearObservable.add((engine: Engine) => {
                 engine.clear(new Color4(0.0, 0.0, 0.0, 1.0), true, true, true);
             });
-
             // Custom render function
             var renderSubMesh = (subMesh: SubMesh): void => {
                 var mesh = subMesh.getRenderingMesh();

+ 6 - 6
src/Shaders/ssao2.fragment.fx

@@ -51,6 +51,10 @@ void main()
 	vec3 origin = vViewRay * depth;
 	vec3 rvec = random * 2.0 - 1.0;
 	rvec.z = 0.0;
+
+	// Avoid numerical precision issue while applying Gram-Schmidt
+	float dotProduct = dot(rvec, normal);
+	rvec = 1.0 - abs(dotProduct) < 1e-2 ? rvec : vec3(-rvec.y, 0.0, rvec.x);
 	vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
 	vec3 bitangent = cross(normal, tangent);
 	mat3 tbn = mat3(tangent, bitangent, normal);
@@ -80,15 +84,11 @@ void main()
 		// get sample linearDepth:
 	   float sampleDepth = abs(texture2D(textureSampler, offset.xy).r);
 		// range check & accumulate:
-	   float rangeCheck = abs(depth - sampleDepth) < correctedRadius ? 1.0 : 0.0;
 	   difference = depthSign * samplePosition.z - sampleDepth;
-	  //occlusion += step(fallOff, difference) * (1.0 - smoothstep(fallOff, area, difference)) * rangeCheck;
-	   occlusion += (difference >= 1e-5 ? 1.0 : 0.0) * rangeCheck;
+	   float rangeCheck = smoothstep(correctedRadius, difference, correctedRadius * 0.15);
+	   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 = vec4(vec3(result), 1.0);