Benjamin Guignabert 7 лет назад
Родитель
Сommit
a3b7af2ba2

+ 51 - 30
src/PostProcess/RenderPipeline/Pipelines/babylon.ssao2RenderingPipeline.ts

@@ -48,6 +48,26 @@
         private _samples: number = 8;
 
         /**
+        * Number of samples to use for antialiasing
+        */
+        @serialize("textureSamples")
+        private _textureSamples: number = 1;
+
+        public set textureSamples(n: number) {
+            this._textureSamples = n;
+
+            this._originalColorPostProcess.samples = n;
+            this._blurHPostProcess.samples = n;
+            this._blurVPostProcess.samples = n;
+            this._ssaoPostProcess.samples = n;
+            this._ssaoCombinePostProcess.samples = n;
+        }
+
+        public get textureSamples(): number {
+            return this._textureSamples;
+        }
+
+        /**
          * Ratio object used for SSAO ratio and blur ratio
          */
         @serialize()
@@ -104,7 +124,7 @@
         * The final result is "base + ssao" between [0, 1]
         */
         @serialize()
-        public base: number = 0.1;
+        public base: number = 0;
 
         /**
         *  Support test.
@@ -158,7 +178,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._originalColorPostProcess.samples = this.textureSamples;
             this._createSSAOPostProcess(1.0);
             this._createBlurPostProcess(ssaoRatio, blurRatio);
             this._createSSAOCombinePostProcess(blurRatio);
@@ -247,8 +267,8 @@
                 }
             };
 
-            this._blurHPostProcess.samples =4;
-            this._blurVPostProcess.samples =4;
+            this._blurHPostProcess.samples = this.textureSamples;
+            this._blurVPostProcess.samples = this.textureSamples;
         }
 
         /** @hidden */
@@ -263,38 +283,39 @@
         //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;
+            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 _hammersley(i: number, n: number) {
+            return [i / n, this._radicalInverse_VdC(i)];
         }
 
