Benjamin Guignabert 8 лет назад
Родитель
Сommit
9016bd6f02

+ 58 - 98
src/PostProcess/babylon.ssaoRenderingPipeline.ts

@@ -36,38 +36,29 @@
         public totalStrength: number = 1.0;
 
         /**
-        * Number of samples used for the SSAO calculations. Default value is 8
+        * The radius around the analyzed pixel used by the SSAO post-process. Default value is 0.0006
         * @type {number}
         */
         @serialize()
-        private _samples: number = 8;
+        public radius: number = 0.0001;
 
-        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 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;
 
         /**
-        * The radius around the analyzed pixel used by the SSAO post-process. Default value is 2.0
+        * 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
         * @type {number}
         */
         @serialize()
-        public radius: number = 2.0;
+        public fallOff: number = 0.000001;
 
         /**
         * The base color of the SSAO post-process
@@ -78,8 +69,7 @@
         public base: number = 0.5;
 
         private _scene: Scene;
-        private _depthTexture: Texture;
-        private _normalTexture: Texture;
+        private _depthTexture: RenderTargetTexture;
         private _randomTexture: DynamicTexture;
 
         private _originalColorPostProcess: PassPostProcess;
@@ -105,6 +95,10 @@
 
             this._scene = scene;
 
+            // Set up assets
+            this._createRandomTexture();
+            this._depthTexture = scene.enableDepthRenderer().getDepthMap(); // Force depth renderer "on"
+
             var ssaoRatio = ratio.ssaoRatio || ratio;
             var combineRatio = ratio.combineRatio || ratio;
             this._ratio = {
@@ -112,11 +106,6 @@
                 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);
@@ -127,6 +116,7 @@
             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.SSAOCombineRenderEffect, () => { return this._ssaoCombinePostProcess; }, true));
 
             // Finish
@@ -140,7 +130,7 @@
         /**
          * Removes the internal pipeline assets and detatches the pipeline from the scene cameras
          */
-        public dispose(disableGeometryRenderer: boolean = false): void {
+        public dispose(disableDepthRender: boolean = false): void {
             for (var i = 0; i < this._scene.cameras.length; i++) {
                 var camera = this._scene.cameras[i];
 
@@ -153,8 +143,8 @@
 
             this._randomTexture.dispose();
 
-            if (disableGeometryRenderer)
-                this._scene.disableGeometryRenderer();
+            if (disableDepthRender)
+                this._scene.disableDepthRenderer();
 
             this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
 
@@ -163,6 +153,13 @@
 
         // Private Methods
         private _createBlurPostProcess(ratio: number): void {
+            /*
+            var samplerOffsets = [
+                -8.0, -6.0, -4.0, -2.0,
+                0.0,
+                2.0, 4.0, 6.0, 8.0
+            ];
+            */
             var samples = 16;
             var samplerOffsets = [];
 
@@ -170,12 +167,9 @@
                 samplerOffsets.push(i * 2);
             }
 
-            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 = 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.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) {
@@ -183,12 +177,9 @@
                 }
             };
 
-            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 = 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.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) {
@@ -198,55 +189,34 @@
             };
         }
 
