浏览代码

Add support for depth/stencil textures

Popov72 4 年之前
父节点
当前提交
b1a6f431f9

+ 12 - 3
src/Engines/engine.ts

@@ -749,6 +749,14 @@ export class Engine extends ThinEngine {
     }
 
     /**
+     * Gets a boolean indicating if depth testing is enabled
+     * @param enable defines the state to set
+     */
+    public getDepthBuffer(): boolean {
+        return this._depthCullingState.depthTest;
+    }
+
+    /**
      * Enable or disable depth buffering
      * @param enable defines the state to set
      */
@@ -1152,8 +1160,9 @@ export class Engine extends ThinEngine {
      * @param channel The texture channel
      * @param uniform The uniform to set
      * @param texture The render target texture containing the depth stencil texture to apply
+     * @param name The texture name
      */
-    public setDepthStencilTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<RenderTargetTexture>): void {
+    public setDepthStencilTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<RenderTargetTexture>, name?: string): void {
         if (channel === undefined) {
             return;
         }
@@ -1163,10 +1172,10 @@ export class Engine extends ThinEngine {
         }
 
         if (!texture || !texture.depthStencilTexture) {
-            this._setTexture(channel, null);
+            this._setTexture(channel, null, undefined, undefined, name);
         }
         else {
-            this._setTexture(channel, texture, false, true);
+            this._setTexture(channel, texture, false, true, name);
         }
     }
 

+ 6 - 0
src/Engines/engineFeatures.ts

@@ -7,4 +7,10 @@ export interface EngineFeatures {
 
     /** Indicates that framebuffers have Y going from top to bottom for increasing y values */
     framebuffersHaveYTopToBottom: boolean;
+
+    /** Indicates that the engine support handling depth/stencil textures */
+    supportDepthStencilTexture: boolean;
+
+    /** Indicates that the engine support shadow samplers */
+    supportShadowSamplers: boolean;
 }

+ 5 - 1
src/Engines/thinEngine.ts

