Browse Source

Merge pull request #95 from simonferquel/master

FXAA support
deltakosh 11 years ago
parent
commit
ec8e019677

BIN
Babylon/JSKompactor.exe


+ 16 - 0
Babylon/PostProcess/babylon.fxaaPostProcess.js

@@ -0,0 +1,16 @@
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.FxaaPostProcess = function (name, ratio, camera) {
+        BABYLON.PostProcess.call(this, name, "fxaa", ["texelSize"], null, ratio, camera);
+    };
+    
+    BABYLON.FxaaPostProcess.prototype = Object.create(BABYLON.PostProcess.prototype);
+    BABYLON.FxaaPostProcess.prototype.onSizeChanged = function () {
+        this.texelWidth = 1.0 / this.width;
+        this.texelHeight = 1.0 / this.height;
+    };
+    BABYLON.FxaaPostProcess.prototype.onApply = function (effect) {
+        effect.setFloat2("texelSize", this.texelWidth, this.texelHeight);
+    };
+})();

+ 28 - 10
Babylon/PostProcess/babylon.postProcess.js

@@ -1,17 +1,16 @@
 var BABYLON = BABYLON || {};
 var BABYLON = BABYLON || {};
 
 
 (function () {
 (function () {
-    BABYLON.PostProcess = function (name, fragmentUrl, parameters, samplers, ratio, camera) {
+    BABYLON.PostProcess = function (name, fragmentUrl, parameters, samplers, ratio, camera, samplingMode) {
         this.name = name;
         this.name = name;
         this._camera = camera;
         this._camera = camera;
         this._scene = camera.getScene();
         this._scene = camera.getScene();
         camera.postProcesses.push(this);
         camera.postProcesses.push(this);
         this._engine = this._scene.getEngine();
         this._engine = this._scene.getEngine();
-
-        this.width = this._engine._renderingCanvas.width * ratio;
-        this.height = this._engine._renderingCanvas.height * ratio;
-        
-        this._texture = this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, false);
+        this._renderRatio = ratio;
+        this.width = -1;
+        this.height = -1;
+        this.renderTargetSamplingMode = samplingMode ? samplingMode : BABYLON.TextureSamplingModes.NEAREST;
 
 
         samplers = samplers || [];
         samplers = samplers || [];
         samplers.push("textureSampler");
         samplers.push("textureSampler");
@@ -25,8 +24,22 @@
     // Methods
     // Methods
     BABYLON.PostProcess.prototype.onApply = null;
     BABYLON.PostProcess.prototype.onApply = null;
     BABYLON.PostProcess.prototype._onDispose = null;
     BABYLON.PostProcess.prototype._onDispose = null;
-
-    BABYLON.PostProcess.prototype.activate = function() {
+    BABYLON.PostProcess.prototype.onSizeChanged = null;
+    BABYLON.PostProcess.prototype.activate = function () {
+        var desiredWidth = this._engine._renderingCanvas.width * this._renderRatio;
+        var desiredHeight = this._engine._renderingCanvas.height * this._renderRatio;
+        if (this.width !== desiredWidth || this.height !== desiredHeight) {
+            if (this._texture) {
+                this._engine._releaseTexture(this._texture);
+                this._texture = null;
+            }
+            this.width = desiredWidth;
+            this.height = desiredHeight;
+            this._texture = this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: this._camera.postProcesses.indexOf(this) === 0, samplingMode: this.renderTargetSamplingMode });
+            if (this.onSizeChanged) {
+                this.onSizeChanged();
+            }
+        }
         this._engine.bindFramebuffer(this._texture);
         this._engine.bindFramebuffer(this._texture);
     };
     };
 
 
@@ -55,11 +68,16 @@
         if (this._onDispose) {
         if (this._onDispose) {
             this._onDispose();
             this._onDispose();
         }
         }
-
-        this._engine._releaseTexture(this._texture);
+        if (this._texture) {
+            this._engine._releaseTexture(this._texture);
+            this._texture = null;
+        }
         
         
         var index = this._camera.postProcesses.indexOf(this);
         var index = this._camera.postProcesses.indexOf(this);
         this._camera.postProcesses.splice(index, 1);
         this._camera.postProcesses.splice(index, 1);
+        if (index == 0 && this._camera.postProcesses.length > 0) {
+            this._camera.postProcesses[0].width = -1; // invalidate frameBuffer to hint the postprocess to create a depth buffer
+        }
     };
     };
 
 
 })();
 })();

