Explorar o código

Adding support for post-processes

Deltakosh %!s(int64=11) %!d(string=hai) anos
pai
achega
11723727ef

+ 1 - 1
Babylon/Layer/babylon.layer.js

@@ -72,7 +72,7 @@
     
     BABYLON.Layer.prototype.dispose = function () {
         if (this._vertexBuffer) {
-            //this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+            this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
             this._vertexBuffer = null;
         }
 

+ 37 - 7
Babylon/Materials/babylon.effect.js

@@ -13,24 +13,34 @@
         this._attributesNames = attributesNames;
 
         var that = this;
+        
+        var vertex = baseName.vertex || baseName;
+        var fragment = baseName.fragment || baseName;
 
         // Is in local store ?
-        if (BABYLON.Effect.ShadersStore[baseName + "VertexShader"]) {
-            this._prepareEffect(BABYLON.Effect.ShadersStore[baseName + "VertexShader"], BABYLON.Effect.ShadersStore[baseName + "PixelShader"], attributesNames, defines, optionalDefines);
+        if (BABYLON.Effect.ShadersStore[vertex + "VertexShader"]) {
+            this._prepareEffect(BABYLON.Effect.ShadersStore[vertex + "VertexShader"], BABYLON.Effect.ShadersStore[fragment + "PixelShader"], attributesNames, defines, optionalDefines);
         } else {
-            var shaderUrl;
+            var vertexShaderUrl;
+            var fragmentShaderUrl;
 
             if (baseName[0] === ".") {
-                shaderUrl = baseName;
+                vertexShaderUrl = vertex;
+                fragmentShaderUrl = fragment;
             } else {
-                shaderUrl = BABYLON.Engine.ShadersRepository + baseName;
+                vertexShaderUrl = BABYLON.Engine.ShadersRepository + vertex;
+                if (fragment != vertex) {
+                    fragmentShaderUrl = fragment;
+                } else {
+                    fragmentShaderUrl = BABYLON.Engine.ShadersRepository + fragment;
+                }
             }
 
             // Vertex shader
-            BABYLON.Tools.LoadFile(shaderUrl + ".vertex.fx",
+            BABYLON.Tools.LoadFile(vertexShaderUrl + ".vertex.fx",
                 function (vertexSourceCode) {
                     // Fragment shader
-                    BABYLON.Tools.LoadFile(shaderUrl + ".fragment.fx",
+                    BABYLON.Tools.LoadFile(fragmentShaderUrl + ".fragment.fx",
                         function (fragmentSourceCode) {
                             that._prepareEffect(vertexSourceCode, fragmentSourceCode, attributesNames, defines, optionalDefines);
                         });
@@ -107,14 +117,25 @@
                 }
                 this._prepareEffect(vertexSourceCode, fragmentSourceCode, attributesNames, defines, optionalDefines, true);
             } else {
+                console.error("Unable to compile effect: " + this.name);
+                console.error("Defines: " + defines);
+                console.error("Optional defines: " + optionalDefines);
                 this._compilationError = e.message;
             }
         }
     };
+    
+    BABYLON.Effect.prototype._bindTexture = function (channel, texture) {
+        this._engine._bindTexture(this._samplers.indexOf(channel), texture);
+    };
 
     BABYLON.Effect.prototype.setTexture = function (channel, texture) {
         this._engine.setTexture(this._samplers.indexOf(channel), texture);
     };
+    
+    BABYLON.Effect.prototype.setTextureFromPostProcess = function (channel, postProcess) {
+        this._engine.setTextureFromPostProcess(this._samplers.indexOf(channel), postProcess);
+    };
 
     //BABYLON.Effect.prototype._cacheMatrix = function (uniformName, matrix) {
     //    if (!this._valueCache[uniformName]) {
@@ -181,6 +202,15 @@
         //this._cacheMatrix(uniformName, matrix);
         this._engine.setMatrix(this.getUniform(uniformName), matrix);
     };
+    
+    BABYLON.Effect.prototype.setFloat = function (uniformName, value) {
+        if (this._valueCache[uniformName] && this._valueCache[uniformName] === value)
+            return;
+
+        this._valueCache[uniformName] = value;
+
+        this._engine.setFloat(this.getUniform(uniformName), value);
+    };
 
     BABYLON.Effect.prototype.setBool = function (uniformName, bool) {
         if (this._valueCache[uniformName] && this._valueCache[uniformName] === bool)

+ 3 - 0
Babylon/Materials/babylon.standardMaterial.js

@@ -100,6 +100,7 @@
                 return false;
             } else {
                 defines.push("#define SPECULAR");
+                optionalDefines.push(defines[defines.length - 1]);
             }
         }
 
@@ -108,6 +109,7 @@
                 return false;
             } else {
                 defines.push("#define BUMP");
+                optionalDefines.push(defines[defines.length - 1]);
             }
         }
 
