فهرست منبع

Merge pull request #4028 from TrevorDev/dofKernelFix

Dof kernel fix
sebavan 7 سال پیش
والد
کامیت
493b6d9767

+ 1 - 1
dist/preview release/what's new.md

@@ -13,7 +13,7 @@
 - Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos. Demo [here](https://www.babylonjs-playground.com/frame.html#1E9JQ8#7) ([DavidHGillen](https://github.com/DavidHGillen))
 - Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials. Demo [here](http://www.babylonjs.com/demos/GlowLayer/) ([sebavan](https://github.com/sebavan))
 - New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) class and loading methods ([trevordev](https://github.com/trevordev))
-- Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#9), [sharpening, MSAA, chromatic aberration and grain effect](https://www.babylonjs-playground.com/#Y3C0HQ#146) to the default pipeline ([trevordev](https://github.com/trevordev))
+- Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#9), [MSAA, sharpening, chromatic aberration and grain effect](https://www.babylonjs-playground.com/#Y3C0HQ#146) to the default pipeline ([trevordev](https://github.com/trevordev))
 - Added support for [animation weights](http://doc.babylonjs.com/babylon101/animations#animation-weights). Demo [here](https://www.babylonjs-playground.com/#IQN716#9) ([deltakosh](https://github.com/deltakosh))
 - Added [sub emitters for particle system](http://doc.babylonjs.com/babylon101/particles#sub-emitters) which will spawn new particle systems when particles dies. Demo [here](https://www.babylonjs-playground.com/frame.html#9NHBCC#1) ([IbraheemOsama](https://github.com/IbraheemOsama))
 - New [Babylon.js](http://doc.babylonjs.com/resources/maya) and [glTF](http://doc.babylonjs.com/resources/maya_to_gltf) exporter for Autodesk Maya ([Noalak](https://github.com/Noalak))

+ 189 - 178
src/PostProcess/babylon.blurPostProcess.ts

@@ -1,80 +1,84 @@
 module BABYLON {
-	/**
-	 * The Blur Post Process which blurs an image based on a kernel and direction. 
-	 * Can be used twice in x and y directions to perform a guassian blur in two passes.
+    /**
+     * The Blur Post Process which blurs an image based on a kernel and direction. 
+     * Can be used twice in x and y directions to perform a guassian blur in two passes.
      */
     export class BlurPostProcess extends PostProcess {
-		protected _kernel: number;
-		protected _idealKernel: number;
-		protected _packedFloat: boolean	= false;
-		private _staticDefines:string = ""
-		/**
-		 * Sets the length in pixels of the blur sample region
-		 */
-		public set kernel(v: number) {
-			if (this._idealKernel === v) {
-				return;
-			}
-
-			v = Math.max(v, 1);
-			this._idealKernel = v;
-			this._kernel = this._nearestBestKernel(v);
-			if(!this.blockCompilation){
-				this._updateParameters();
-			}
-		}
-
-		/**
-		 * Gets the length in pixels of the blur sample region
-		 */
-		public get kernel(): number {
-			return this._idealKernel;
-		}
-
-		/**
-		 * Sets wether or not the blur needs to unpack/repack floats
-		 */
-		public set packedFloat(v: boolean) {
-			if (this._packedFloat === v) {
-				return;
-			}
-			this._packedFloat = v;
+        protected _kernel: number;
+        protected _idealKernel: number;
+        protected _packedFloat: boolean	= false;
+        private _staticDefines:string = ""
+        /**
+         * Sets the length in pixels of the blur sample region
+         */
+        public set kernel(v: number) {
+            if (this._idealKernel === v) {
+                return;
+            }
+
+            v = Math.max(v, 1);
+            this._idealKernel = v;
+            this._kernel = this._nearestBestKernel(v);
+            if(!this.blockCompilation){
+                this._updateParameters();
+            }
+        }
+
+        /**
+         * Gets the length in pixels of the blur sample region
+         */
+        public get kernel(): number {
+            return this._idealKernel;
+        }
+
+        /**
+         * Sets wether or not the blur needs to unpack/repack floats
+         */
+        public set packedFloat(v: boolean) {
+            if (this._packedFloat === v) {
+                return;
+            }
+            this._packedFloat = v;
             if(!this.blockCompilation){
-				this._updateParameters();
-			}
-		}
-
-		/**
-		 * Gets wether or not the blur is unpacking/repacking floats
-		 */
-		public get packedFloat(): boolean {
-			return this._packedFloat;
-		}
-
-		/**
+                this._updateParameters();
+            }
+        }
+
+        /**
+         * Gets wether or not the blur is unpacking/repacking floats
+         */
+        public get packedFloat(): boolean {
+            return this._packedFloat;
+        }
+
+        /**
          * Creates a new instance BlurPostProcess
          * @param name The name of the effect.
          * @param direction The direction in which to blur the image.
-		 * @param kernel The size of the kernel to be used when computing the blur. eg. Size of 3 will blur the center pixel by 2 pixels surrounding it.
+         * @param kernel The size of the kernel to be used when computing the blur. eg. Size of 3 will blur the center pixel by 2 pixels surrounding it.
          * @param options The required width/height ratio to downsize to before computing the render pass. (Use 1.0 for full size)
          * @param camera The camera to apply the render pass to.
          * @param samplingMode The sampling mode to be used when computing the pass. (default: 0)
          * @param engine The engine which the post process will be applied. (default: current engine)
          * @param reusable If the post process can be reused on the same frame. (default: false)
          * @param textureType Type of textures used when performing the post process. (default: 0)
-		 * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
         constructor(name: string, /** The direction in which to blur the image. */ public direction: Vector2, kernel: number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, defines = "", private blockCompilation = false) {
-			super(name, "kernelBlur", ["delta", "direction", "cameraMinMaxZ"], ["circleOfConfusionSampler"], options, camera, samplingMode, engine, reusable, null, textureType, "kernelBlur", {varyingCount: 0, depCount: 0}, true);
-			this._staticDefines = defines;
-			this.onApplyObservable.add((effect: Effect) => {
-				effect.setFloat2('delta', (1 / this.width) * this.direction.x, (1 / this.height) * this.direction.y);
-			});
+            super(name, "kernelBlur", ["delta", "direction", "cameraMinMaxZ"], ["circleOfConfusionSampler"], options, camera, samplingMode, engine, reusable, null, textureType, "kernelBlur", {varyingCount: 0, depCount: 0}, true);
+            this._staticDefines = defines;
+            this.onApplyObservable.add((effect: Effect) => {
+                if(this._outputTexture){
+                    effect.setFloat2('delta', (1 / this._outputTexture.width) * this.direction.x, (1 / this._outputTexture.height) * this.direction.y);
+                }else{
+                    effect.setFloat2('delta', (1 / this.width) * this.direction.x, (1 / this.height) * this.direction.y);
+                }
+            });
 
             this.kernel = kernel;
         }
 
-		/**
+        /**
          * Updates the effect with the current post process compile time values and recompiles the shader.
          * @param defines Define statements that should be added at the beginning of the shader. (default: null)
          * @param uniforms Set of uniform variables that will be passed to the shader. (default: null)
@@ -90,144 +94,151 @@
 
         protected _updateParameters(onCompiled?: (effect: Effect) => void, onError?: (effect: Effect, errors: string) => void): void {
             // Generate sampling offsets and weights
-			let N = this._kernel;
-			let centerIndex = (N - 1) / 2;
-
-			// Generate Gaussian sampling weights over kernel
-			let offsets = [];
-			let weights = [];
-			let totalWeight = 0;
-			for (let i = 0; i < N; i++) {
-				let u = i / (N - 1);
-				let w = this._gaussianWeight(u * 2.0 - 1);
-				offsets[i] = (i - centerIndex);
-				weights[i] = w;
-				totalWeight += w;
-			}
-
-			// Normalize weights
-			for (let i = 0; i < weights.length; i++) {
-				weights[i] /= totalWeight;
-			}
-
-			// Optimize: combine samples to take advantage of hardware linear sampling
-			// Walk from left to center, combining pairs (symmetrically)
-			let linearSamplingWeights = [];
-			let linearSamplingOffsets = [];
-
-			let linearSamplingMap = [];
-
-			for (let i = 0; i <= centerIndex; i += 2) {
-				let j = Math.min(i + 1, Math.floor(centerIndex));
-
-				let singleCenterSample = i === j;
-
-				if (singleCenterSample) {
-					linearSamplingMap.push({ o: offsets[i], w: weights[i] });
-				} else {
-					let sharedCell = j === centerIndex;
-
-					let weightLinear = (weights[i] + weights[j] * (sharedCell ? .5 : 1.));
-					let offsetLinear = offsets[i] + 1 / (1 + weights[i] / weights[j]);
-
-					if (offsetLinear === 0) {
-						linearSamplingMap.push({ o: offsets[i], w: weights[i] });
-						linearSamplingMap.push({ o: offsets[i + 1], w: weights[i + 1] });
-					} else {
-						linearSamplingMap.push({ o: offsetLinear, w: weightLinear });
-						linearSamplingMap.push({ o: -offsetLinear, w: weightLinear });
-					}
-
-				}
-			}
-
-			for (let i = 0; i < linearSamplingMap.length; i++) {
-				linearSamplingOffsets[i] = linearSamplingMap[i].o;
-				linearSamplingWeights[i] = linearSamplingMap[i].w;
-			}
-
-			// Replace with optimized
-			offsets = linearSamplingOffsets;
-			weights = linearSamplingWeights;
-
-			// Generate shaders
-			let maxVaryingRows = this.getEngine().getCaps().maxVaryingVectors;
-			let freeVaryingVec2 = Math.max(maxVaryingRows, 0.) - 1; // Because of sampleCenter
+            let N = this._kernel;
+            let centerIndex = (N - 1) / 2;
+
+            // Generate Gaussian sampling weights over kernel
+            let offsets = [];
+            let weights = [];
+            let totalWeight = 0;
+            for (let i = 0; i < N; i++) {
+                let u = i / (N - 1);
+                let w = this._gaussianWeight(u * 2.0 - 1);
+                offsets[i] = (i - centerIndex);
+                weights[i] = w;
+                totalWeight += w;
+            }
+
+            // Normalize weights
+            for (let i = 0; i < weights.length; i++) {
+                weights[i] /= totalWeight;
+            }
+
+            // Optimize: combine samples to take advantage of hardware linear sampling
+            // Walk from left to center, combining pairs (symmetrically)
+            let linearSamplingWeights = [];
+            let linearSamplingOffsets = [];
+
+            let linearSamplingMap = [];
+
+            for (let i = 0; i <= centerIndex; i += 2) {
+                let j = Math.min(i + 1, Math.floor(centerIndex));
+
+                let singleCenterSample = i === j;
+
+                if (singleCenterSample) {
+                    linearSamplingMap.push({ o: offsets[i], w: weights[i] });
+                } else {
+                    let sharedCell = j === centerIndex;
+
+                    let weightLinear = (weights[i] + weights[j] * (sharedCell ? .5 : 1.));
+                    let offsetLinear = offsets[i] + 1 / (1 + weights[i] / weights[j]);
+
+                    if (offsetLinear === 0) {
+                        linearSamplingMap.push({ o: offsets[i], w: weights[i] });
+                        linearSamplingMap.push({ o: offsets[i + 1], w: weights[i + 1] });
+                    } else {
+                        linearSamplingMap.push({ o: offsetLinear, w: weightLinear });
+                        linearSamplingMap.push({ o: -offsetLinear, w: weightLinear });
+                    }
+
+                }
+            }
+
+            for (let i = 0; i < linearSamplingMap.length; i++) {
+                linearSamplingOffsets[i] = linearSamplingMap[i].o;
+                linearSamplingWeights[i] = linearSamplingMap[i].w;
+            }
+
+            // Replace with optimized
+            offsets = linearSamplingOffsets;
+            weights = linearSamplingWeights;
+
+            // Generate shaders
+            let maxVaryingRows = this.getEngine().getCaps().maxVaryingVectors;
+            let freeVaryingVec2 = Math.max(maxVaryingRows, 0.) - 1; // Because of sampleCenter
 
             let varyingCount = Math.min(offsets.length, freeVaryingVec2);
-        
-			let defines = "";
-			defines+=this._staticDefines;
+
+            let defines = "";
+            defines+=this._staticDefines;
+
+            // The DOF fragment should ignore the center pixel when looping as it is handled manualy in the fragment shader.
+            if(this._staticDefines.indexOf("DOF") != -1){
+                defines += `#define CENTER_WEIGHT ${this._glslFloat(weights[varyingCount-1])}\r\n`;
+                varyingCount--;
+            }
+            
             for (let i = 0; i < varyingCount; i++) {
                 defines += `#define KERNEL_OFFSET${i} ${this._glslFloat(offsets[i])}\r\n`;
                 defines += `#define KERNEL_WEIGHT${i} ${this._glslFloat(weights[i])}\r\n`;
-			}
+            }
 
             let depCount = 0;
             for (let i = freeVaryingVec2; i < offsets.length; i++) {
                 defines += `#define KERNEL_DEP_OFFSET${depCount} ${this._glslFloat(offsets[i])}\r\n`;
                 defines += `#define KERNEL_DEP_WEIGHT${depCount} ${this._glslFloat(weights[i])}\r\n`;
                 depCount++;
-			}
+            }
 
-			if (this.packedFloat) {
-				defines += `#define PACKEDFLOAT 1`;
-			}
+            if (this.packedFloat) {
+                defines += `#define PACKEDFLOAT 1`;
+            }
 
-			this.blockCompilation = false;
+            this.blockCompilation = false;
             super.updateEffect(defines, null, null, {
-				varyingCount: varyingCount,
-				depCount: depCount
-			}, onCompiled, onError);
+                varyingCount: varyingCount,
+                depCount: depCount
+            }, onCompiled, onError);
         }
 
         /**
-		 * Best kernels are odd numbers that when divided by 2, their integer part is even, so 5, 9 or 13.
-		 * Other odd kernels optimize correctly but require proportionally more samples, even kernels are
-		 * possible but will produce minor visual artifacts. Since each new kernel requires a new shader we
-		 * want to minimize kernel changes, having gaps between physical kernels is helpful in that regard.
-		 * The gaps between physical kernels are compensated for in the weighting of the samples
-		 * @param idealKernel Ideal blur kernel.
-		 * @return Nearest best kernel.
-		 */
-		protected _nearestBestKernel(idealKernel: number): number {
-			let v = Math.round(idealKernel);
-			for (let k of [v, v - 1, v + 1, v - 2, v + 2]) {
-				if (((k % 2) !== 0) && ((Math.floor(k / 2) % 2) === 0) && k > 0) {
-					return Math.max(k, 3);
-				}
-			}
-			return Math.max(v, 3);
-		}
-
-		/**
-		 * Calculates the value of a Gaussian distribution with sigma 3 at a given point.
-		 * @param x The point on the Gaussian distribution to sample.
-		 * @return the value of the Gaussian function at x.
-		 */
-		protected _gaussianWeight(x: number): number {
-			//reference: Engine/ImageProcessingBlur.cpp #dcc760
-			// We are evaluating the Gaussian (normal) distribution over a kernel parameter space of [-1,1],
-			// so we truncate at three standard deviations by setting stddev (sigma) to 1/3.
-			// The choice of 3-sigma truncation is common but arbitrary, and means that the signal is
-			// truncated at around 1.3% of peak strength.
-
-			//the distribution is scaled to account for the difference between the actual kernel size and the requested kernel size
-			let sigma = (1 / 3);
-			let denominator = Math.sqrt(2.0 * Math.PI) * sigma;
-			let exponent = -((x * x) / (2.0 * sigma * sigma));
-			let weight = (1.0 / denominator) * Math.exp(exponent);
-			return weight;
-		}      
+         * Best kernels are odd numbers that when divided by 2, their integer part is even, so 5, 9 or 13.
+         * Other odd kernels optimize correctly but require proportionally more samples, even kernels are
+         * possible but will produce minor visual artifacts. Since each new kernel requires a new shader we
+         * want to minimize kernel changes, having gaps between physical kernels is helpful in that regard.
+         * The gaps between physical kernels are compensated for in the weighting of the samples
+         * @param idealKernel Ideal blur kernel.
+         * @return Nearest best kernel.
+         */
+        protected _nearestBestKernel(idealKernel: number): number {
+            let v = Math.round(idealKernel);
+            for (let k of [v, v - 1, v + 1, v - 2, v + 2]) {
+                if (((k % 2) !== 0) && ((Math.floor(k / 2) % 2) === 0) && k > 0) {
+                    return Math.max(k, 3);
+                }
+            }
+            return Math.max(v, 3);
+        }
+
+        /**
+         * Calculates the value of a Gaussian distribution with sigma 3 at a given point.
+         * @param x The point on the Gaussian distribution to sample.
+         * @return the value of the Gaussian function at x.
+         */
+        protected _gaussianWeight(x: number): number {
+            //reference: Engine/ImageProcessingBlur.cpp #dcc760
+            // We are evaluating the Gaussian (normal) distribution over a kernel parameter space of [-1,1],
+            // so we truncate at three standard deviations by setting stddev (sigma) to 1/3.
+            // The choice of 3-sigma truncation is common but arbitrary, and means that the signal is
+            // truncated at around 1.3% of peak strength.
+
+            //the distribution is scaled to account for the difference between the actual kernel size and the requested kernel size
+            let sigma = (1 / 3);
+            let denominator = Math.sqrt(2.0 * Math.PI) * sigma;
+            let exponent = -((x * x) / (2.0 * sigma * sigma));
+            let weight = (1.0 / denominator) * Math.exp(exponent);
+            return weight;
+        }      
 
        /**
-		 * Generates a string that can be used as a floating point number in GLSL.
-		 * @param x Value to print.
-		 * @param decimalFigures Number of decimal places to print the number to (excluding trailing 0s).
-		 * @return GLSL float string.
-		 */
-		protected _glslFloat(x: number, decimalFigures = 8) {
-			return x.toFixed(decimalFigures).replace(/0+$/, '');
-		}      
+         * Generates a string that can be used as a floating point number in GLSL.
+         * @param x Value to print.
+         * @param decimalFigures Number of decimal places to print the number to (excluding trailing 0s).
+         * @return GLSL float string.
+         */
+        protected _glslFloat(x: number, decimalFigures = 8) {
+            return x.toFixed(decimalFigures).replace(/0+$/, '');
+        }      
     }
 } 

+ 5 - 3
src/PostProcess/babylon.depthOfFieldEffect.ts

@@ -109,10 +109,12 @@ module BABYLON {
                 }
             }
             var adjustedKernelSize = kernelSize/Math.pow(2, blurCount-1);
+            var ratio = 1.0;
             for(var i = 0;i<blurCount;i++){
-                var blurY = new DepthOfFieldBlurPostProcess("verticle blur", scene, new Vector2(0, 1.0), adjustedKernelSize, 1.0/Math.pow(2, i), null, this._circleOfConfusion, i == 0 ? this._circleOfConfusion : null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
+                var blurY = new DepthOfFieldBlurPostProcess("verticle blur", scene, new Vector2(0, 1.0), adjustedKernelSize, ratio, null, this._circleOfConfusion, i == 0 ? this._circleOfConfusion : null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
                 blurY.autoClear = false;
-                var blurX = new DepthOfFieldBlurPostProcess("horizontal blur", scene, new Vector2(1.0, 0), adjustedKernelSize, 1.0/Math.pow(2, i), null,  this._circleOfConfusion, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
+                ratio = 0.75/Math.pow(2, i);
+                var blurX = new DepthOfFieldBlurPostProcess("horizontal blur", scene, new Vector2(1.0, 0), adjustedKernelSize, ratio, null,  this._circleOfConfusion, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
                 blurX.autoClear = false;
                 this._depthOfFieldBlurY.push(blurY);
                 this._depthOfFieldBlurX.push(blurX);
@@ -126,7 +128,7 @@ module BABYLON {
             }
 
             // Merge blurred images with original image based on circleOfConfusion
-            this._dofMerge = new DepthOfFieldMergePostProcess("dofMerge", this._circleOfConfusion, this._circleOfConfusion, this._depthOfFieldBlurX, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
+            this._dofMerge = new DepthOfFieldMergePostProcess("dofMerge", this._circleOfConfusion, this._circleOfConfusion, this._depthOfFieldBlurX, ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
             this._dofMerge.autoClear = false;
             this._effects.push(this._dofMerge);
         }

+ 2 - 2
src/PostProcess/babylon.depthOfFieldMergePostProcess.ts

@@ -42,13 +42,13 @@ module BABYLON {
          * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
         constructor(name: string, originalFromInput:PostProcess, circleOfConfusion:PostProcess, private blurSteps:Array<PostProcess>, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
-            super(name, "depthOfFieldMerge", ["bloomWeight"], ["circleOfConfusionSampler", "blurStep0", "blurStep1", "blurStep2", "bloomBlur"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, true);
+            super(name, "depthOfFieldMerge", [], ["circleOfConfusionSampler", "blurStep0", "blurStep1", "blurStep2"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, true);
             this.onApplyObservable.add((effect: Effect) => {
                 effect.setTextureFromPostProcess("textureSampler", originalFromInput);
                 effect.setTextureFromPostProcessOutput("circleOfConfusionSampler", circleOfConfusion);
                 blurSteps.forEach((step,index)=>{
                     effect.setTextureFromPostProcessOutput("blurStep"+(blurSteps.length-index-1), step);
-                });    
+                });  
             });
 
             if(!blockCompilation){

+ 2 - 0
src/PostProcess/babylon.postProcessManager.ts

@@ -154,8 +154,10 @@
                 } else {
                     if (targetTexture) {
                         engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, forceFullscreenViewport);
+                        pp._outputTexture = targetTexture;
                     } else {
                         engine.restoreDefaultFramebuffer();
+                        pp._outputTexture = null;
                     }
                 }
 

+ 1 - 2
src/Shaders/ShadersInclude/kernelBlurFragment.fx

@@ -1,6 +1,5 @@
 #ifdef DOF
-    sampleDepth = sampleDistance(sampleCoord{X});
-    factor = clamp(1.0-((centerSampleDepth - sampleDepth)/centerSampleDepth),0.0,1.0);
+    factor = sampleCoC(sampleCoord{X});    
     computedWeight = KERNEL_WEIGHT{X} * factor;
     sumOfWeights += computedWeight;
 #else

+ 1 - 2
src/Shaders/ShadersInclude/kernelBlurFragment2.fx

@@ -1,6 +1,5 @@
 #ifdef DOF
-    sampleDepth = sampleDistance(sampleCoord{X});
-    factor = clamp(1.0-((centerSampleDepth - sampleDepth)/centerSampleDepth),0.0,1.0);
+    factor = sampleCoC(sampleCenter + delta * KERNEL_DEP_OFFSET{X});
     computedWeight = KERNEL_DEP_WEIGHT{X} * factor;
     sumOfWeights += computedWeight;
 #else

+ 3 - 7
src/Shaders/circleOfConfusion.fragment.fx

@@ -11,15 +11,11 @@ uniform vec2 cameraMinMaxZ;
 uniform float focusDistance;
 uniform float cocPrecalculation;
 
-float sampleDistance(const in vec2 offset) {
-    float depth = texture2D(depthSampler, offset).r;	// depth value from DepthRenderer: 0 to 1
-	return (cameraMinMaxZ.x + (cameraMinMaxZ.y - cameraMinMaxZ.x)*depth)*1000.0;		            // actual distance from the lens in scene units/1000 (eg. millimeter)
-}
-
 void main(void)
 {
-    float pixelDistance = sampleDistance(vUV);
+    float depth = texture2D(depthSampler, vUV).r;
+    float pixelDistance = (cameraMinMaxZ.x + (cameraMinMaxZ.y - cameraMinMaxZ.x)*depth)*1000.0;	// actual distance from the lens in scene units/1000 (eg. millimeter)
     float coc = abs(cocPrecalculation* ((focusDistance - pixelDistance)/pixelDistance));
     coc = clamp(coc, 0.0, 1.0);
-    gl_FragColor = vec4(coc, texture2D(depthSampler, vUV).r, coc, 1.0);
+    gl_FragColor = vec4(coc, depth, coc, 1.0);
 }

+ 11 - 8
src/Shaders/depthOfFieldMerge.fragment.fx

@@ -13,32 +13,35 @@ uniform sampler2D blurStep2;
 
 void main(void)
 {
-    gl_FragColor = texture2D(textureSampler, vUV);
-
     float coc = texture2D(circleOfConfusionSampler, vUV).r;
-    vec4 original = texture2D(textureSampler, vUV);
 #if BLUR_LEVEL == 0
+    vec4 original = texture2D(textureSampler, vUV);
     vec4 blurred0 = texture2D(blurStep0, vUV);
     gl_FragColor = mix(original, blurred0, coc);
 #endif
 #if BLUR_LEVEL == 1
-    vec4 blurred0 = texture2D(blurStep0, vUV);   
-    vec4 blurred1 = texture2D(blurStep1, vUV);
     if(coc < 0.5){
+        vec4 original = texture2D(textureSampler, vUV);
+        vec4 blurred1 = texture2D(blurStep1, vUV);
         gl_FragColor = mix(original, blurred1, coc/0.5);
     }else{
+        vec4 blurred0 = texture2D(blurStep0, vUV);   
+        vec4 blurred1 = texture2D(blurStep1, vUV);
         gl_FragColor = mix(blurred1, blurred0, (coc-0.5)/0.5);
     }
 #endif
 #if BLUR_LEVEL == 2
-    vec4 blurred0 = texture2D(blurStep0, vUV);
-    vec4 blurred1 = texture2D(blurStep1, vUV);
-    vec4 blurred2 = texture2D(blurStep2, vUV);
     if(coc < 0.33){
+        vec4 original = texture2D(textureSampler, vUV);
+        vec4 blurred2 = texture2D(blurStep2, vUV);
         gl_FragColor = mix(original, blurred2, coc/0.33);
     }else if(coc < 0.66){
+        vec4 blurred1 = texture2D(blurStep1, vUV);
+        vec4 blurred2 = texture2D(blurStep2, vUV);
         gl_FragColor = mix(blurred2, blurred1, (coc-0.33)/0.33);
     }else{
+        vec4 blurred0 = texture2D(blurStep0, vUV);
+        vec4 blurred1 = texture2D(blurStep1, vUV);
         gl_FragColor = mix(blurred1, blurred0, (coc-0.66)/0.34);
     }
 #endif

+ 58 - 53
src/Shaders/kernelBlur.fragment.fx

@@ -6,68 +6,73 @@ uniform vec2 delta;
 varying vec2 sampleCenter;
 
 #ifdef DOF
-	uniform sampler2D circleOfConfusionSampler;
+    uniform sampler2D circleOfConfusionSampler;
 
-	uniform vec2 cameraMinMaxZ;
+    uniform vec2 cameraMinMaxZ;
 
-	float sampleDistance(const in vec2 offset) {
-		float depth = texture2D(circleOfConfusionSampler, offset).g; // depth value from DepthRenderer: 0 to 1 
-		return cameraMinMaxZ.x + (cameraMinMaxZ.y - cameraMinMaxZ.x)*depth; // actual distance from the lens 
-	}
+    float sampleDistance(const in vec2 offset) {
+        float depth = texture2D(circleOfConfusionSampler, offset).g; // depth value from DepthRenderer: 0 to 1 
+        return cameraMinMaxZ.x + (cameraMinMaxZ.y - cameraMinMaxZ.x)*depth; // actual distance from the lens 
+    }
+    float sampleCoC(const in vec2 offset) {
+        float coc = texture2D(circleOfConfusionSampler, offset).r; 
+        return coc; // actual distance from the lens 
+    }
 #endif
 
 #include<kernelBlurVaryingDeclaration>[0..varyingCount]
 
 #ifdef PACKEDFLOAT
-	vec4 pack(float depth)
-	{
-		const vec4 bit_shift = vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0);
-		const vec4 bit_mask = vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
-
-		vec4 res = fract(depth * bit_shift);
-		res -= res.xxyz * bit_mask;
-
-		return res;
-	}
-
-	float unpack(vec4 color)
-	{
-		const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
-		return dot(color, bit_shift);
-	}
+    vec4 pack(float depth)
+    {
+        const vec4 bit_shift = vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0);
+        const vec4 bit_mask = vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
+
+        vec4 res = fract(depth * bit_shift);
+        res -= res.xxyz * bit_mask;
+
+        return res;
+    }
+
+    float unpack(vec4 color)
+    {
+        const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
+        return dot(color, bit_shift);
+    }
 #endif
 
 void main(void)
 {
-	#ifdef DOF
-		float sumOfWeights = 0.0; // Since not all values are blended, keep track of sum to devide result by at the end to get an average
-		float sampleDepth = 0.0;
-    	float factor = 0.0;
-		float centerSampleDepth = sampleDistance(sampleCenter);
-	#endif
-
-	float computedWeight = 0.0;
-
-	#ifdef PACKEDFLOAT	
-		float blend = 0.;
-	#else
-		vec4 blend = vec4(0.);
-	#endif
-
-	#include<kernelBlurFragment>[0..varyingCount]
-	#include<kernelBlurFragment2>[0..depCount]
-
-	#ifdef PACKEDFLOAT
-		gl_FragColor = pack(blend);
-	#else
-		gl_FragColor = blend;
-	#endif
-
-	#ifdef DOF
-		// If there are no samples to blend, make pixel black.
-		if(sumOfWeights == 0.0){
-			gl_FragColor = vec4(0.0,0.0,0.0,1.0);
-		}
-		gl_FragColor /= sumOfWeights;
-	#endif
+    float computedWeight = 0.0;
+
+    #ifdef PACKEDFLOAT	
+        float blend = 0.;
+    #else
+        vec4 blend = vec4(0.);
+    #endif
+
+    #ifdef DOF
+        float sumOfWeights = CENTER_WEIGHT; // Since not all values are blended, keep track of sum to devide result by at the end to get an average (start at center weight as center pixel is added by default)
+        float factor = 0.0;
+
+        // Add center pixel to the blur by default
+        #ifdef PACKEDFLOAT
+            blend += unpack(texture2D(textureSampler, sampleCenter)) * CENTER_WEIGHT;
+        #else
+            blend += texture2D(textureSampler, sampleCenter) * CENTER_WEIGHT;
+        #endif
+    #endif
+
+    #include<kernelBlurFragment>[0..varyingCount]
+    #include<kernelBlurFragment2>[0..depCount]
+
+    #ifdef PACKEDFLOAT
+        gl_FragColor = pack(blend);
+    #else
+        gl_FragColor = blend;
+    #endif
+
+    #ifdef DOF
+        gl_FragColor /= sumOfWeights;
+    #endif
 }

BIN
tests/validation/ReferenceImages/defaultPipeline.png


BIN
tests/validation/ReferenceImages/depthOfField.png