-        private _generateHemisphere(): number[] {
-            var numSamples = this.samples;
-            var result = [];
-            var vector, scale;
-
-            var rand = (min, max) => {
-                return Math.random() * (max - min) + min;
-            }
-
-            var lerp = (start, end, percent) => {
-                return (start + percent*(end - start));
-            }
-
-            var i = 0;
-            var normal = new BABYLON.Vector3(0, 0, 1);
-            while (i < numSamples) {
-               vector = new BABYLON.Vector3(
-                   rand(-1.0, 1.0),
-                   rand(-1.0, 1.0),
-                   rand(0.0, 1.0));
-               vector.normalize();
-               if (BABYLON.Vector3.Dot(vector, normal) < 0.07) {
-                   continue;
-               }
-               scale = i / numSamples;
-               scale = lerp(0.1, 1.0, scale*scale);
-               vector.scaleInPlace(scale);
-
-
-               result.push(vector.x, vector.y, vector.z);
-               i++;
-            }
-
-            return result;
-        }
-
         private _createSSAOPostProcess(ratio: number): void {
-            var numSamples = this.samples;
-
-            var sampleSphere = this._generateHemisphere();
+            var numSamples = 16;
+            var sampleSphere = [
+                0.5381, 0.1856, -0.4319,
+                0.1379, 0.2486, 0.4430,
+                0.3371, 0.5679, -0.0057,
+                -0.6999, -0.0451, -0.0019,
+                0.0689, -0.1598, -0.8547,
+                0.0560, 0.0069, -0.1843,
+                -0.0146, 0.1402, 0.0762,
+                0.0100, -0.1924, -0.0344,
+                -0.3577, -0.5301, -0.4358,
+                -0.3169, 0.1063, 0.0158,
+                0.0103, -0.5869, 0.0046,
+                -0.0897, -0.4940, 0.3287,
+                0.7119, -0.0154, -0.0918,
+                -0.0533, 0.0596, -0.5411,
+                0.0352, -0.0631, 0.5460,
+                -0.4776, 0.2847, -0.0271
+            ];
             var samplesFactor = 1.0 / numSamples;
 
             this._ssaoPostProcess = new PostProcess("ssao", "ssao",
                                                     [
                                                         "sampleSphere", "samplesFactor", "randTextureTiles", "totalStrength", "radius",
-                                                        "base", "range", "viewport", "projection", "near", "far",
-                                                        "xViewport", "yViewport"
+                                                        "area", "fallOff", "base", "range", "viewport"
                                                     ],
-                                                    ["randomSampler", "normalSampler"],
+                                                    ["randomSampler"],
                                                     ratio, null, Texture.BILINEAR_SAMPLINGMODE,
                                                     this._scene.getEngine(), false,
                                                     "#define SAMPLES " + numSamples + "\n#define SSAO");
@@ -262,15 +232,11 @@
 
                 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("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());
 
                 effect.setTexture("textureSampler", this._depthTexture);
-                effect.setTexture("normalSampler", this._normalTexture);
                 effect.setTexture("randomSampler", this._randomTexture);
             };
         }