@@ -123,6 +125,7 @@
         // Fog
         if (this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) {
             defines.push("#define FOG");
+            optionalDefines.push(defines[defines.length - 1]);
         }
 
         var shadowsActivated = false;

+ 56 - 2
Babylon/PostProcess/babylon.postProcess.js

@@ -1,6 +1,60 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-    BABYLON.PostProcess = function () {
-    }; 
+    BABYLON.PostProcess = function (name, fragmentUrl, parameters, samplers, ratio, scene) {
+        this.name = name;
+        this._scene = scene;
+        this._manager = scene.postProcessManager;
+        this._manager.postProcesses.push(this);
+        this._engine = 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);
+
+        samplers = samplers || [];
+        samplers.push("textureSampler");
+
+        this._effect = this._engine.createEffect({ vertex: "postprocess", fragment: fragmentUrl },
+            ["position"],
+            parameters || [],
+            samplers, "");
+    };
+    
+    // Methods
+    BABYLON.PostProcess.prototype.onApply = null;
+
+    BABYLON.PostProcess.prototype.activate = function() {
+        this._engine.bindFramebuffer(this._texture);
+    };
+
+    BABYLON.PostProcess.prototype.apply = function () {
+        // Check
+        if (!this._effect.isReady())
+            return null;
+
+        // Render
+        this._engine.enableEffect(this._effect);
+        this._engine.setState(false);
+        this._engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+
+        // Texture
+        this._effect._bindTexture("textureSampler", this._texture);
+        
+        // Parameters
+        if (this.onApply) {
+            this.onApply(this._effect);
+        }
+
+        return this._effect;
+    };
+
+    BABYLON.PostProcess.prototype.dispose = function() {
+        this._engine._releaseTexture(this._texture);
+        
+        var index = this._manager.postProcesses.indexOf(this);
+        this._manager.postProcesses.splice(index, 1);        
+    };
+
 })();

+ 64 - 3
Babylon/PostProcess/babylon.postProcessManager.js