-        private _hemisphereSample_uniform(u: number, v: number) : Vector3 {
+        private _hemisphereSample_uniform(u: number, v: number): Vector3 {
             var phi = v * 2.0 * Math.PI;
-            var cosTheta = 1.0 - u;
+            // rejecting samples that are close to tangent plane to avoid z-fighting artifacts
+            var cosTheta = 1.0 - (u * 0.85 + 0.15); 
             var sinTheta = Math.sqrt(1.0 - cosTheta * cosTheta);
-            return new Vector3(Math.cos(phi) * sinTheta, Math.sin(phi) * sinTheta, cosTheta);
-         }
+            return new Vector3(Math.cos(phi) * sinTheta, Math.sin(phi) * sinTheta, cosTheta );
+        }
 
         private _generateHemisphere(): number[] {
             var numSamples = this.samples;
             var result = [];
-            var vector, scale;
-
-            var i = 1;
-            while (i < numSamples + 1) {
-                var rand = this._hammersley(i, numSamples + 1);
-                vector = this._hemisphereSample_uniform(rand[0], rand[1]);
-                vector.normalize();
-                scale = i / numSamples;
-                scale = Scalar.Lerp(0.15, 1.0, scale * scale);
-                vector.scaleInPlace(scale);
+            var vector;
+
+            var i = 0;
+            while (i < numSamples) {
+                if (numSamples < 16) {
+                    vector = this._hemisphereSample_uniform(Math.random(), Math.random());
+                } else {
+                    var rand = this._hammersley(i, numSamples);
+                    vector = this._hemisphereSample_uniform(rand[0], rand[1]);
+                }
 
                 result.push(vector.x, vector.y, vector.z);
                 i++;
@@ -322,7 +343,7 @@
             this._ssaoPostProcess.onApply = (effect: Effect) => {
                 if (this._firstUpdate) {
                     effect.setArray3("sampleSphere", this._sampleSphere);
-                    effect.setFloat("randTextureTiles", 128.0);
+                    effect.setFloat("randTextureTiles", 32.0);
                 }
 
                 if (!this._scene.activeCamera) {
@@ -346,7 +367,7 @@
                 effect.setTexture("normalSampler", this._normalTexture);
                 effect.setTexture("randomSampler", this._randomTexture);
             };
-            this._ssaoPostProcess.samples =4;
+            this._ssaoPostProcess.samples = this.textureSamples;
         }
 
         private _createSSAOCombinePostProcess(ratio: number): void {
@@ -359,13 +380,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;
+            this._ssaoCombinePostProcess.samples = this.textureSamples;
         }
 
         private _createRandomTexture(): void {
-            var size = 16;
+            var size = 128;
 
-            this._randomTexture = new DynamicTexture("SSAORandomTexture", size, this._scene, false, Texture.NEAREST_SAMPLINGMODE);
+            this._randomTexture = new DynamicTexture("SSAORandomTexture", size, this._scene, false, Texture.TRILINEAR_SAMPLINGMODE);
             this._randomTexture.wrapU = Texture.WRAP_ADDRESSMODE;
             this._randomTexture.wrapV = Texture.WRAP_ADDRESSMODE;
 

+ 15 - 1
src/PostProcess/babylon.postProcess.ts

@@ -76,7 +76,21 @@
         /**
         * Number of sample textures (default: 1)
         */
-        public samples = 1;
+        private _samples = 1;
+        public get samples () {
+            return this._samples;
+        }
+
+        public set samples (n: number) {
+            this._samples = n;
+
+            this._textures.forEach(texture => {
+                if (texture.samples !== this._samples) {
+                    this._engine.updateRenderTargetTextureSampleCount(texture, this._samples);
+                }
+            });
+        }
+        
         /**
         * Modify the scale of the post process to be the same as the viewport (default: false)
         */

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

@@ -188,7 +188,7 @@ module BABYLON {
 
             this._multiRenderTarget = new MultiRenderTarget("gBuffer",
                 { width: engine.getRenderWidth() * this._ratio, height: engine.getRenderHeight() * this._ratio }, count, this._scene,
-                { generateMipMaps: false, generateDepthTexture: true, defaultType: Engine.TEXTURETYPE_FLOAT, samplingModes:[Texture.NEAREST_SAMPLINGMODE, Texture.NEAREST_SAMPLINGMODE] });
+                { generateMipMaps: false, generateDepthTexture: true, defaultType: Engine.TEXTURETYPE_FLOAT });
             if (!this.isSupported) {
                 return;
             }

+ 22 - 8
src/Shaders/ssao2.fragment.fx

@@ -5,6 +5,25 @@ uniform float near;
 uniform float far;
 uniform float radius;
 
+float scales[16] = float[16](
+0.1,
+0.11406250000000001,
+0.131640625,
+0.15625,
+0.187890625,
+0.2265625,
+0.272265625,
+0.325,
+0.384765625,
+0.4515625,
+0.525390625,
+0.60625,
+0.694140625,
+0.7890625,
+0.891015625,
+1.0
+);
+
 varying vec2 vUV;
 
 float perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {
@@ -61,14 +80,9 @@ void main()
 
 	float difference;
 
-	if (depth > maxZ) {
-		gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
-		return;
-	}
-
 	for (int i = 0; i < SAMPLES; ++i) {
 		// get sample position:
-	   vec3 samplePosition = tbn * sampleSphere[i];
+	   vec3 samplePosition = scales[(i + int(random.x * 16.0)) % 16] * tbn * sampleSphere[(i + int(random.y * 16.0)) % 16];
 	   samplePosition = samplePosition * correctedRadius + origin;
 	  
 		// project sample position:
@@ -85,10 +99,10 @@ void main()
 	   float sampleDepth = abs(texture2D(textureSampler, offset.xy).r);
 		// range check & accumulate:
 	   difference = depthSign * samplePosition.z - sampleDepth;
-	   float rangeCheck = smoothstep(correctedRadius, difference, correctedRadius * 0.15);
+	   float rangeCheck = 1.0 - smoothstep(correctedRadius*0.5, correctedRadius, difference);
 	   occlusion += (difference >= 0.0 ? 1.0 : 0.0) * rangeCheck;
 	}
-
+	occlusion = occlusion*(1.0 - smoothstep(maxZ * 0.75, maxZ, depth));
 	float ao = 1.0 - totalStrength * occlusion * samplesFactor;
 	float result = clamp(ao + base, 0.0, 1.0);
 	gl_FragColor = vec4(vec3(result), 1.0);