+ 8 - 1
Babylon/PostProcess/babylon.postProcessManager.js

@@ -59,11 +59,18 @@
             if (effect) {
             if (effect) {
                 // VBOs
                 // VBOs
                 engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
                 engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
-
+                // some effect activation have a side effect of putting depthBuffer / dephWrite on
+                // so we force it off at each post process pass
+                engine.setDepthBuffer(false);
+                engine.setDepthWrite(false);
                 // Draw order
                 // Draw order
                 engine.draw(true, 0, 6);
                 engine.draw(true, 0, 6);
             }
             }
         }
         }
+        // reenable depth buffer
+
+        engine.setDepthBuffer(true);
+        engine.setDepthWrite(true);
     };
     };
 
 
     BABYLON.PostProcessManager.prototype.dispose = function () {
     BABYLON.PostProcessManager.prototype.dispose = function () {

+ 50 - 0
Babylon/Shaders/fxaa.fragment.fx

@@ -0,0 +1,50 @@
+#define FXAA_REDUCE_MIN   (1.0/128.0)
+#define FXAA_REDUCE_MUL   (1.0/8.0)
+#define FXAA_SPAN_MAX     8.0
+//#define texelSize  vec2(1.0/1600, 1.0/900)
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+uniform vec2 texelSize;
+
+void main(){
+	vec2 localTexelSize = texelSize;
+	vec3 rgbNW = texture2D(textureSampler, (vUV + vec2(-1.0, -1.0) * localTexelSize)).xyz;
+	vec3 rgbNE = texture2D(textureSampler, (vUV + vec2(1.0, -1.0) * localTexelSize)).xyz;
+	vec3 rgbSW = texture2D(textureSampler, (vUV + vec2(-1.0, 1.0) * localTexelSize)).xyz;
+	vec3 rgbSE = texture2D(textureSampler, (vUV + vec2(1.0, 1.0) * localTexelSize)).xyz;
+	vec3 rgbM = texture2D(textureSampler, vUV ).xyz;
+	vec3 luma = vec3(0.299, 0.587, 0.114);
+	float lumaNW = dot(rgbNW, luma);
+	float lumaNE = dot(rgbNE, luma);
+	float lumaSW = dot(rgbSW, luma);
+	float lumaSE = dot(rgbSE, luma);
+	float lumaM = dot(rgbM, luma);
+	float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
+	float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
+
+	vec2 dir = vec2(-((lumaNW + lumaNE) - (lumaSW + lumaSE)), ((lumaNW + lumaSW) - (lumaNE + lumaSE)));
+
+	float dirReduce = max(
+		(lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),
+		FXAA_REDUCE_MIN);
+
+	float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
+	dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
+		max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
+		dir * rcpDirMin)) * localTexelSize;
+
+	vec3 rgbA = 0.5 * (
+		texture2D(textureSampler, vUV + dir * (1.0 / 3.0 - 0.5)).xyz +
+		texture2D(textureSampler, vUV + dir * (2.0 / 3.0 - 0.5)).xyz);
+
+	vec3 rgbB = rgbA * 0.5 + 0.25 * (
+		texture2D(textureSampler, vUV + dir *  -0.5).xyz +
+		texture2D(textureSampler, vUV + dir * 0.5).xyz);
+	float lumaB = dot(rgbB, luma);
+	if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
+		gl_FragColor = vec4(rgbA, 1.0);
+	}
+	else {
+		gl_FragColor = vec4(rgbB, 1.0);
+	}
+}

+ 58 - 10
Babylon/babylon.engine.js