@@ -302,15 +268,9 @@
 
             for (var x = 0; x < size; x++) {
                 for (var y = 0; y < size; y++) {
-                    randVector.x = rand(0.0, 1.0);
-                    randVector.y = rand(0.0, 1.0);
-                    randVector.z = 0.0;
-
-                    randVector.normalize();
-
-                    randVector.scaleInPlace(255);
-                    randVector.x = Math.floor(randVector.x);
-                    randVector.y = Math.floor(randVector.y);
+                    randVector.x = Math.floor(rand(-1.0, 1.0) * 255);
+                    randVector.y = Math.floor(rand(-1.0, 1.0) * 255);
+                    randVector.z = Math.floor(rand(-1.0, 1.0) * 255);
 
                     context.fillStyle = 'rgb(' + randVector.x + ', ' + randVector.y + ', ' + randVector.z + ')';
                     context.fillRect(x, y, 1, 1);

+ 0 - 167
src/Shaders/alternativessao.fragment.fx

@@ -1,167 +0,0 @@
-/*
-SSAO GLSL shader v1.2
-assembled by Martins Upitis (martinsh) (devlog-martinsh.blogspot.com)
-original technique is made by Arkano22 (www.gamedev.net/topic/550699-ssao-no-halo-artifacts/)
-
-changelog:
-1.2 - added fog calculation to mask AO. Minor fixes.
-1.1 - added spiral sampling method from here:
-(http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere)
-*/
-uniform sampler2D textureSampler;
-uniform float width;
-uniform float height;
-
-#define PI    3.14159265
-varying vec2 vUV;
-
-//------------------------------------------
-//general stuff
-
-//make sure that these two values are the same for your camera, otherwise distances will be wrong.
-
-float znear = 0.3; //Z-near
-float zfar = 100.0; //Z-far
-
-//user variables
-int samples = 1; //ao sample count
-
-float radius = 2.5; //ao radius
-float aoclamp = 0.25; //depth clamp - reduces haloing at screen edges
-bool noise = true; //use noise instead of pattern for sample dithering
-float noiseamount = 0.0002; //dithering amount
-
-float diffarea = 0.25; //self-shadowing reduction
-float gdisplace = 0.4; //gauss bell center
-
-bool mist = false; //use mist?
-float miststart = 0.0; //mist start
-float mistend = 16.0; //mist end
-
-bool onlyAO = true; //use only ambient occlusion pass?
-float lumInfluence = 0.7; //how much luminance affects occlusion
-
-//--------------------------------------------------------
-
-vec2 rand(vec2 coord) //generating noise/pattern texture for dithering
-{
-	float noiseX = ((fract(1.0-coord.s*(width/2.0))*0.25)+(fract(coord.t*(height/2.0))*0.75))*2.0-1.0;
-	float noiseY = ((fract(1.0-coord.s*(width/2.0))*0.75)+(fract(coord.t*(height/2.0))*0.25))*2.0-1.0;
-	
-	if (noise)
-	{
-		noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0;
-		noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0;
-	}
-	return vec2(noiseX,noiseY)*noiseamount;
-}
-
-float doMist()
-{
-	float zdepth = texture2D(textureSampler,vUV.xy).x;
-	float depth = -zfar * znear / (zdepth * (zfar - znear) - zfar);
-	return clamp((depth-miststart)/mistend,0.0,1.0);
-}
-
-float readDepth(in vec2 coord) 
-{
-	if (vUV.x<0.0||vUV.y<0.0) return 1.0;
-	return (2.0 * znear) / (zfar + znear - texture2D(textureSampler, coord ).x * (zfar-znear));
-}
-
-float compareDepths(in float depth1, in float depth2,inout int far)
-{   
-	float garea = 2.0; //gauss bell width    
-	float diff = (depth1 - depth2)*100.0; //depth difference (0-100)
-	//reduce left bell width to avoid self-shadowing 
-	if (diff<gdisplace)
-	{
-	garea = diffarea;
-	}else{
-	far = 1;
-	}
-	
-	float gauss = pow(2.7182,-2.0*(diff-gdisplace)*(diff-gdisplace)/(garea*garea));
-	return gauss;
-}   
-
-float calAO(float depth,float dw, float dh)
-{   
-	float dd = (1.0-depth)*radius;
-	
-	float temp = 0.0;
-	float temp2 = 0.0;
-	float coordw = vUV.x + dw*dd;
-	float coordh = vUV.y + dh*dd;
-	float coordw2 = vUV.x - dw*dd;
-	float coordh2 = vUV.y - dh*dd;
-	
-	vec2 coord = vec2(coordw , coordh);
-	vec2 coord2 = vec2(coordw2, coordh2);
-	
-	int far = 0;
-	temp = compareDepths(depth, readDepth(coord),far);
-	//DEPTH EXTRAPOLATION:
-	if (far > 0)
-	{
-		temp2 = compareDepths(readDepth(coord2),depth,far);
-		temp += (1.0-temp)*temp2;
-	}
-	
-	return temp;
-} 
-
-void main(void)
-{
-	vec2 noise = rand(vUV); 
-	float depth = readDepth(vUV);
-	
-	float w = (1.0 / width)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x));
-	float h = (1.0 / height)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y));
-	
-	float pw;
-	float ph;
-	
-	float ao;
-	
-	float dl = PI*(3.0-sqrt(5.0));
-	float dz = 1.0/float(samples);
-	float l = 0.0;
-	float z = 1.0 - dz/2.0;
-	
-	for (int i = 0; i <= samples; i ++)
-	{     
-		float r = sqrt(1.0-z);
-		
-		pw = cos(l)*r;
-		ph = sin(l)*r;
-		ao += calAO(depth,pw*w,ph*h);        
-		z = z - dz;
-		l = l + dl;
-	}
-	
-	ao /= float(samples);
-	ao = 1.0-ao;	
-	
-	if (mist)
-	{
-	ao = mix(ao, 1.0,doMist());
-	}
-	
-	vec3 color = vec3(0.5, 0.5, 0.5);
-	
-	vec3 lumcoeff = vec3(0.299,0.587,0.114);
-	float lum = dot(color.rgb, lumcoeff);
-	vec3 luminance = vec3(lum, lum, lum);
-	
-	vec3 final = vec3(color*mix(vec3(ao),vec3(1.0),luminance*lumInfluence));//mix(color*ao, white, luminance)
-	
-	if (onlyAO)
-	{
-	final = vec3(mix(vec3(ao),vec3(1.0),luminance*lumInfluence)); //ambient occlusion only
-	}
-	
-	
-	gl_FragColor = vec4(final,1.0); 
-	
-}

