Просмотр исходного кода

Merge pull request #3786 from sebavan/master

Integrate Depth Texture Support
David Catuhe 7 лет назад
Родитель
Сommit
8b9e46bc14

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

@@ -77,6 +77,7 @@
 - (Viewer) XHR requests not use Tools.LoadFile and are disposed correctly - [#3671](https://github.com/BabylonJS/Babylon.js/issues/3671) ([RaananW](https://github.com/RaananW))
 - Added `Tools.WorkerPool` class for web worker management. ([bghgary](https://github.com/bghgary))
 - Support depth maps for multiple active cameras for post processes like depth of field ([trevordev](https://github.com/trevordev))
+- Integrates depth texture support in the engine ([sebavan](https://github.com/sebavan))
 
 ## Bug fixes
 

+ 238 - 1
src/Engine/babylon.engine.ts

@@ -217,6 +217,18 @@
     }
 
     /**
+     * Define options used to create a depth texture
+     */
+    export class DepthTextureCreationOptions {
+        /** Specifies wether or not a stencil should be allocated in the texture */
+        generateStencil?: boolean;
+        /** Specifies wether or not bilinear filtering is enable on the texture */
+        bilinearFiltering?: boolean;
+        /** Specifies the comparison function to set on the texture. If 0 or undefined, the texture is not in comparison mode */
+        comparisonFunction?: number;
+    }
+
+    /**
      * Regroup several parameters relative to the browser in use
      */
     export class EngineCapabilities {
@@ -1290,6 +1302,7 @@
 
                 if (depthTextureExtension != null) {
                     this._caps.depthTextureExtension = true;
+                    this._gl.UNSIGNED_INT_24_8 = depthTextureExtension.UNSIGNED_INT_24_8_WEBGL;
                 }
             }
 
@@ -1927,7 +1940,16 @@
             });
         }
 
-        public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void {
+        /**
+         * Binds the frame buffer to the specified texture.
+         * @param texture The texture to render to or null for the default canvas
+         * @param faceIndex The face of the texture to render to in case of cube texture
+         * @param requiredWidth The width of the target to render to
+         * @param requiredHeight The height of the target to render to
+         * @param forceFullscreenViewport Forces the viewport to be the entire texture/screen if true
+         * @param depthStencilTexture The depth stencil texture to use to render
+         */
+        public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean, depthStencilTexture?: InternalTexture): void {
             if (this._currentRenderTarget) {
                 this.unBindFramebuffer(this._currentRenderTarget);
             }
@@ -1939,6 +1961,15 @@
                     faceIndex = 0;
                 }
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, 0);
+
+                if (depthStencilTexture) {
+                    if (depthStencilTexture._generateStencilBuffer) {
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture, 0);
+                    }
+                    else {
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture, 0);
+                    }
+                }
             }
 
             if (this._cachedViewport && !forceFullscreenViewport) {
@@ -3637,6 +3668,212 @@
             }
         }
 
