浏览代码

initial commit for MRT implementation

Benjamin Guignabert 8 年之前
父节点
当前提交
3d0b70ccc9

文件差异内容过多而无法显示
+ 3064 - 3024
dist/preview release/babylon.d.ts


文件差异内容过多而无法显示
+ 3064 - 3024
dist/preview release/babylon.module.d.ts


+ 124 - 0
src/Materials/Textures/babylon.multiRenderTarget.ts

@@ -0,0 +1,124 @@
+module BABYLON {
+    export class MultiRenderTarget {
+
+        public getScene(): Scene {
+            return this._scene;
+        }
+
+        private _textures: WebGLTexture[];
+        private _count: number;
+        private _scene: Scene;
+        private _renderingManager: RenderingManager;
+        private _doNotChangeAspectRatio: boolean;
+        private _size: number;
+
+        public customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents?: () => void) => void;
+
+        constructor(name: string, size: any, count: number, scene: Scene, options?: any) {
+            options = options || {};
+
+            var generateMipMaps = options.generateMipMaps ? options.generateMipMaps[0] : true;
+            var doNotChangeAspectRatio = options.doNotChangeAspectRatio;
+            var type = options.types ? options.types[0] : Engine.TEXTURETYPE_UNSIGNED_INT;
+            var samplingMode = options.samplingModes ? options.samplingModes[0] : Texture.TRILINEAR_SAMPLINGMODE;
+            var generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
+            var generateStencilBuffer = options.generateStencilBuffer === undefined ? false : options.generateStencilBuffer;
+
+            this._count = count;
+            this._scene = scene;
+            this._doNotChangeAspectRatio = doNotChangeAspectRatio;
+            this._size = size;
+            this._textures = scene.getEngine().createMultipleRenderTarget(size, {
+                samplingMode: samplingMode,
+                generateMipMaps: generateMipMaps,
+                generateDepthBuffer: generateDepthBuffer,
+                generateStencilBuffer: generateStencilBuffer,
+                type: type,
+                textureCount: count
+            });
+        }
+
+        public render(useCameraPostProcess?: boolean, dumpForDebug?: boolean) {
+            var scene = this.getScene();
+            var engine = scene.getEngine();
+
+            engine.setViewport(scene.activeCamera.viewport);
+
+            // Prepare renderingManager
+            this._renderingManager.reset();
+
+            var currentRenderList = scene.getActiveMeshes().data;
+            var currentRenderListLength = scene.getActiveMeshes().length;
+            var sceneRenderId = scene.getRenderId();
+            for (var meshIndex = 0; meshIndex < currentRenderListLength; meshIndex++) {
+                var mesh = currentRenderList[meshIndex];
+
+                if (mesh) {
+                    if (!mesh.isReady()) {
+                        continue;
+                    }
+
+                    if (mesh.isEnabled() && mesh.isVisible && mesh.subMeshes && ((mesh.layerMask & scene.activeCamera.layerMask) !== 0)) {
+                        for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
+                            var subMesh = mesh.subMeshes[subIndex];
+                            scene._activeIndices.addCount(subMesh.indexCount, false);
+                            this._renderingManager.dispatch(subMesh);
+                        }
+                    }
+                }
+            }
+
+            this.renderToTarget(0, currentRenderList, currentRenderListLength, useCameraPostProcess, dumpForDebug);
+
+            engine.setViewport(scene.activeCamera.viewport);
+
+            scene.resetCachedMaterial();
+        }
+
+        public renderToTarget(faceIndex: number, currentRenderList: AbstractMesh[], currentRenderListLength:number, useCameraPostProcess: boolean, dumpForDebug: boolean): void {
+            var scene = this.getScene();
+            var engine = scene.getEngine();
+
+            // Bind
+            engine.bindFramebuffer(this._textures[0]);
+            engine.clear(scene.clearColor, true, true, true);
+
+            if (!this._doNotChangeAspectRatio) {
+                scene.updateTransformMatrix(true);
+            }
+
+            // Render
+            this._renderingManager.render(this.customRenderFunction, currentRenderList, false, false);
+
+            if (!this._doNotChangeAspectRatio) {
+                scene.updateTransformMatrix(true);
+            }
+
+            // Dump ?
+            if (dumpForDebug) {
+                Tools.DumpFramebuffer(this._size, this._size, engine);
+            }
+
+            // Unbind
+            engine.unBindFramebuffer(this._textures[0]);
+        }
+
+
+        public dispose(): void {
+            // Animations
+            this.getScene().stopAnimation(this);
+
+            // Remove from scene
+            this._scene._removePendingData(this);
+
+            for (var i = this._textures.length - 1; i >= 0; i--) {
+                if (this._textures[i] !== undefined) {
+                    this._scene.getEngine().releaseInternalTexture(this._textures[i]);
+                    this._textures.splice(i, 1);
+                }
+            }
+        }
+
+
+    }
+}

