diff --git a/examples/screenshots/webgpu_backdrop_water.jpg b/examples/screenshots/webgpu_backdrop_water.jpg index d7d0acc9a3741d..ebc76f3a816d7f 100644 Binary files a/examples/screenshots/webgpu_backdrop_water.jpg and b/examples/screenshots/webgpu_backdrop_water.jpg differ diff --git a/examples/webgpu_backdrop_water.html b/examples/webgpu_backdrop_water.html index c381a93be977eb..b73d9a996b4bd8 100644 --- a/examples/webgpu_backdrop_water.html +++ b/examples/webgpu_backdrop_water.html @@ -191,7 +191,7 @@ // renderer - renderer = new THREE.WebGPURenderer( /*{ antialias: true }*/ ); + renderer = new THREE.WebGPURenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setAnimationLoop( animate ); diff --git a/src/core/RenderTarget.js b/src/core/RenderTarget.js index ab1c352b7733ff..30ce82d62558b0 100644 --- a/src/core/RenderTarget.js +++ b/src/core/RenderTarget.js @@ -54,6 +54,7 @@ class RenderTarget extends EventDispatcher { this.textures[ i ] = texture.clone(); this.textures[ i ].isRenderTargetTexture = true; + this.textures[ i ].renderTarget = this; } @@ -63,6 +64,7 @@ class RenderTarget extends EventDispatcher { this.resolveDepthBuffer = options.resolveDepthBuffer; this.resolveStencilBuffer = options.resolveStencilBuffer; + this._depthTexture = null; this.depthTexture = options.depthTexture; this.samples = options.samples; @@ -81,6 +83,21 @@ class RenderTarget extends EventDispatcher { } + set depthTexture( current ) { + + if ( this._depthTexture !== null ) this._depthTexture.renderTarget = null; + if ( current !== null ) current.renderTarget = this; + + this._depthTexture = current; + + } + + get depthTexture() { + + return this._depthTexture; + + } + setSize( width, height, depth = 1 ) { if ( this.width !== width || this.height !== height || this.depth !== depth ) { @@ -129,6 +146,7 @@ class RenderTarget extends EventDispatcher { this.textures[ i ] = source.textures[ i ].clone(); this.textures[ i ].isRenderTargetTexture = true; + this.textures[ i ].renderTarget = this; } diff --git a/src/nodes/display/PassNode.js b/src/nodes/display/PassNode.js index 31277f041e01e3..ff69d888965660 100644 --- a/src/nodes/display/PassNode.js +++ b/src/nodes/display/PassNode.js @@ -169,7 +169,6 @@ class PassNode extends TempNode { const refTexture = this.renderTarget.texture; texture = refTexture.clone(); - texture.isRenderTargetTexture = true; texture.name = name; this._textures[ name ] = texture; @@ -189,7 +188,6 @@ class PassNode extends TempNode { if ( texture === undefined ) { texture = this.getTexture( name ).clone(); - texture.isRenderTargetTexture = true; this._previousTextures[ name ] = texture; @@ -302,8 +300,6 @@ class PassNode extends TempNode { } - this.renderTarget.depthTexture.isMultisampleRenderTargetTexture = this.renderTarget.samples > 1; - return this.scope === PassNode.COLOR ? this.getTextureNode() : this.getLinearDepthNode(); } diff --git a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js index 74fb78f2445c2e..170f654b73680b 100644 --- a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -311,7 +311,9 @@ class WGSLNodeBuilder extends NodeBuilder { let textureDimensionsParams; - if ( texture.isMultisampleRenderTargetTexture === true ) { + const { primarySamples } = this.renderer.backend.utils.getTextureSampleData( texture ); + + if ( primarySamples > 1 ) { textureDimensionsParams = textureProperty; @@ -388,7 +390,7 @@ class WGSLNodeBuilder extends NodeBuilder { return this.getComponentTypeFromTexture( texture ) !== 'float' || ( ! this.isAvailable( 'float32Filterable' ) && texture.isDataTexture === true && texture.type === FloatType ) || ( this.isSampleCompare( texture ) === false && texture.minFilter === NearestFilter && texture.magFilter === NearestFilter ) || - texture.isMultisampleRenderTargetTexture === true; + this.renderer.backend.utils.getTextureSampleData( texture ).primarySamples > 1; } @@ -1120,7 +1122,9 @@ ${ flowData.code } let multisampled = ''; - if ( texture.isMultisampleRenderTargetTexture === true ) { + const { primarySamples } = this.renderer.backend.utils.getTextureSampleData( texture ); + + if ( primarySamples > 1 ) { multisampled = '_multisampled'; diff --git a/src/renderers/webgpu/utils/WebGPUBindingUtils.js b/src/renderers/webgpu/utils/WebGPUBindingUtils.js index 52efd08d2c0b88..ba349d46592520 100644 --- a/src/renderers/webgpu/utils/WebGPUBindingUtils.js +++ b/src/renderers/webgpu/utils/WebGPUBindingUtils.js @@ -107,10 +107,18 @@ class WebGPUBindingUtils { const texture = {}; // GPUTextureBindingLayout - if ( binding.texture.isMultisampleRenderTargetTexture === true ) { + const { primarySamples } = backend.utils.getTextureSampleData( binding.texture ); + + if ( primarySamples > 1 ) { texture.multisampled = true; + if ( ! binding.texture.isDepthTexture ) { + + texture.sampleType = GPUTextureSampleType.UnfilterableFloat; + + } + } if ( binding.texture.isDepthTexture ) { diff --git a/src/renderers/webgpu/utils/WebGPUTextureUtils.js b/src/renderers/webgpu/utils/WebGPUTextureUtils.js index 0b75594e43be01..476c86784b8338 100644 --- a/src/renderers/webgpu/utils/WebGPUTextureUtils.js +++ b/src/renderers/webgpu/utils/WebGPUTextureUtils.js @@ -146,11 +146,7 @@ class WebGPUTextureUtils { textureData.format = format; - let sampleCount = options.sampleCount !== undefined ? options.sampleCount : 1; - - sampleCount = backend.utils.getSampleCount( sampleCount ); - - const primarySampleCount = texture.isRenderTargetTexture && ! texture.isMultisampleRenderTargetTexture ? 1 : sampleCount; + const { samples, primarySamples, isMSAA } = backend.utils.getTextureSampleData( texture ); let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC; @@ -174,7 +170,7 @@ class WebGPUTextureUtils { depthOrArrayLayers: depth, }, mipLevelCount: levels, - sampleCount: primarySampleCount, + sampleCount: primarySamples, dimension: dimension, format: format, usage: usage @@ -208,12 +204,12 @@ class WebGPUTextureUtils { } - if ( texture.isRenderTargetTexture && sampleCount > 1 && ! texture.isMultisampleRenderTargetTexture ) { + if ( isMSAA ) { const msaaTextureDescriptorGPU = Object.assign( {}, textureDescriptorGPU ); msaaTextureDescriptorGPU.label = msaaTextureDescriptorGPU.label + '-msaa'; - msaaTextureDescriptorGPU.sampleCount = sampleCount; + msaaTextureDescriptorGPU.sampleCount = samples; textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU ); @@ -336,7 +332,7 @@ class WebGPUTextureUtils { depthTexture.image.width = width; depthTexture.image.height = height; - this.createTexture( depthTexture, { sampleCount: backend.utils.getSampleCount( backend.renderer.samples ), width, height } ); + this.createTexture( depthTexture, { width, height } ); return backend.get( depthTexture ).texture; diff --git a/src/renderers/webgpu/utils/WebGPUUtils.js b/src/renderers/webgpu/utils/WebGPUUtils.js index f7ba94556d98e4..a055059c6e15fc 100644 --- a/src/renderers/webgpu/utils/WebGPUUtils.js +++ b/src/renderers/webgpu/utils/WebGPUUtils.js @@ -36,6 +36,36 @@ class WebGPUUtils { } + getTextureSampleData( texture ) { + + let samples; + + if ( texture.isFramebufferTexture ) { + + samples = 1; + + } else if ( texture.isDepthTexture && ! texture.renderTarget ) { + + const renderer = this.backend.renderer; + const renderTarget = renderer.getRenderTarget(); + + samples = renderTarget ? renderTarget.samples : renderer.samples; + + } else if ( texture.renderTarget ) { + + samples = texture.renderTarget.samples; + + } + + samples = samples || 1; + + const isMSAA = samples > 1 && texture.renderTarget !== null && ( texture.isDepthTexture !== true && texture.isFramebufferTexture !== true ); + const primarySamples = isMSAA ? 1 : samples; + + return { samples, primarySamples, isMSAA }; + + } + getCurrentColorFormat( renderContext ) { let format; diff --git a/src/textures/Texture.js b/src/textures/Texture.js index c5168d5621d357..9d300bdbdca38b 100644 --- a/src/textures/Texture.js +++ b/src/textures/Texture.js @@ -69,6 +69,7 @@ class Texture extends EventDispatcher { this.version = 0; this.onUpdate = null; + this.renderTarget = null; // assign texture to a render target this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not this.pmremVersion = 0; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) @@ -134,6 +135,9 @@ class Texture extends EventDispatcher { this.unpackAlignment = source.unpackAlignment; this.colorSpace = source.colorSpace; + this.renderTarget = source.renderTarget; + this.isRenderTargetTexture = source.isRenderTargetTexture; + this.userData = JSON.parse( JSON.stringify( source.userData ) ); this.needsUpdate = true;