@@ -1,6 +1,12 @@
 var BABYLON = BABYLON || {};
 var BABYLON = BABYLON || {};
 
 
 (function () {
 (function () {
+    BABYLON.TextureSamplingModes = {
+        NEAREST : 1,
+        BILINEAR: 2,
+        TRILINEAR: 3,
+        DEFAULT : 3
+    };
     BABYLON.Engine = function (canvas, antialias) {
     BABYLON.Engine = function (canvas, antialias) {
         this._renderingCanvas = canvas;
         this._renderingCanvas = canvas;
 
 
@@ -707,31 +713,66 @@
         texture.isReady = true;
         texture.isReady = true;
     };
     };
 
 
-    BABYLON.Engine.prototype.createRenderTargetTexture = function (size, generateMipMaps) {
+    BABYLON.Engine.prototype.createRenderTargetTexture = function (size, options) {
+        // old version had a "generateMipMaps" arg instead of options.
+        // if options.generateMipMaps is undefined, consider that options itself if the generateMipmaps value
+        // in the same way, generateDepthBuffer is defaulted to true
+        var generateMipMaps = false;
+        var generateDepthBuffer = true;
+        var samplingMode = BABYLON.TextureSamplingModes.DEFAULT;
+        if (options !== undefined) {
+            generateMipMaps = options.generateMipMaps === undefined ? options : options.generateMipmaps;
+            generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
+            if (options.samplingMode !== undefined) {
+                samplingMode = options.samplingMode;
+            }
+        }
         var gl = this._gl;
         var gl = this._gl;
 
 
+        
+
         var texture = gl.createTexture();
         var texture = gl.createTexture();
         gl.bindTexture(gl.TEXTURE_2D, texture);
         gl.bindTexture(gl.TEXTURE_2D, texture);
 
 
         var width = size.width || size;
         var width = size.width || size;
         var height = size.height || size;
         var height = size.height || size;
-
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, generateMipMaps ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
+        var magFilter = gl.NEAREST;
+        var minFilter = gl.NEAREST;
+        if (samplingMode === BABYLON.TextureSamplingModes.BILINEAR) {
+            magFilter = gl.LINEAR;
+            if (generateMipMaps) {
+                minFilter = gl.LINEAR_MIPMAP_NEAREST;
+            } else {
+                minFilter = gl.LINEAR;
+            }
+        } else if (samplingMode === BABYLON.TextureSamplingModes.TRILINEAR) {
+            magFilter = gl.LINEAR;
+            if (generateMipMaps) {
+                minFilter = gl.LINEAR_MIPMAP_LINEAR;
+            } else {
+                minFilter = gl.LINEAR;
+            }
+        }
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
         gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
         gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
 
 
+        var depthBuffer;
         // Create the depth buffer
         // Create the depth buffer
-        var depthBuffer = gl.createRenderbuffer();
-        gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
-        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
-
+        if (generateDepthBuffer) {
+            depthBuffer = gl.createRenderbuffer();
+            gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
+            gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
+        }
         // Create the framebuffer
         // Create the framebuffer
         var framebuffer = gl.createFramebuffer();
         var framebuffer = gl.createFramebuffer();
         gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
         gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
         gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
         gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
-        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
+        if (generateDepthBuffer) {
+            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
+        }
 
 
         // Unbind
         // Unbind
         gl.bindTexture(gl.TEXTURE_2D, null);
         gl.bindTexture(gl.TEXTURE_2D, null);
@@ -739,7 +780,9 @@
         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
         gl.bindFramebuffer(gl.FRAMEBUFFER, null);
 
 
         texture._framebuffer = framebuffer;
         texture._framebuffer = framebuffer;
-        texture._depthBuffer = depthBuffer;
+        if (generateDepthBuffer) {
+            texture._depthBuffer = depthBuffer;
+        }
         texture._width = width;
         texture._width = width;
         texture._height = height;
         texture._height = height;
         texture.isReady = true;
         texture.isReady = true;
@@ -845,6 +888,11 @@
             this._gl.bindTexture(this._gl.TEXTURE_CUBE_MAP, null);
             this._gl.bindTexture(this._gl.TEXTURE_CUBE_MAP, null);
             this._activeTexturesCache[channel] = null;
             this._activeTexturesCache[channel] = null;
         }
         }
+        // hmm vilain leak !
+        var index = this._loadedTexturesCache.indexOf(texture);
+        if (index !== -1) {
+            this._loadedTexturesCache.splice(index, 1);
+        }
     };
     };
 
 
     BABYLON.Engine.prototype.bindSamplers = function (effect) {
     BABYLON.Engine.prototype.bindSamplers = function (effect) {

File diff suppressed because it is too large
+ 1 - 0
Babylon/jscompaktor.bat


File diff suppressed because it is too large
+ 8 - 2
Samples/babylon.js


+ 3 - 0
Samples/index.html

@@ -272,6 +272,9 @@
                         Change control method:
                         Change control method:
                         <button class="buttonControlPanel" id="touchCamera">Switch to touch camera</button>
                         <button class="buttonControlPanel" id="touchCamera">Switch to touch camera</button>
                         <button class="buttonControlPanel" id="deviceOrientationCamera">Switch to device orientation camera</button>
                         <button class="buttonControlPanel" id="deviceOrientationCamera">Switch to device orientation camera</button>
+                        <button class="buttonControlPanel" id="toggleFxaa">Toggle FXAA (antialiasing)</button>
+                        <button class="buttonControlPanel" id="toggleFsaa4">Toggle FSAA 4X (antialiasing)</button>
+                        <button class="buttonControlPanel" id="toggleBandW">Toggle Black and white</button>
                     </p>
                     </p>
                 </div>
                 </div>
                 <div class="cameraTag"><img src="Assets/camera.png" /></div>
                 <div class="cameraTag"><img src="Assets/camera.png" /></div>

+ 37 - 0
Samples/index.js

@@ -92,6 +92,9 @@
     var touchCamera = document.getElementById("touchCamera");
     var touchCamera = document.getElementById("touchCamera");
     var deviceOrientationCamera = document.getElementById("deviceOrientationCamera");
     var deviceOrientationCamera = document.getElementById("deviceOrientationCamera");
     var camerasList = document.getElementById("camerasList");
     var camerasList = document.getElementById("camerasList");
+    var toggleFxaa = document.getElementById("toggleFxaa");
+    var toggleFsaa4 = document.getElementById("toggleFsaa4");
+    var toggleBandW = document.getElementById("toggleBandW");
 
 
     var sceneChecked;
     var sceneChecked;
 
 
@@ -589,6 +592,40 @@
         }
         }
     });
     });
 
 