+ 148 - 0
src/Rendering/babylon.geometryRenderer.ts

@@ -0,0 +1,148 @@
+module BABYLON {
+    export class GeometryRenderer {
+        private _scene: Scene;
+        private _multiRenderTarger: MultiRenderTarget;
+        private _effect: Effect;
+
+        private _viewMatrix = Matrix.Zero();
+        private _projectionMatrix = Matrix.Zero();
+        private _transformMatrix = Matrix.Zero();
+        private _worldViewProjection = Matrix.Zero();
+
+        private _cachedDefines: string;
+
+        constructor(scene: Scene, type: number = Engine.TEXTURETYPE_FLOAT) {
+            this._scene = scene;
+            var engine = scene.getEngine();
+
+            // Render target
+            this._multiRenderTarger = new MultiRenderTarget("gBuffer", { width: engine.getRenderWidth(), height: engine.getRenderHeight() }, 4, this._scene);
+            
+            // Custom render function
+            var renderSubMesh = (subMesh: SubMesh): void => {
+                var mesh = subMesh.getRenderingMesh();
+                var scene = this._scene;
+                var engine = scene.getEngine();
+
+                // Culling
+                engine.setState(subMesh.getMaterial().backFaceCulling);
+
+                // Managing instances
+                var batch = mesh._getInstancesRenderList(subMesh._id);
+
+                if (batch.mustReturn) {
+                    return;
+                }
+
+                var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
+
+                if (this.isReady(subMesh, hardwareInstancedRendering)) {
+                    engine.enableEffect(this._effect);
+                    mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
+                    var material = subMesh.getMaterial();
+
+                    this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+                    this._effect.setFloat("far", scene.activeCamera.maxZ);
+
+                    // Alpha test
+                    if (material && material.needAlphaTesting()) {
+                        var alphaTexture = material.getAlphaTestTexture();
+                        this._effect.setTexture("diffuseSampler", alphaTexture);
+                        this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
+                    }
+
+                    // Bones
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                        this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
+                    }
+
+                    // Draw
+                    mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
+                        (isInstance, world) => this._effect.setMatrix("world", world));
+                }
+            };
+
+            this._multiRenderTarger.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>): void => {
+                var index;
+
+                for (index = 0; index < opaqueSubMeshes.length; index++) {
+                    renderSubMesh(opaqueSubMeshes.data[index]);
+                }
+
+                for (index = 0; index < alphaTestSubMeshes.length; index++) {
+                    // Cannot render alpha meshes this way
+                    // renderSubMesh(alphaTestSubMeshes.data[index]);
+                }
+            };
+        }
+
+        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
+            var material: any = subMesh.getMaterial();
+
+            if (material && (material.disableDepthWrite || material.needAlphaTesting())) {
+                return false;
+            }
+
+            var defines = [];
+
+            var attribs = [VertexBuffer.PositionKind];
+
+            var mesh = subMesh.getMesh();
+            var scene = mesh.getScene();
+
+            if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                attribs.push(VertexBuffer.UVKind);
+                defines.push("#define UV1");
+            }
+            if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                attribs.push(VertexBuffer.UV2Kind);
+                defines.push("#define UV2");
+            }
+
+            // Bones
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                attribs.push(VertexBuffer.MatricesIndicesKind);
+                attribs.push(VertexBuffer.MatricesWeightsKind);
+                if (mesh.numBoneInfluencers > 4) {
+                    attribs.push(VertexBuffer.MatricesIndicesExtraKind);
+                    attribs.push(VertexBuffer.MatricesWeightsExtraKind);
+                }
+                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
+                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
+            } else {
+                defines.push("#define NUM_BONE_INFLUENCERS 0");
+            }
+
+            // Instances
+            if (useInstances) {
+                defines.push("#define INSTANCES");
+                attribs.push("world0");
+                attribs.push("world1");
+                attribs.push("world2");
+                attribs.push("world3");
+            }
+
+            // Get correct effect      
+            var join = defines.join("\n");
+            if (this._cachedDefines !== join) {
+                this._cachedDefines = join;
+                this._effect = this._scene.getEngine().createEffect("geometry",
+                    attribs,
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "far"],
+                    ["diffuseSampler"], join);
+            }
+
+            return this._effect.isReady();
+        }
+
+        public getGBuffer(): MultiRenderTarget {
+            return this._multiRenderTarger;
+        }
+
+        // Methods
+        public dispose(): void {
+            this.getGBuffer.dispose();
+        }
+    }
+} 

+ 97 - 0
src/babylon.engine.ts

@@ -2636,6 +2636,103 @@
             return texture;
         }
 