@@ -178,6 +178,8 @@ export class ThinEngine {
         forceBitmapOverHTMLImageElement: false,
         supportRenderAndCopyToLodForFloatTextures: false,
         framebuffersHaveYTopToBottom: false,
+        supportDepthStencilTexture: false,
+        supportShadowSamplers: false,
     };
 
     /**
@@ -715,6 +717,8 @@ export class ThinEngine {
         }
 
         ThinEngine.Features.supportRenderAndCopyToLodForFloatTextures = this._webGLVersion !== 1;
+        ThinEngine.Features.supportDepthStencilTexture = this._webGLVersion !== 1;
+        ThinEngine.Features.supportShadowSamplers = this._webGLVersion !== 1;
 
         // Ensures a consistent color space unpacking of textures cross browser.
         this._gl.pixelStorei(this._gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, this._gl.NONE);
@@ -3741,7 +3745,7 @@ export class ThinEngine {
         return this._gl.REPEAT;
     }
 
-    protected _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false, depthStencilTexture = false): boolean {
+    protected _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false, depthStencilTexture = false, name = ""): boolean {
         // Not ready?
         if (!texture) {
             if (this._boundTexturesCache[channel] != null) {

+ 85 - 23
src/Engines/webgpuEngine.ts

@@ -31,6 +31,7 @@ import { WebGPUHardwareTexture } from './WebGPU/webgpuHardwareTexture';
 import { IColor4Like } from '../Maths/math.like';
 
 declare type VideoTexture = import("../Materials/Textures/videoTexture").VideoTexture;
+declare type RenderTargetTexture = import("../Materials/Textures/renderTargetTexture").RenderTargetTexture;
 
 // TODO WEBGPU remove when not needed anymore
 function assert(condition: any, msg?: string): asserts condition {
@@ -230,10 +231,12 @@ export class WebGPUEngine extends Engine {
         ThinEngine.Features.forceBitmapOverHTMLImageElement = true;
         ThinEngine.Features.supportRenderAndCopyToLodForFloatTextures = false; // TODO WEBGPU should be true but needs RTT support first for env texture to be generated correctly with this flag on
         ThinEngine.Features.framebuffersHaveYTopToBottom = true;
+        ThinEngine.Features.supportDepthStencilTexture = true;
+        ThinEngine.Features.supportShadowSamplers = true;
 
         options.deviceDescriptor = options.deviceDescriptor || { };
         options.swapChainFormat = options.swapChainFormat || WebGPUConstants.TextureFormat.BGRA8Unorm;
-        options.antialiasing = false;//options.antialiasing === undefined ? true : options.antialiasing;
+        options.antialiasing = false; //options.antialiasing === undefined ? true : options.antialiasing;
         options.stencil = options.stencil ?? true;
 
         Logger.Log(`Babylon.js v${Engine.Version} - WebGPU engine`);
@@ -465,7 +468,7 @@ export class WebGPUEngine extends Engine {
             mipLevelCount: 1,
             sampleCount: this._mainPassSampleCount,
             dimension: WebGPUConstants.TextureDimension.E2d,
-            format: this.isStencilEnable ? WebGPUConstants.TextureFormat.Depth24PlusStencil8 : WebGPUConstants.TextureFormat.Depth32Float,
+            format: this._getDepthTextureFormat(),
             usage:  WebGPUConstants.TextureUsage.OutputAttachment
         };
 
@@ -526,7 +529,7 @@ export class WebGPUEngine extends Engine {
             this._alphaMode = Constants.ALPHA_ADD;
             this._alphaEquation = Constants.ALPHA_DISABLE;
 
-            this._colorWrite = true;
+            this.__colorWrite = true;
             this._colorWriteChanged = true;
         }
 
@@ -986,6 +989,10 @@ export class WebGPUEngine extends Engine {
     //                              Textures
     //------------------------------------------------------------------------------
 
+    private _getDepthTextureFormat(): GPUTextureFormat {
+        return this.isStencilEnable ? WebGPUConstants.TextureFormat.Depth24PlusStencil8 : WebGPUConstants.TextureFormat.Depth32Float;
+    }
+
     /** @hidden */
     public _createHardwareTexture(): HardwareTextureWrapper {
         return new WebGPUHardwareTexture();
@@ -1467,6 +1474,10 @@ export class WebGPUEngine extends Engine {
     }
 
     public setTexture(channel: number, _: Nullable<WebGLUniformLocation>, texture: Nullable<BaseTexture>, name: string): void {
+        this._setTexture(channel, texture, false, false, name);
+    }
+
+    protected _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false, depthStencilTexture = false, name = ""): boolean {
         if (this._currentEffect) {
             const webgpuPipelineContext = this._currentEffect._pipelineContext as WebGPUPipelineContext;
             if (!texture) {
@@ -1474,10 +1485,51 @@ export class WebGPUEngine extends Engine {
                     webgpuPipelineContext.bindGroups = null as any; // the bind groups need to be rebuilt (at least the bind group owning this texture, but it's easier to just have them all rebuilt)
                 }
                 webgpuPipelineContext.samplers[name] = null;
-                return;
+                return false;
+            }
+
+            // Video
+            if ((<VideoTexture>texture).video) {
+                this._activeChannel = channel;
+                (<VideoTexture>texture).update();
+            } else if (texture.delayLoadState === Constants.DELAYLOADSTATE_NOTLOADED) { // Delay loading
+                texture.delayLoad();
+                return false;
+            }
+
+            let internalTexture: InternalTexture;
+            if (depthStencilTexture) {
+                internalTexture = (<RenderTargetTexture>texture).depthStencilTexture!;
+            }
+            else if (texture.isReady()) {
+                internalTexture = <InternalTexture>texture.getInternalTexture();
+            }
+            else if (texture.isCube) {
+                internalTexture = this.emptyCubeTexture;
+            }
+            else if (texture.is3D) {
+                internalTexture = this.emptyTexture3D;
+            }
+            else if (texture.is2DArray) {
+                internalTexture = this.emptyTexture2DArray;
+            }
+            else {
+                internalTexture = this.emptyTexture;
+            }
+
+            if (internalTexture && !internalTexture.isMultiview) {
+                // CUBIC_MODE and SKYBOX_MODE both require CLAMP_TO_EDGE.  All other modes use REPEAT.
+                if (internalTexture.isCube && internalTexture._cachedCoordinatesMode !== texture.coordinatesMode) {
+                    internalTexture._cachedCoordinatesMode = texture.coordinatesMode;
+
+                    const textureWrapMode = (texture.coordinatesMode !== Constants.TEXTURE_CUBIC_MODE && texture.coordinatesMode !== Constants.TEXTURE_SKYBOX_MODE) ? Constants.TEXTURE_WRAP_ADDRESSMODE : Constants.TEXTURE_CLAMP_ADDRESSMODE;
+                    texture.wrapU = textureWrapMode;
+                    texture.wrapV = textureWrapMode;
+                }
+
+                this._setAnisotropicLevel(0, internalTexture, texture.anisotropicFilteringLevel);
             }
 
-            const internalTexture = texture!.getInternalTexture();
             if (internalTexture) {
                 internalTexture._cachedWrapU = texture.wrapU;
                 internalTexture._cachedWrapV = texture.wrapV;
@@ -1491,15 +1543,23 @@ export class WebGPUEngine extends Engine {
             }
 
             this._setInternalTexture(name, internalTexture);
+        }
 
-            // Video
-            if ((<VideoTexture>texture).video) {
-                this._activeChannel = channel;
-                (<VideoTexture>texture).update();
-            } else if (texture.delayLoadState === Constants.DELAYLOADSTATE_NOTLOADED) { // Delay loading
-                texture.delayLoad();
-                return;
-            }
+        return true;
+    }
+
+    /** @hidden */
+    public _setAnisotropicLevel(target: number, internalTexture: InternalTexture, anisotropicFilteringLevel: number) {
+        if (internalTexture.samplingMode !== Constants.TEXTURE_LINEAR_LINEAR_MIPNEAREST
+            && internalTexture.samplingMode !== Constants.TEXTURE_LINEAR_LINEAR_MIPLINEAR
+            && internalTexture.samplingMode !== Constants.TEXTURE_LINEAR_LINEAR) {
+            anisotropicFilteringLevel = 1; // Forcing the anisotropic to 1 because else webgl will force filters to linear
+        }
+
+        if (internalTexture._cachedAnisotropicFilteringLevel !== anisotropicFilteringLevel) {
+            //this._setTextureParameterFloat(target, anisotropicFilterExtension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(anisotropicFilteringLevel, this._caps.maxAnisotropy), internalTexture);
+            internalTexture._cachedAnisotropicFilteringLevel = anisotropicFilteringLevel;
+            console.warn("_setAnisotropicLevel not implemented yet");
         }
     }
 
@@ -1546,7 +1606,7 @@ export class WebGPUEngine extends Engine {
 
         const textureUsages =
             texture._source === InternalTextureSource.RenderTarget ? WebGPUConstants.TextureUsage.Sampled | WebGPUConstants.TextureUsage.OutputAttachment :
-            texture._source === InternalTextureSource.Depth ? /*WebGPUConstants.TextureUsage.Sampled |*/ WebGPUConstants.TextureUsage.OutputAttachment : -1;
+            texture._source === InternalTextureSource.Depth ? WebGPUConstants.TextureUsage.Sampled | WebGPUConstants.TextureUsage.OutputAttachment : -1;
 
         const generateMipMaps = texture._source === InternalTextureSource.RenderTarget ? false : texture.generateMipMaps;
 
@@ -1896,7 +1956,7 @@ export class WebGPUEngine extends Engine {
             ...options
         };
 
-        internalTexture.format = internalOptions.generateStencil ? Constants.TEXTUREFORMAT_DEPTH24_STENCIL8 : Constants.TEXTUREFORMAT_DEPTH32_FLOAT;
+        internalTexture.format = internalOptions.generateStencil && this.isStencilEnable ? Constants.TEXTUREFORMAT_DEPTH24_STENCIL8 : Constants.TEXTUREFORMAT_DEPTH32_FLOAT;
 
         this._setupDepthStencilTexture(internalTexture, size, internalOptions.generateStencil, internalOptions.bilinearFiltering, internalOptions.comparisonFunction);
 
@@ -2000,7 +2060,9 @@ export class WebGPUEngine extends Engine {
         const gpuTexture = (internalTexture._hardwareTexture as WebGPUHardwareTexture).underlyingResource!;
 
         const colorTextureView = gpuTexture.createView(this._currentRenderTargetViewDescriptor);
-        const depthTexture = internalTexture._depthStencilTexture?._hardwareTexture?.underlyingResource;
+
+        const depthStencilTexture = internalTexture._depthStencilTexture;
+        const gpuDepthStencilTexture = depthStencilTexture?._hardwareTexture?.underlyingResource;
 
         const renderPass = this._renderTargetEncoder.beginRenderPass({
             colorAttachments: [{
@@ -2008,11 +2070,11 @@ export class WebGPUEngine extends Engine {
                 loadValue: clearColor !== null ? clearColor : WebGPUConstants.LoadOp.Load,
                 storeOp: WebGPUConstants.StoreOp.Store
             }],
-            depthStencilAttachment: (internalTexture._generateDepthBuffer || internalTexture._generateStencilBuffer) && depthTexture ? {
-                attachment: (internalTexture._depthStencilTexture?._hardwareTexture as WebGPUHardwareTexture).view!,
-                depthLoadValue: clearDepth && internalTexture._generateDepthBuffer ? this._clearDepthValue : WebGPUConstants.LoadOp.Load,
+            depthStencilAttachment: depthStencilTexture && gpuDepthStencilTexture ? {
+                attachment: (depthStencilTexture._hardwareTexture as WebGPUHardwareTexture).view!,
+                depthLoadValue: clearDepth && depthStencilTexture._generateDepthBuffer ? this._clearDepthValue : WebGPUConstants.LoadOp.Load,
                 depthStoreOp: WebGPUConstants.StoreOp.Store,
-                stencilLoadValue: clearStencil && internalTexture._generateStencilBuffer ? this._clearStencilValue : WebGPUConstants.LoadOp.Load,
+                stencilLoadValue: clearStencil && depthStencilTexture._generateStencilBuffer ? this._clearStencilValue : WebGPUConstants.LoadOp.Load,
                 stencilStoreOp: WebGPUConstants.StoreOp.Store,
             } : undefined
         });
@@ -2121,7 +2183,7 @@ export class WebGPUEngine extends Engine {
 
     public unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps = false, onBeforeUnbind?: () => void): void {
         // TODO WEBGPU remove the assert debugging code
-        assert(texture === this._currentRenderTarget);
+        assert(this._currentRenderTarget === null || (this._currentRenderTarget !== null && texture === this._currentRenderTarget), "unBindFramebuffer - the texture we wan't to unbind is not the same than the currentRenderTarget! texture=" + texture + ", this._currentRenderTarget=" + this._currentRenderTarget);
 
         this._currentRenderTarget = null;
 
@@ -2262,8 +2324,8 @@ export class WebGPUEngine extends Engine {
 
         return {
             depthWriteEnabled: this.getDepthWrite(),
-            depthCompare: this._getCompareFunction(this.getDepthFunction()),
-            format: this._currentRenderTarget && this._currentRenderTarget._depthStencilTexture ? this._getWebGPUTextureFormat(-1, this._currentRenderTarget._depthStencilTexture.format) : WebGPUConstants.TextureFormat.Depth24PlusStencil8,
+            depthCompare: this.getDepthBuffer() ? this._getCompareFunction(this.getDepthFunction()) : WebGPUConstants.CompareFunction.Always,
+            format: this._currentRenderTarget && this._currentRenderTarget._depthStencilTexture ? this._getWebGPUTextureFormat(-1, this._currentRenderTarget._depthStencilTexture.format) : this._getDepthTextureFormat(),
             stencilFront: stencilFrontBack,
             stencilBack: stencilFrontBack,
             stencilReadMask: this._stencilState.stencilFuncMask,

+ 3 - 3
src/Lights/Shadows/shadowGenerator.ts

@@ -28,6 +28,7 @@ import { Observable } from '../../Misc/observable';
 import { _DevTools } from '../../Misc/devTools';
 import { EffectFallbacks } from '../../Materials/effectFallbacks';
 import { RenderingManager } from '../../Rendering/renderingManager';
+import { ThinEngine } from '../../Engines/thinEngine';
 
 const tmpMatrix = new Matrix(),
       tmpMatrix2 = new Matrix();
@@ -413,7 +414,7 @@ export class ShadowGenerator implements IShadowGenerator {
 
         // Weblg1 fallback for PCF.
         if (value === ShadowGenerator.FILTER_PCF || value === ShadowGenerator.FILTER_PCSS) {
-            if (this._scene.getEngine().webGLVersion === 1) {
+            if (!ThinEngine.Features.supportShadowSamplers) {
                 this.usePoissonSampling = true;
                 return;
             }
@@ -860,8 +861,7 @@ export class ShadowGenerator implements IShadowGenerator {
     }
 
     protected _createTargetRenderTexture(): void {
-        let engine = this._scene.getEngine();
-        if (engine.webGLVersion > 1) {
+        if (ThinEngine.Features.supportDepthStencilTexture) {
             this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube(), undefined, false, false);
             this._shadowMap.createDepthStencilTexture(Constants.LESS, true);
         }

+ 1 - 1
src/Materials/effect.ts

@@ -819,7 +819,7 @@ export class Effect implements IDisposable {
      * @param texture Texture to set.
      */
     public setDepthStencilTexture(channel: string, texture: Nullable<RenderTargetTexture>): void {
-        this._engine.setDepthStencilTexture(this._samplers[channel], this._uniforms[channel], texture);
+        this._engine.setDepthStencilTexture(this._samplers[channel], this._uniforms[channel], texture, channel);
     }
 
     /**

+ 3 - 3
src/Shaders/ShadersInclude/hdrFilteringFunctions.fx

@@ -1,7 +1,7 @@
 #ifdef NUM_SAMPLES
     #if NUM_SAMPLES > 0
 
-    #ifdef WEBGL2
+    #if defined(WEBGL2) || defined(WEBGPU)
         // https://learnopengl.com/PBR/IBL/Specular-IBL
         // Hammersley
         float radicalInverse_VdC(uint bits) 
@@ -184,7 +184,7 @@
             float dim0 = filteringInfo.x;
             float omegaP = (4. * PI) / (6. * dim0 * dim0);
 
-            #ifdef WEBGL2
+            #if defined(WEBGL2) || defined(WEBGPU)
             for(uint i = 0u; i < NUM_SAMPLES; ++i)
             #else
             for(int i = 0; i < NUM_SAMPLES; ++i)
@@ -243,7 +243,7 @@
             float omegaP = (4. * PI) / (6. * dim0 * dim0);
 
             float weight = 0.;
-            #ifdef WEBGL2
+            #if defined(WEBGL2) || defined(WEBGPU)
             for(uint i = 0u; i < NUM_SAMPLES; ++i)
             #else
             for(int i = 0; i < NUM_SAMPLES; ++i)

+ 4 - 2
src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx

@@ -113,7 +113,7 @@
         return esm;
     }
 
-    #ifdef WEBGL2
+    #if defined(WEBGL2) || defined(WEBGPU)
         #define inline
         float computeShadowCSM(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray shadowSampler, float darkness, float frustumEdgeFalloff)
         {
@@ -249,7 +249,7 @@
         }
     }
 
-    #ifdef WEBGL2
+    #if defined(WEBGL2) || defined(WEBGPU)
         #define GREATEST_LESS_THAN_ONE 0.99999994
 
         // Shadow PCF kernel size 1 with a single tap (lowest quality)
@@ -420,6 +420,8 @@
                 vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
                 vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
 
+                //uvDepth.y = 1.0 - uvDepth.y;
+
                 vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x;	// uv in texel units
                 uv += 0.5;											// offset of half to be in the center of the texel
                 vec2 st = fract(uv);								// how far from the center