+ 42 - 58
src/Shaders/ssao.fragment.fx

@@ -1,85 +1,70 @@
-// SSAO Shader
-precision highp float;
+// SSAO Shader
 uniform sampler2D textureSampler;
-uniform float near;
-uniform float far;
-uniform float radius;
 
 varying vec2 vUV;
 
-float perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {
-	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 );
-}
-
 #ifdef SSAO
 uniform sampler2D randomSampler;
-uniform sampler2D normalSampler;
 
 uniform float randTextureTiles;
 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 = texture2D(randomSampler, vUV * randTextureTiles).rgb;
+	vec3 random = normalize(texture2D(randomSampler, vUV * randTextureTiles).rgb);
 	float depth = texture2D(textureSampler, vUV).r;
-	float linearDepth = - perspectiveDepthToViewZ(depth, near, far);
-	vec3 normal = texture2D(normalSampler, vUV).rgb; 
+	vec3 position = vec3(vUV, depth);
+	vec3 normal = normalFromDepth(depth, vUV);
+	float radiusDepth = radius / depth;
 	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) {
-		// get sample position:
-	   vec3 samplePosition = tbn * sampleSphere[i];
-	   samplePosition = samplePosition * radius + origin;
-	  
-		// project sample position:
-	   vec4 offset = vec4(samplePosition, 1.0);
-	   offset = projection * offset;
-	   offset.xyz /= offset.w;
-	   offset.xy = offset.xy * 0.5 + 0.5;
-	  
-		// get sample linearDepth:
-	   float sampleDepth = texture(textureSampler, offset.xy).r;
-	   float linearSampleDepth = - perspectiveDepthToViewZ(texture(textureSampler, offset.xy).r, near, far);
-		// range check & accumulate:
-	   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.0 ? 1.0 : 0.0) * rangeCheck;
-
-	}
+	for (int i = 0; i < SAMPLES; i++)
+	{
+		ray = radiusDepth * 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 = depth - occlusionDepth;
 
-	// 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);
+		occlusion += step(fallOff, difference) * (1.0 - smoothstep(fallOff, area, difference));
+	}
 
 	float ao = 1.0 - totalStrength * occlusion * samplesFactor;
 	float result = clamp(ao + base, 0.0, 1.0);
-	gl_FragColor = vec4(result, result, result, 1.0);
+
+	gl_FragColor.r = result;
+	gl_FragColor.g = result;
+	gl_FragColor.b = result;
+	gl_FragColor.a = 1.0;
 }
 #endif
 
@@ -90,9 +75,9 @@ uniform float samplerOffsets[SAMPLES];
 
 void main()
 {
+
 	float texelsize = 1.0 / outSize;
 	float compareDepth = texture2D(depthSampler, vUV).r;
-	float linearDepth = - perspectiveDepthToViewZ(compareDepth, near, far);
 	float result = 0.0;
 	float weightSum = 0.0;
 
@@ -106,8 +91,7 @@ void main()
 		vec2 samplePos = vUV + sampleOffset;
 
 		float sampleDepth = texture2D(depthSampler, samplePos).r;
-		float linearSampleDepth = - perspectiveDepthToViewZ(sampleDepth, near, far);
-		float weight = abs(linearDepth - linearSampleDepth) < radius ? 1.0 : 0.0;
+		float weight = (1.0 / (0.0001 + abs(compareDepth - sampleDepth)));
 
 		result += texture2D(textureSampler, samplePos).r * weight;
 		weightSum += weight;