+        /**
+         * Updates a depth texture Comparison Mode and Function.
+         * If the comparison Function is equal to 0, the mode will be set to none.
+         * Otherwise, this only works in webgl 2 and requires a shadow sampler in the shader.
+         * @param texture The texture to set the comparison function for
+         * @param comparisonFunction The comparison function to set, 0 if no comparison required
+         */
+        public updateTextureComparisonFunction(texture: InternalTexture, comparisonFunction: number): void {
+            if (this.webGLVersion === 1) {
+                Tools.Error("WebGL 1 does not support texture comparison.");
+                return;
+            }
+
+            var gl = this._gl;
+
+            if (texture.isCube) {
+                this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);
+
+                if (comparisonFunction === 0) {
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, Engine.LEQUAL);
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE);
+                }
+                else {
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
+                    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
+                }
+
+                this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
+            } else {
+                this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
+
+                if (comparisonFunction === 0) {
+                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, Engine.LEQUAL);
+                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.NONE);
+                }
+                else {
+                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
+                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
+                }
+
+                this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
+            }
+
+            texture._comparisonFunction = comparisonFunction;
+        }
+
+        private _setupDepthStencilTexture(internalTexture: InternalTexture, size: number | { width: number, height: number }, generateStencil: boolean, bilinearFiltering: boolean, comparisonFunction: number) : void {
+            var width = (<{ width: number, height: number }>size).width || <number>size;
+            var height = (<{ width: number, height: number }>size).height || <number>size;
+            internalTexture.baseWidth = width;
+            internalTexture.baseHeight = height;
+            internalTexture.width = width;
+            internalTexture.height = height;
+            internalTexture.isReady = true;
+            internalTexture.samples = 1;
+            internalTexture.generateMipMaps = false;
+            internalTexture._generateDepthBuffer = true;
+            internalTexture._generateStencilBuffer = generateStencil;
+            internalTexture.samplingMode = bilinearFiltering ? Texture.NEAREST_SAMPLINGMODE : Texture.BILINEAR_SAMPLINGMODE;
+            internalTexture.type = Engine.TEXTURETYPE_UNSIGNED_INT;
+            internalTexture._comparisonFunction = comparisonFunction;
+
+            var gl = this._gl;
+            var target = internalTexture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
+            var samplingParameters = getSamplingParameters(internalTexture.samplingMode, false, gl);
+            gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, samplingParameters.mag);
+            gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, samplingParameters.min);
+            gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+            gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+            if (comparisonFunction === 0) {
+                gl.texParameteri(target, gl.TEXTURE_COMPARE_FUNC, Engine.LEQUAL);
+                gl.texParameteri(target, gl.TEXTURE_COMPARE_MODE, gl.NONE);
+            }
+            else {
+                gl.texParameteri(target, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
+                gl.texParameteri(target, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
+            }
+        }
+
+        /**
+         * Creates a depth stencil texture.
+         * This is only available in WebGL 2 or with the depth texture extension available.
+         * @param size The size of face edge in the texture.
+         * @param options The options defining the texture.
+         * @returns The texture
+         */
+        public createDepthStencilTexture(size: number | { width: number, height: number }, options: DepthTextureCreationOptions) : InternalTexture {
+            var internalTexture = new InternalTexture(this, InternalTexture.DATASOURCE_DEPTHTEXTURE);
+
+            if (!this._caps.depthTextureExtension) {
+                Tools.Error("Depth texture is not supported by your browser or hardware.");
+                return internalTexture;
+            }
+
+            var internalOptions = {
+                bilinearFiltering: false,
+                comparisonFunction: 0,
+                generateStencil: false,
+                ...options
+            }
+
+            var gl = this._gl;
+            this._bindTextureDirectly(gl.TEXTURE_2D, internalTexture, true);
+
+            this._setupDepthStencilTexture(internalTexture, size, internalOptions.generateStencil, internalOptions.bilinearFiltering, internalOptions.comparisonFunction);
+
+            if (this.webGLVersion > 1) {
+                if (internalOptions.generateStencil) {
+                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH24_STENCIL8, internalTexture.width, internalTexture.height, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null);
+                }
+                else {
+                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT24, internalTexture.width, internalTexture.height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
+                }
+            }
+            else {
+                if (internalOptions.generateStencil) {
+                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_STENCIL, internalTexture.width, internalTexture.height, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null);
+                }
+                else {
+                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, internalTexture.width, internalTexture.height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
+                }
+            }
+
+            this._bindTextureDirectly(gl.TEXTURE_2D, null);
+
+            return internalTexture;
+        }
+
+        /**
+         * Creates a depth stencil cube texture.
+         * This is only available in WebGL 2.
+         * @param size The size of face edge in the cube texture.
+         * @param options The options defining the cube texture.
+         * @returns The cube texture
+         */
+        public createDepthStencilCubeTexture(size: number, options: DepthTextureCreationOptions) : InternalTexture {
+            var internalTexture = new InternalTexture(this, InternalTexture.DATASOURCE_UNKNOWN);
+            internalTexture.isCube = true;
+
+            if (this.webGLVersion === 1) {
+                Tools.Error("Depth cube texture is not supported by WebGL 1.");
+                return internalTexture;
+            }
+
+            var internalOptions = {
+                bilinearFiltering: false,
+                comparisonFunction: 0,
+                generateStencil: false,
+                ...options
+            }
+
+            var gl = this._gl;
+            this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, internalTexture, true);
+
+            this._setupDepthStencilTexture(internalTexture, size, internalOptions.generateStencil, internalOptions.bilinearFiltering, internalOptions.comparisonFunction);
+
+            // Create the depth/stencil buffer
+            for (var face = 0; face < 6; face++) {
+                if (internalOptions.generateStencil) {
+                    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, gl.DEPTH24_STENCIL8, size, size, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null);
+                }
+                else {
+                    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, gl.DEPTH_COMPONENT24, size, size, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
+                }
+            }
+
+            this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
+
+            return internalTexture;
+        }
+
+        /**
+         * Sets the frame buffer Depth / Stencil attachement of the render target to the defined depth stencil texture.
+         * @param renderTarget The render target to set the frame buffer for
+         */
+        public setFrameBufferDepthStencilTexture(renderTarget: RenderTargetTexture): void {
+            // Create the framebuffer
+            var internalTexture = renderTarget.getInternalTexture();
+            if (!internalTexture || !internalTexture._framebuffer || !renderTarget.depthStencilTexture) {
+                return;
+            }
+
+            var gl = this._gl;
+            var depthStencilTexture = renderTarget.depthStencilTexture;
+
+            this.bindUnboundFramebuffer(internalTexture._framebuffer);
+            if (depthStencilTexture.isCube) {
+                if (depthStencilTexture._generateStencilBuffer) {
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture, 0);
+                }
+                else {
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture, 0);
+                }
+            }
+            else {
+                if (depthStencilTexture._generateStencilBuffer) {
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture, 0);
+                }
+                else {
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture, 0);
+                }
+            }
+            this.bindUnboundFramebuffer(null);
+        }
+
         public createRenderTargetTexture(size: number | { width: number, height: number }, options: boolean | RenderTargetCreationOptions): InternalTexture {
             let fullOptions = new RenderTargetCreationOptions();
 

+ 4 - 0
src/Engine/babylon.webgl2.ts

@@ -5,8 +5,12 @@
 
 interface WebGLRenderingContext {
     readonly RASTERIZER_DISCARD: number;
+    readonly DEPTH_COMPONENT24: number;
     readonly TEXTURE_3D: number;
     readonly TEXTURE_2D_ARRAY: number;
+    readonly TEXTURE_COMPARE_FUNC: number;
+    readonly TEXTURE_COMPARE_MODE: number;
+    readonly COMPARE_REF_TO_TEXTURE: number;
     readonly TEXTURE_WRAP_R: number;
 
     texImage3D(target: number, level: number, internalformat: number, width: number, height: number, depth: number, border: number, format: number, type: number, pixels: ArrayBufferView | null): void;

+ 22 - 0
src/Materials/Textures/babylon.internalTexture.ts

@@ -49,6 +49,10 @@ module BABYLON {
          * Texture content is raw 3D data
          */
         public static DATASOURCE_RAW3D = 10;
+        /**
+         * Texture content is a depth texture
+         */
+        public static DATASOURCE_DEPTHTEXTURE = 11;
 
         /**
          * Defines if the texture is ready
@@ -180,6 +184,8 @@ module BABYLON {
         /** @ignore */
         public _generateDepthBuffer: boolean;
         /** @ignore */
+        public _comparisonFunction: number = 0;
+        /** @ignore */
         public _sphericalPolynomial: Nullable<SphericalPolynomial>;
         /** @ignore */
         public _lodGenerationScale: number;
@@ -311,6 +317,22 @@ module BABYLON {
 
                     this.isReady = true;
                     return;
+                case InternalTexture.DATASOURCE_DEPTHTEXTURE:
+                    let depthTextureOptions = {
+                        bilinearFiltering: this.samplingMode !== Texture.BILINEAR_SAMPLINGMODE,
+                        comparisonFunction: this._comparisonFunction,
+                        generateStencil: this._generateStencilBuffer,
+                    };
+
+                    if (this.isCube) {
+                        proxy = this._engine.createDepthStencilTexture({ width: this.width, height: this.height }, depthTextureOptions);
+                    } else {
+                        proxy = this._engine.createDepthStencilCubeTexture(this.width, depthTextureOptions);
+                    }
+                    proxy._swapAndDie(this);
+
+                    this.isReady = true;
+                    return;
 
                 case InternalTexture.DATASOURCE_CUBE:
                     proxy = this._engine.createCubeTexture(this.url, null, this._files, !this.generateMipMaps, () => {

+ 23 - 1
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -156,6 +156,28 @@
             return this._boundingBoxSize;
         }
 
+        /**
+         * In case the RTT has been created with a depth texture, get the associated 
+         * depth texture.
+         * Otherwise, return null.
+         */
+        public depthStencilTexture: Nullable<InternalTexture>;
+
+        /**
+         * Instantiate a render target texture. This is mainly to render of screen the scene to for instance apply post processse
+         * or used a shadow, depth texture...
+         * @param name The friendly name of the texture
+         * @param size The size of the RTT (number if square, or {with: number, height:number} or {ratio:} to define a ratio from the main scene)
+         * @param scene The scene the RTT belongs to. The latest created scene will be used if not precised.
+         * @param generateMipMaps True if mip maps need to be generated after render.
+         * @param doNotChangeAspectRatio True to not change the aspect ratio of the scene in the RTT
+         * @param type The type of the buffer in the RTT (int, half float, float...)
+         * @param isCube True if a cube texture needs to be created
+         * @param samplingMode The sampling mode to be usedwith the render target (Linear, Nearest...)
+         * @param generateDepthBuffer True to generate a depth buffer
+         * @param generateStencilBuffer True to generate a stencil buffer
+         * @param isMulti True if multiple textures need to be created (Draw Buffers)
+         */
         constructor(name: string, size: number | {width: number, height: number} | {ratio: number}, scene: Nullable<Scene>, generateMipMaps?: boolean, doNotChangeAspectRatio: boolean = true, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, public isCube = false, samplingMode = Texture.TRILINEAR_SAMPLINGMODE, generateDepthBuffer = true, generateStencilBuffer = false, isMulti = false) {
             super(null, scene, !generateMipMaps);
             scene = this.getScene();
@@ -551,7 +573,7 @@
             }
             else if (!useCameraPostProcess || !scene.postProcessManager._prepareFrame(this._texture)) {
                 if (this._texture) {
-                    engine.bindFramebuffer(this._texture, this.isCube ? faceIndex : undefined, undefined, undefined, this.ignoreCameraViewport);
+                    engine.bindFramebuffer(this._texture, this.isCube ? faceIndex : undefined, undefined, undefined, this.ignoreCameraViewport, this.depthStencilTexture ? this.depthStencilTexture : undefined);
                 }
             }
 

+ 1 - 0
src/babylon.mixins.ts

@@ -60,6 +60,7 @@ interface WebGLRenderingContext {
     RED: number;
     RG: number;
 
+    UNSIGNED_INT_24_8: number;
     DEPTH24_STENCIL8: number;
 
     /* Multiple Render Targets */