Pārlūkot izejas kodu

filtering ok, need some code cleanup

Benjamin Guignabert 5 gadi atpakaļ
vecāks
revīzija
8c20e1045d

+ 9 - 7
src/Engines/Extensions/engine.renderTargetCube.ts

@@ -48,13 +48,19 @@ ThinEngine.prototype.createRenderTargetCubeTexture = function(size: number, opti
         Logger.Warn("Float textures are not supported. Cube render target forced to TEXTURETYPE_UNESIGNED_BYTE type");
     }
 
+    for (var face = 0; face < 6; face++) {
+        gl.texImage2D((gl.TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, this._getRGBABufferInternalSizedFormat(fullOptions.type, fullOptions.format), size, size, 0, this._getInternalFormat(fullOptions.format), this._getWebGLTextureType(fullOptions.type), null);
+    }
+
     gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, filters.mag);
     gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, filters.min);
     gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
     gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-
-    for (var face = 0; face < 6; face++) {
-        gl.texImage2D((gl.TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, this._getRGBABufferInternalSizedFormat(fullOptions.type, fullOptions.format), size, size, 0, this._getInternalFormat(fullOptions.format), this._getWebGLTextureType(fullOptions.type), null);
+    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+    
+    // MipMaps
+    if (fullOptions.generateMipMaps) {
+        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
     }
 
     // Create the framebuffer
@@ -63,10 +69,6 @@ ThinEngine.prototype.createRenderTargetCubeTexture = function(size: number, opti
 
     texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(fullOptions.generateStencilBuffer, fullOptions.generateDepthBuffer, size, size);
 
-    // MipMaps
-    if (fullOptions.generateMipMaps) {
-        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
-    }
 
     // Unbind
     this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);

+ 59 - 55
src/Materials/Textures/Filtering/hdrFiltering.ts

@@ -21,7 +21,7 @@ export class HDRFiltering {
 	private _engine: Engine;
 	private _effect: Effect;
 
-	private _numSamples: number = 128;
+	private _numSamples: number = 256;
 
 	constructor(scene: Scene) {
 		// pass
@@ -84,54 +84,68 @@ export class HDRFiltering {
 	        const a2 = alphaG * alphaG;
 	        // NdotH = samples[i].z
 	        const d = samples[i].z * samples[i].z * (a2 - 1) + 1;
-	        result.push(a2  / (Math.PI * d * d));
+	        // result.push(a2  / (Math.PI * d * d)); // TODO is it wrong in IBL baker ?
+	        result.push(a2  / (d * d));
 	    }
 
 	    return result;
 	}
 
+	/**
+	 * Get a value indicating if the post-process is ready to be used
+	 * @returns true if the post-process is ready (shader is compiled)
+	 */
+	public isReady(texture: CubeTexture | HDRCubeTexture) {
+		return (texture.isReady() && this._effect.isReady())
+	}
+
 	// Todo merge hdrCubeTexture with CubeTexture
-	public prefilter(texture: CubeTexture | HDRCubeTexture) : RenderTargetTexture | null {
-		//
-		const nbRoughnessStops = 1;
-		const samples = 1024;
-		const mipmaps: InternalTexture[] = [];
-		let filteredTexture = null;
-
-		for (let i = 0; i < nbRoughnessStops; i++) {
-			const roughness = i / nbRoughnessStops;
+	public prefilter(texture: CubeTexture | HDRCubeTexture) : Promise<RenderTargetTexture | null> {
+		return new Promise((resolve) => {
+			const callback = () => {
+				if (this.isReady(texture)) {
+					resolve(this._prefilter(texture));
+					console.log("unregister");
+					this._scene.unregisterAfterRender(callback);
+				}
+			};
+			// Is dependence of renderloop really necessary ? maybe setInterval is more suited
+			this._scene.registerAfterRender(callback);
+		})
+	}
+
+	private _prefilter(texture: CubeTexture | HDRCubeTexture) : RenderTargetTexture | null {
+		// const nbRoughnessStops = 2;
+		const maxLodLevel = Math.round(Math.log(texture.getSize().width) / Math.log(2));
+		const samples = this._numSamples;
+		console.log(this._numSamples, maxLodLevel);
+		const outputTexture = new RenderTargetTexture("temp", texture.getSize(), this._scene, true, true, undefined, true, undefined, false);
+		outputTexture.gammaSpace = false;
+
+		for (let i = 0; i < maxLodLevel + 1; i++) {
+			const roughness = i / maxLodLevel;
 			const kernel = HDRFiltering.generateSamples(samples, roughness);
 			const weights = HDRFiltering.generateWeights(kernel, roughness);
 
-			filteredTexture = this.filter(texture, kernel, weights);
-			// mipmaps.push(filteredTexture);
+			this.filter(texture, outputTexture, kernel, weights, i);
 		}
 
-		this.setMipmaps(texture, mipmaps);
-
-		return filteredTexture;
+		return outputTexture;
 	}
 
-	public filter(texture: CubeTexture | HDRCubeTexture, kernel: Vector3[], weights: number[]) : RenderTargetTexture | null {
+	public filter(texture: CubeTexture | HDRCubeTexture, outputTexture: RenderTargetTexture, kernel: Vector3[], weights: number[], lodLevel: number = 0) : RenderTargetTexture | null {
 		if (!texture.isReady()) {
 			return null;
 		}
 
-		const outputTexture = new RenderTargetTexture("temp", texture.getSize(), this._scene, false, true, undefined, true);
-
-		// Wait for readyness
-		if (!outputTexture.isReady() || !texture.isReady()) {
-			return null;
-		}
-
-
+		// Direction are flipped because of LH vs RH
 		const directions = [
-			[new Vector3(0, 1, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0)], // PositiveX
-			[new Vector3(0, 1, 0), new Vector3(0, 0, -1), new Vector3(-1, 0, 0)], // NegativeX
-			[new Vector3(-1, 0, 0), new Vector3(0, 0, 1), new Vector3(0, 1, 0)], // PositiveY
-			[new Vector3(1, 0, 0), new Vector3(0, 0, 1), new Vector3(0, -1, 0)], // NegativeY
-			[new Vector3(0, 1, 0), new Vector3(-1, 0, 0), new Vector3(0, 0, 1)], // PositiveZ
-			[new Vector3(0, 1, 0), new Vector3(1, 0, 0), new Vector3(0, 0, -1)], // NegativeZ
+			[new Vector3(0, 0, 1), new Vector3(0, 1, 0), new Vector3(-1, 0, 0)], // PositiveX
+			[new Vector3(0, 0, -1), new Vector3(0, 1, 0), new Vector3(1, 0, 0)], // NegativeX
+			[new Vector3(-1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, -1, 0)], // PositiveY
+			[new Vector3(-1, 0, 0), new Vector3(0, 0, 1), new Vector3(0, 1, 0)], // NegativeY
+			[new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, -1)], // PositiveZ
+			[new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1)], // NegativeZ
 		];
 
 		for (let i = 0; i < 6 ; i++) {
@@ -139,16 +153,12 @@ export class HDRFiltering {
 			this._effect.setVector3("up", directions[i][0]);
 			this._effect.setVector3("right", directions[i][1]);
 			this._effect.setVector3("front", directions[i][2]);
-			this.directRender(outputTexture._texture!, i);
+			this.directRender(outputTexture._texture!, i, lodLevel);
 		}
 
 		return outputTexture;
 	}
 
-	public setMipmaps(texture: CubeTexture | HDRCubeTexture, mipmaps: InternalTexture[]) {
-		// pass
-	}
-
 	public static flatten(arr: Vector3[]) : number[] {
 		const result = [];
 
@@ -180,20 +190,12 @@ export class HDRFiltering {
 	    // Parameters
 	    this._effect.setArray3("sampleDirections", HDRFiltering.flatten(kernel));
 	    this._effect.setArray("weights", weights);
-	    this._effect.setFloat("cubeSize", texture.getSize().width);
+	    this._effect.setFloat("cubeWidth", texture.getSize().width);
 	    this._effect.setFloat2("scale", 1, 1);
 	    return this._effect;
 	}
 
 	/**
-	 * Get a value indicating if the post-process is ready to be used
-	 * @returns true if the post-process is ready (shader is compiled)
-	 */
-	public isReady(): boolean {
-	    return this._effect && this._effect.isReady();
-	}
-
-	/**
 	 * 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)
@@ -219,24 +221,26 @@ export class HDRFiltering {
      * @param lodLevel defines which lod of the texture to render to
      */
     public directRender(targetTexture: InternalTexture, faceIndex = 0, lodLevel = 0): void {
-    	if (!this.isReady()) {
-    		return;
-    	}
-
+    	console.log("Rendering lod level " + lodLevel)
         var engine = this._engine;
-        engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, false, lodLevel);
+        var gl = engine._gl;
+        engine._currentRenderTarget = null;
+        engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, true, lodLevel);
+        const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+
+        console.assert(status === gl.FRAMEBUFFER_COMPLETE, 'incomplete!');
 
-        engine.clear(new Color4(1.0, 0.0, 0.0, 1.0), true, true);
+        engine.clear(new Color4(0.0, 0.0, 0.0, 0.0), true, true);
         // VBOs
         this._prepareBuffers();
         engine.bindBuffers(this._vertexBuffers, this._indexBuffer, this._effect);
         engine.drawElementsType(Material.TriangleFillMode, 0, 6);
 
-        engine.restoreDefaultFramebuffer();
+        // engine.restoreDefaultFramebuffer();
         // Restore depth buffer
-	    engine.setState(true);
-        engine.setDepthBuffer(true);
-        engine.setDepthWrite(true);
+	    // engine.setState(true);
+     //    engine.setDepthBuffer(true);
+     //    engine.setDepthWrite(true);
     }
 
     private _indexBuffer: DataBuffer;

+ 1 - 1
src/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.fx

@@ -205,7 +205,7 @@
             NoH = clamp(dot(h, n), 0.0, 1.0);
             NoL = clamp(dot(l, n), 0.0, 1.0);
             if (NoL > 0.) {
-                float solidAngleTexel = 4. * 3.14159 / (6. * 128. * 128.);
+                float solidAngleTexel = 4. / (6. * 128. * 128.);
                 float solidAngleSample = 4.0 / (float(NUM_SAMPLES) * weights[i]);
                 float lod = 0.5 * log2(solidAngleSample/solidAngleTexel);
                 // gamma correction needed ?

+ 31 - 30
src/Shaders/hdrFiltering.fragment.fx

@@ -6,38 +6,39 @@ uniform float weights[NUM_SAMPLES];
 varying vec3 direction;
 
 void main() {
-    // // Rotation by PI around y is necessary for consistency with IBLBaker
+    // Rotation by PI around y is necessary for consistency with IBLBaker
     // vec3 n = vec3(-direction.x, direction.y, -direction.z);
-    // vec3 tangent = abs(n.z) < 0.999 ? vec3(0., 0., 1.) : vec3(1., 0., 0.);
-    // tangent = normalize(cross(tangent, n));
-    // vec3 bitangent = cross(n, tangent);
-    // mat3 tbn = mat3(tangent, bitangent, n);
+    vec3 n = normalize(direction);
+    vec3 tangent = abs(n.z) < 0.999 ? vec3(0., 0., 1.) : vec3(1., 0., 0.);
+    tangent = normalize(cross(tangent, n));
+    vec3 bitangent = cross(n, tangent);
+    mat3 tbn = mat3(tangent, bitangent, n);
 
-    // vec3 color = vec3(0.);
-    // vec3 h;
-    // vec3 l;
-    // float NoH;
-    // float NoL;
-    // float totalWeight = 0.;
-    // for (int i = 0; i < NUM_SAMPLES; i++) {
-    //     h = tbn * sampleDirections[i];
-    //     l = 2. * dot(h, n) * h - n;
-    //     NoH = clamp(dot(h, n), 0.0, 1.0);
-    //     NoL = clamp(dot(l, n), 0.0, 1.0);
-    //     if (NoL > 0.) {
-    //         float solidAngleTexel = 4. * 3.14159 / (6. * cubeWidth * cubeWidth);
-    //         float solidAngleSample = 4.0 / (float(NUM_SAMPLES) * weights[i]);
-    //         float lod = 0.5 * log2(solidAngleSample / solidAngleTexel);
-    //         // gamma correction needed ?
-    //         color += textureCubeLodEXT(inputTexture, l, lod).xyz * NoL;
-    //         totalWeight += NoL;            
-    //     }
-    // }
+    vec3 color = vec3(0.);
+    vec3 h;
+    vec3 l;
+    float NoH;
+    float NoL;
+    float totalWeight = 0.;
+    for (int i = 0; i < NUM_SAMPLES; i++) {
+        h = tbn * sampleDirections[i];
+        l = 2. * dot(h, n) * h - n;
+        NoH = clamp(dot(h, n), 0.0, 1.0);
+        NoL = clamp(dot(l, n), 0.0, 1.0);
+        if (NoL > 0.) {
+            float solidAngleTexel = 4. * 3.14159 / (6. * cubeWidth * cubeWidth);
+            float solidAngleSample = 1.5 * 4.0 / (float(NUM_SAMPLES) * weights[i]); // Multiplying by 1.5 gives better results
+            float lod = 0.5 * log2(solidAngleSample / solidAngleTexel);
+            // gamma correction needed ?
+            color += textureCubeLodEXT(inputTexture, l, lod).xyz * NoL;
+            totalWeight += NoL;            
+        }
+    }
 
-    // if (totalWeight != 0.) {
-    //     color /= totalWeight;
-    // }
+    if (totalWeight != 0.) {
+        color /= totalWeight;
+    }
 
-    // gl_FragColor = vec4(color, 1.0);
-    gl_FragColor = vec4(textureCube(inputTexture, normalize(direction)).xyz, 1.0);
+    gl_FragColor = vec4(color, 1.0);
+    // gl_FragColor = vec4(textureCube(inputTexture, normalize(direction)).xyz, 1.0);
 }