+    toggleFxaa.addEventListener("click", function () {
+        if (scene && scene.activeCamera) {
+            if (scene.activeCamera.__fxaa_cookie) {
+                scene.activeCamera.__fxaa_cookie.dispose(),
+                scene.activeCamera.__fxaa_cookie = null;
+            } else {
+                scene.activeCamera.__fxaa_cookie = new BABYLON.FxaaPostProcess("fxaa", 1.0, scene.activeCamera);
+            }
+        }
+    });
+    toggleBandW.addEventListener("click", function () {
+        if (scene && scene.activeCamera) {
+            if (scene.activeCamera.__bandw_cookie) {
+                scene.activeCamera.__bandw_cookie.dispose(),
+                scene.activeCamera.__bandw_cookie = null;
+            } else {
+                scene.activeCamera.__bandw_cookie = new BABYLON.BlackAndWhitePostProcess("bandw", 1.0, scene.activeCamera);
+            }
+        }
+    });
+    toggleFsaa4.addEventListener("click", function () {
+
+        if (scene && scene.activeCamera) {
+            if (scene.activeCamera.__fsaa_cookie) {
+                scene.activeCamera.__fsaa_cookie.dispose(),
+                scene.activeCamera.__fsaa_cookie = null;
+            } else {
+                var fx = new BABYLON.PassPostProcess("fsaa", 2.0, scene.activeCamera);
+                fx.renderTargetSamplingMode = BABYLON.TextureSamplingModes.BILINEAR;
+                scene.activeCamera.__fsaa_cookie = fx;
+            }
+        }
+    });
+
     // Cameras
     // Cameras
     camerasList.addEventListener("change", function (ev) {
     camerasList.addEventListener("change", function (ev) {
         scene.activeCamera.detachControl(canvas);
         scene.activeCamera.detachControl(canvas);

+ 9 - 0
Samples/web.config

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <system.webServer>
+        <staticContent>
+            <mimeMap fileExtension=".fx" mimeType="application/shader" />
+            <mimeMap fileExtension=".babylon" mimeType="application/babylon" />
+        </staticContent>
+    </system.webServer>
+</configuration>

File diff suppressed because it is too large
+ 19 - 0
babylon.js