@@ -1,20 +1,81 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-    BABYLON.PostProcessManager = function () {
+    BABYLON.PostProcessManager = function (scene) {
         this.postProcesses = [];
+        this._scene = scene;
+        
+        // VBO
+        var vertices = [];
+        vertices.push(1, 1);
+        vertices.push(-1, 1);
+        vertices.push(-1, -1);
+        vertices.push(1, -1);
+        this._vertexDeclaration = [2];
+        this._vertexStrideSize = 2 * 4;
+        this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+
+        // Indices
+        var indices = [];
+        indices.push(0);
+        indices.push(1);
+        indices.push(2);
+
+        indices.push(0);
+        indices.push(2);
+        indices.push(3);
+
+        this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
     };
 
     // Methods
     BABYLON.PostProcessManager.prototype._prepareFrame = function () {
-        if (this.postProcesses.length === 0) {
+        if (this.postProcesses.length === 0 || !this._scene.postProcessesEnabled) {
             return;
         }
+
+        this.postProcesses[0].activate();
     };
     
     BABYLON.PostProcessManager.prototype._finalizeFrame = function () {
-        if (this.postProcesses.length === 0) {
+        if (this.postProcesses.length === 0 || !this._scene.postProcessesEnabled) {
             return;
         }
+
+        var engine = this._scene.getEngine();
+        
+        for (var index = 0; index < this.postProcesses.length; index++) {            
+            if (index < this.postProcesses.length - 1) {
+                this.postProcesses[index + 1].activate();
+            } else {
+                engine.restoreDefaultFramebuffer();
+            }
+
+            var effect = this.postProcesses[index].apply();
+
+            if (effect) {
+                // VBOs
+                engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+
+                // Draw order
+                engine.draw(true, 0, 6);
+            }
+        }
+    };
+
+    BABYLON.PostProcessManager.prototype.dispose = function () {
+        if (this._vertexBuffer) {
+            this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+            this._vertexBuffer = null;
+        }
+
+        if (this._indexBuffer) {
+            this._scene.getEngine()._releaseBuffer(this._indexBuffer);
+            this._indexBuffer = null;
+        }
+
+        while (this.postProcesses.length) {
+            this.postProcesses[0].dispose();
+        }
     };
 })();

+ 17 - 0
Babylon/Shaders/postprocess.vertex.fx

@@ -0,0 +1,17 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+// Attributes
+attribute vec2 position;
+
+// Output
+varying vec2 vUV;
+
+const vec2 madd = vec2(0.5, 0.5);
+
+void main(void) {	
+
+	vUV = position * madd + madd;
+	gl_Position = vec4(position, 0.0, 1.0);
+}

+ 31 - 7
Babylon/babylon.engine.js

@@ -217,7 +217,7 @@
     BABYLON.Engine.prototype.bindFramebuffer = function (texture) {
         var gl = this._gl;
         gl.bindFramebuffer(gl.FRAMEBUFFER, texture._framebuffer);
-        gl.viewport(0.0, 0.0, texture._size, texture._size);
+        gl.viewport(0.0, 0.0, texture._width, texture._height);
 
         this.wipeCaches();
     };
@@ -345,7 +345,10 @@
 
     // Shaders
     BABYLON.Engine.prototype.createEffect = function (baseName, attributesNames, uniformsNames, samplers, defines, optionalDefines) {
-        var name = baseName + "@" + defines;
+        var vertex = baseName.vertex || baseName;
+        var fragment = baseName.fragment || baseName;
+        
+        var name = vertex + "+" + fragment + "@" + defines;
         if (this._compiledEffects[name]) {
             return this._compiledEffects[name];
         }
@@ -363,8 +366,6 @@
         gl.compileShader(shader);
 
         if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
-            console.error("Error while compiling shader: " + gl.getShaderInfoLog(shader));
-            console.error("Defines: " + defines);
             throw new Error(gl.getShaderInfoLog(shader));
         }
         return shader;
@@ -475,6 +476,13 @@
 
         this._gl.uniform3f(uniform, x, y, z);
     };
+    
+    BABYLON.Engine.prototype.setFloat = function (uniform, value) {
+        if (!uniform)
+            return;
+
+        this._gl.uniform1f(uniform, value);
+    };
 
     BABYLON.Engine.prototype.setBool = function (uniform, bool) {
         if (!uniform)
@@ -719,16 +727,19 @@
         var texture = gl.createTexture();
         gl.bindTexture(gl.TEXTURE_2D, texture);
 
+        var width = size.width || 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);
         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.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
 
         // Create the depth buffer
         var depthBuffer = gl.createRenderbuffer();
         gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
-        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size);
+        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
 
         // Create the framebuffer
         var framebuffer = gl.createFramebuffer();
@@ -743,7 +754,8 @@
 
         texture._framebuffer = framebuffer;
         texture._depthBuffer = depthBuffer;
-        texture._size = size;
+        texture._width = width;
+        texture._height = height;
         texture.isReady = true;
         texture.generateMipMaps = generateMipMaps;
         texture.references = 1;
@@ -859,6 +871,18 @@
         this._currentEffect = null;
     };
 
+
+    BABYLON.Engine.prototype._bindTexture = function (channel, texture) {
+        this._gl.activeTexture(this._gl["TEXTURE" + channel]);
+        this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
+        
+        this._activeTexturesCache[channel] = null;
+    };
+
+    BABYLON.Engine.prototype.setTextureFromPostProcess = function (channel, postProcess) {
+        this._bindTexture(channel, postProcess._texture);
+    };
+
     BABYLON.Engine.prototype.setTexture = function (channel, texture) {
         if (channel < 0) {
             return;

+ 5 - 1
Babylon/babylon.scene.js

@@ -90,7 +90,8 @@
         this._scaledVelocity = BABYLON.Vector3.Zero();
 
         // Postprocesses
-        this.postProcessManager = new BABYLON.PostProcessManager();
+        this.postProcessesEnabled = true;
+        this.postProcessManager = new BABYLON.PostProcessManager(this);
     };
 
     // Properties   
@@ -725,6 +726,9 @@
         while (this.textures.length) {
             this.textures[0].dispose();
         }
+        
+        // Post-processes
+        this.postProcessManager.dispose();
 
         // Remove from engine
         index = this._engine.scenes.indexOf(this);