From 28c2613b4d96f93e2dbf8b611864297d71a50adf Mon Sep 17 00:00:00 2001 From: Rik Cabanier Date: Fri, 30 May 2025 21:39:57 +0000 Subject: [PATCH] first pass at occlusion in gpurenderer --- examples/files.json | 1 + .../screenshots/webgpu_xr_occluded_cubes.jpg | Bin 0 -> 52947 bytes examples/webgpu_xr_occluded_cubes.html | 279 ++++++++++++++++++ src/Three.TSL.js | 2 + src/nodes/TSL.js | 1 + src/nodes/core/NodeBuilder.js | 6 + src/nodes/display/ScreenNode.js | 19 +- src/renderers/common/Renderer.js | 5 +- src/renderers/common/Textures.js | 14 +- src/renderers/common/XRManager.js | 109 ++++++- .../webgl-fallback/nodes/GLSLNodeBuilder.js | 6 + .../webgl-fallback/utils/WebGLTextureUtils.js | 22 +- src/renderers/webgpu/nodes/WGSLNodeBuilder.js | 6 + 13 files changed, 450 insertions(+), 20 deletions(-) create mode 100644 examples/screenshots/webgpu_xr_occluded_cubes.jpg create mode 100644 examples/webgpu_xr_occluded_cubes.html diff --git a/examples/files.json b/examples/files.json index 1230263cb7dad9..32f9332d959fc0 100644 --- a/examples/files.json +++ b/examples/files.json @@ -464,6 +464,7 @@ "webgpu_water", "webgpu_xr_rollercoaster", "webgpu_xr_cubes", + "webgpu_xr_occluded_cubes", "webgpu_xr_native_layers" ], "webaudio": [ diff --git a/examples/screenshots/webgpu_xr_occluded_cubes.jpg b/examples/screenshots/webgpu_xr_occluded_cubes.jpg new file mode 100644 index 0000000000000000000000000000000000000000..214028953b5d6de40da7fd27291d03a10a1963a3 GIT binary patch literal 52947 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 + + + three.js xr - cubes + + + + + + +
+ three.js xr - interactive cubes +
+ + + + + + diff --git a/src/Three.TSL.js b/src/Three.TSL.js index e930ff2e500b4e..d8ed56504b6b13 100644 --- a/src/Three.TSL.js +++ b/src/Three.TSL.js @@ -88,6 +88,7 @@ export const bool = TSL.bool; export const buffer = TSL.buffer; export const bufferAttribute = TSL.bufferAttribute; export const bumpMap = TSL.bumpMap; +export const builtin = TSL.builtin; export const burn = TSL.burn; export const bvec2 = TSL.bvec2; export const bvec3 = TSL.bvec3; @@ -423,6 +424,7 @@ export const samplerComparison = TSL.samplerComparison; export const saturate = TSL.saturate; export const saturation = TSL.saturation; export const screen = TSL.screen; +export const screenRaw = TSL.screenRaw; export const screenCoordinate = TSL.screenCoordinate; export const screenSize = TSL.screenSize; export const screenUV = TSL.screenUV; diff --git a/src/nodes/TSL.js b/src/nodes/TSL.js index 70f798b9b6caf4..c764e68494b4ef 100644 --- a/src/nodes/TSL.js +++ b/src/nodes/TSL.js @@ -50,6 +50,7 @@ export * from './tsl/TSLBase.js'; export * from './accessors/AccessorsUtils.js'; export * from './accessors/Arrays.js'; export * from './accessors/UniformArrayNode.js'; +export * from './accessors/BuiltinNode.js'; export * from './accessors/Bitangent.js'; export * from './accessors/BufferAttributeNode.js'; export * from './accessors/BufferNode.js'; diff --git a/src/nodes/core/NodeBuilder.js b/src/nodes/core/NodeBuilder.js index 4eaeb829037778..f7767350728118 100644 --- a/src/nodes/core/NodeBuilder.js +++ b/src/nodes/core/NodeBuilder.js @@ -979,6 +979,12 @@ class NodeBuilder { } + getFrag() { + + console.warn( 'Abstract function.' ); + + } + /** * Whether to flip texture data along its vertical axis or not. WebGL needs * this method evaluate to `true`, WebGPU to `false`. diff --git a/src/nodes/display/ScreenNode.js b/src/nodes/display/ScreenNode.js index b5b33a1c2da58a..5e980725e249aa 100644 --- a/src/nodes/display/ScreenNode.js +++ b/src/nodes/display/ScreenNode.js @@ -1,7 +1,7 @@ import Node from '../core/Node.js'; import { NodeUpdateType } from '../core/constants.js'; import { uniform } from '../core/UniformNode.js'; -import { Fn, nodeImmutable, vec2 } from '../tsl/TSLBase.js'; +import { Fn, nodeImmutable, vec2, vec4 } from '../tsl/TSLBase.js'; import { Vector2 } from '../../math/Vector2.js'; import { Vector4 } from '../../math/Vector4.js'; @@ -26,7 +26,7 @@ class ScreenNode extends Node { /** * Constructs a new screen node. * - * @param {('coordinate'|'viewport'|'size'|'uv')} scope - The node's scope. + * @param {('coordinate'|'viewport'|'size'|'uv'|'raw')} scope - The node's scope. */ constructor( scope ) { @@ -62,7 +62,7 @@ class ScreenNode extends Node { */ getNodeType() { - if ( this.scope === ScreenNode.VIEWPORT ) return 'vec4'; + if ( this.scope === ScreenNode.VIEWPORT || this.scope === ScreenNode.RAW ) return 'vec4'; else return 'vec2'; } @@ -143,6 +143,10 @@ class ScreenNode extends Node { output = uniform( viewportVec || ( viewportVec = new Vector4() ) ); + } else if ( scope === ScreenNode.RAW ) { + + output = vec4( screenRaw.div( screenSize ) ); + } else { output = vec2( screenCoordinate.div( screenSize ) ); @@ -155,7 +159,11 @@ class ScreenNode extends Node { generate( builder ) { - if ( this.scope === ScreenNode.COORDINATE ) { + if ( this.scope === ScreenNode.RAW ) { + + return builder.getFrag(); + + } else if ( this.scope === ScreenNode.COORDINATE ) { let coord = builder.getFragCoord(); @@ -183,6 +191,7 @@ ScreenNode.COORDINATE = 'coordinate'; ScreenNode.VIEWPORT = 'viewport'; ScreenNode.SIZE = 'size'; ScreenNode.UV = 'uv'; +ScreenNode.RAW = 'raw'; export default ScreenNode; @@ -230,6 +239,8 @@ export const viewport = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.VIEW */ export const viewportSize = viewport.zw; +export const screenRaw = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.RAW );//.div( vec4( viewport.z, viewport.w, 1, 1 ) ); + /** * TSL object that represents the current `x`/`y` pixel position on the viewport in physical pixel units. * diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index e2ee9095e9ba63..ef28bd8a6c4282 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -2494,8 +2494,9 @@ class Renderer { * This method can only be used if the renderer has been initialized. * * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. */ - initTexture( texture ) { + initTexture( texture, options = {} ) { if ( this._initialized === false ) { @@ -2503,7 +2504,7 @@ class Renderer { } - this._textures.updateTexture( texture ); + this._textures.updateTexture( texture, options ); } diff --git a/src/renderers/common/Textures.js b/src/renderers/common/Textures.js index c966ac75678ebe..d4eac48b092ddb 100644 --- a/src/renderers/common/Textures.js +++ b/src/renderers/common/Textures.js @@ -242,7 +242,7 @@ class Textures extends DataMap { // - if ( isRenderTarget || texture.isStorageTexture === true ) { + if ( isRenderTarget || texture.isStorageTexture === true || texture.isExternalTexture === true ) { backend.createSampler( texture ); backend.createTexture( texture, options ); @@ -306,7 +306,11 @@ class Textures extends DataMap { // async update - backend.createDefaultTexture( texture ); + if ( options.source === undefined ) { + + backend.createDefaultTexture( texture ); + + } textureData.isDefaultTexture = true; textureData.generation = texture.version; @@ -332,7 +336,11 @@ class Textures extends DataMap { texture.removeEventListener( 'dispose', onDispose ); - this._destroyTexture( texture ); + if ( options.source === undefined ) { + + this._destroyTexture( texture ); + + } }; diff --git a/src/renderers/common/XRManager.js b/src/renderers/common/XRManager.js index 217851c5936b7b..04fb341a0f865a 100644 --- a/src/renderers/common/XRManager.js +++ b/src/renderers/common/XRManager.js @@ -16,6 +16,11 @@ import NodeMaterial from '../../materials/nodes/NodeMaterial.js'; import { PlaneGeometry } from '../../geometries/PlaneGeometry.js'; import { MeshBasicMaterial } from '../../materials/MeshBasicMaterial.js'; import { Mesh } from '../../objects/Mesh.js'; +import { Fn, vec2, vec3 } from '../../nodes/tsl/TSLBase.js'; +import { texture3D } from '../../nodes/accessors/Texture3DNode.js'; +import { screenRaw, viewport } from '../../nodes/display/ScreenNode.js'; +import { builtin } from '../../nodes/accessors/BuiltinNode.js'; +import { Texture } from '../../textures/Texture.js'; const _cameraLPos = /*@__PURE__*/ new Vector3(); const _cameraRPos = /*@__PURE__*/ new Vector3(); @@ -859,6 +864,67 @@ class XRManager extends EventDispatcher { } + applyOcclusion( scene ) { + + if ( this.depthData ) { + + const data = this.depthData[ 0 ]; + + if ( this._occlusionTexture == undefined ) { + + this._occlusionTexture = new Texture( { width: data.width, height: data.height, depth: 2 } ); + this._occlusionTexture.isTextureArray = true; + this._occlusionTexture.isExternalTexture = true; + + this._masknode = Fn( () => { + + let pixel = ( screenRaw.xyzw ).toVar( 'pixel' ); + pixel = pixel.xy.div( vec2( viewport.zw ) ); + + const real_world_depth = texture3D( this._occlusionTexture, vec3( pixel, builtin( 'gl_ViewID_OVR' ) ) ).r; + const virtual_world_depth = screenRaw.z; + + return virtual_world_depth.lessThan( real_world_depth ); + + } )(); + + this._renderer.initTexture( this._occlusionTexture, { width: data.width, height: data.height, depth: 2, source: data.texture } ); + + scene.traverse( ( object ) => { + + if ( object.material ) { + + object.material.maskNode = this._masknode; + + } + + } ); + + } + + } else { + + if ( this._masknode ) { + + scene.traverse( ( object ) => { + + if ( object.material ) { + + delete object.material.maskNode; + + } + + } ); + + } + + delete this._masknode; + delete this._occlusionTexture; + + } + + } + /** * Returns the current XR session. @@ -1069,8 +1135,15 @@ class XRManager extends EventDispatcher { if ( session === null ) return; - const depthNear = camera.near; - const depthFar = camera.far; + let depthNear = camera.near; + let depthFar = camera.far; + + if ( this.depthData ) { + + depthNear = this.depthData[ 0 ].depthNear; + depthFar = this.depthData[ 0 ].depthFar; + + } const cameraXR = this._cameraXR; const cameraL = this._cameraL; @@ -1565,6 +1638,36 @@ function onAnimationFrame( time, frame ) { } + const enabledFeatures = this._session.enabledFeatures; + const gpuDepthSensingEnabled = enabledFeatures && + enabledFeatures.includes( 'depth-sensing' ) && + this._session.depthUsage == 'gpu-optimized'; + let depth_data = undefined; + + if ( gpuDepthSensingEnabled ) { + + depth_data = this._glBinding.getDepthInformation( view ); + + } + + if ( depth_data ) { + + if ( this.depthData === undefined ) { + + this.depthData = [ depth_data ]; + + } else { + + this.depthData.push( depth_data ); + + } + + } else { + + delete this.depthData; + + } + } else { viewport = glBaseLayer.getViewport( view ); @@ -1624,6 +1727,8 @@ function onAnimationFrame( time, frame ) { if ( this._currentAnimationLoop ) this._currentAnimationLoop( time, frame ); + delete this.depthData; + if ( frame.detectedPlanes ) { this.dispatchEvent( { type: 'planesdetected', data: frame } ); diff --git a/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js b/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js index da2f96f8911a88..22eb54af991735 100644 --- a/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +++ b/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js @@ -935,6 +935,12 @@ ${ flowData.code } } + getFrag() { + + return 'gl_FragCoord'; + + } + /** * Returns the frag depth builtin. * diff --git a/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js b/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js index 4e0c0fca20f1d2..3da5b3b7632b81 100644 --- a/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +++ b/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js @@ -404,30 +404,34 @@ class WebGLTextureUtils { createTexture( texture, options ) { const { gl, backend } = this; - const { levels, width, height, depth } = options; + const { levels, width, height, depth, source } = options; const glFormat = backend.utils.convert( texture.format, texture.colorSpace ); const glType = backend.utils.convert( texture.type ); const glInternalFormat = this.getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); - const textureGPU = gl.createTexture(); + const textureGPU = source ? source : gl.createTexture(); const glTextureType = this.getGLTextureType( texture ); backend.state.bindTexture( glTextureType, textureGPU ); - this.setTextureParameters( glTextureType, texture ); + if ( ! source ) { - if ( texture.isArrayTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + this.setTextureParameters( glTextureType, texture ); - gl.texStorage3D( gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, width, height, depth ); + if ( texture.isArrayTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - } else if ( texture.isData3DTexture ) { + gl.texStorage3D( gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, width, height, depth ); + + } else if ( texture.isData3DTexture ) { - gl.texStorage3D( gl.TEXTURE_3D, levels, glInternalFormat, width, height, depth ); + gl.texStorage3D( gl.TEXTURE_3D, levels, glInternalFormat, width, height, depth ); - } else if ( ! texture.isVideoTexture ) { + } else if ( ! texture.isVideoTexture ) { - gl.texStorage2D( glTextureType, levels, glInternalFormat, width, height ); + gl.texStorage2D( glTextureType, levels, glInternalFormat, width, height ); + + } } diff --git a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js index 55488ec8aa7aa2..e22c736e75f125 100644 --- a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -1174,6 +1174,12 @@ ${ flowData.code } } + getFrag() { + + return this.getBuiltin( 'position', 'fragCoord', 'vec4' ); + + } + /** * Returns the frag depth builtin. *