+        public createMultipleRenderTarget(size: any, options): WebGLTexture[] {
+            var generateMipMaps = false;
+            var generateDepthBuffer = true;
+            var generateStencilBuffer = false;
+            var textureCount = 1;
+
+            var type = Engine.TEXTURETYPE_UNSIGNED_INT;
+            var samplingMode = Texture.TRILINEAR_SAMPLINGMODE;
+            if (options !== undefined) {
+                generateMipMaps = options.generateMipMaps;
+                generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
+                generateStencilBuffer = options.generateStencilBuffer;
+                textureCount = options.textureCount || 1;
+
+                type = options.type === undefined ? type : options.type;
+                if (options.samplingMode !== undefined) {
+                    samplingMode = options.samplingMode;
+                }
+                if (type === Engine.TEXTURETYPE_FLOAT && !this._caps.textureFloatLinearFiltering) {
+                    // if floating point linear (gl.FLOAT) then force to NEAREST_SAMPLINGMODE
+                    samplingMode = Texture.NEAREST_SAMPLINGMODE;
+                }
+                else if (type === Engine.TEXTURETYPE_HALF_FLOAT && !this._caps.textureHalfFloatLinearFiltering) {
+                    // if floating point linear (HALF_FLOAT) then force to NEAREST_SAMPLINGMODE
+                    samplingMode = Texture.NEAREST_SAMPLINGMODE;
+                }
+            }
+            var gl = this._gl;
+            // Create the framebuffer
+            var framebuffer = gl.createFramebuffer();
+            this.bindUnboundFramebuffer(framebuffer);
+
+            var width = size.width || size;
+            var height = size.height || size;
+            var filters = getSamplingParameters(samplingMode, generateMipMaps, gl);
+            
+            var textures = [];
+            var attachments = []
+            if (type === Engine.TEXTURETYPE_FLOAT && !this._caps.textureFloat) {
+                type = Engine.TEXTURETYPE_UNSIGNED_INT;
+                Tools.Warn("Float textures are not supported. Render target forced to TEXTURETYPE_UNSIGNED_BYTE type");
+            }
+
+            for (var i = 0; i < textureCount; i++) {
+                var texture = gl.createTexture();
+                var attachment = gl["COLOR_ATTACHMENT" + i];
+                textures.push(texture);
+                attachments.push(attachment);
+
+                gl.activeTexture(gl["TEXTURE" + i]);
+                gl.bindTexture(gl.TEXTURE_2D, texture);
+
+                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filters.mag);
+                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filters.min);
+                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, this._getRGBABufferInternalSizedFormat(type), width, height, 0, gl.RGBA, this._getWebGLTextureType(type), null);
+            
+                gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, texture, 0);
+
+                texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(generateStencilBuffer, generateDepthBuffer, width, height);
+
+                if (generateMipMaps) {
+                    this._gl.generateMipmap(this._gl.TEXTURE_2D);
+                }
+
+                // Unbind
+                this._bindTextureDirectly(gl.TEXTURE_2D, null);
+                gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+                this.bindUnboundFramebuffer(null);
+
+                texture._framebuffer = framebuffer;
+                texture._baseWidth = width;
+                texture._baseHeight = height;
+                texture._width = width;
+                texture._height = height;
+                texture.isReady = true;
+                texture.samples = 1;
+                texture.generateMipMaps = generateMipMaps;
+                texture.references = 1;
+                texture.samplingMode = samplingMode;
+                texture.type = type;
+                texture._generateDepthBuffer = generateDepthBuffer;
+                texture._generateStencilBuffer = generateStencilBuffer;
+            }
+
+            gl.drawBuffers(attachments);
+
+            this.resetTextureCache();
+
+            // To keep ?
+            //this._loadedTexturesCache.push(texture);
+
+            return textures;
+        }
+
         private _setupFramebufferDepthAttachments(generateStencilBuffer: boolean, generateDepthBuffer: boolean, width: number, height: number, samples = 1): WebGLRenderbuffer {
             var depthStencilBuffer: WebGLRenderbuffer = null;
             var gl = this._gl;

+ 7 - 0
src/babylon.mixins.ts

@@ -50,6 +50,13 @@ interface WebGLRenderingContext {
     DRAW_FRAMEBUFFER: number;
     UNIFORM_BUFFER: number;
 
+    /* Multiple Render Targets */
+    drawBuffers(buffers: number[]): void;
+
+    readonly COLOR_ATTACHMENT0: number;                             // 0x8CE1
+    readonly COLOR_ATTACHMENT1: number;                             // 0x8CE2
+    readonly COLOR_ATTACHMENT2: number;                             // 0x8CE3
+    readonly COLOR_ATTACHMENT3: number;                             // 0x8CE4
 }
 
 interface HTMLURL {