From 325bb90320640a2216ece54581ef644a7afca921 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 21 Jan 2025 10:20:22 +0100 Subject: [PATCH 1/3] Add `XRRenderTarget`. (#30369) --- src/renderers/common/Textures.js | 19 +++-- src/renderers/common/XRManager.js | 12 ++-- src/renderers/common/XRRenderTarget.js | 74 ++++++++++++++++++++ src/renderers/webgl-fallback/WebGLBackend.js | 10 +-- 4 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 src/renderers/common/XRRenderTarget.js diff --git a/src/renderers/common/Textures.js b/src/renderers/common/Textures.js index 88b12e5eafc945..79487279ba7fab 100644 --- a/src/renderers/common/Textures.js +++ b/src/renderers/common/Textures.js @@ -127,7 +127,18 @@ class Textures extends DataMap { const options = { sampleCount }; - if ( ( renderTarget.isXRRenderTarget === true && renderTarget.hasExternalTextures === true ) === false ) { + // when using the WebXR Layers API, the render target uses external textures which + // require no manual updates + + if ( renderTarget.isXRRenderTarget === true && renderTarget.hasExternalTextures === true ) { + + if ( depthTexture && renderTarget.autoAllocateDepthBuffer === true ) { + + this.updateTexture( depthTexture, options ); + + } + + } else { for ( let i = 0; i < textures.length; i ++ ) { @@ -139,11 +150,11 @@ class Textures extends DataMap { } - } + if ( depthTexture ) { - if ( depthTexture && renderTarget.autoAllocateDepthBuffer !== false ) { + this.updateTexture( depthTexture, options ); - this.updateTexture( depthTexture, options ); + } } diff --git a/src/renderers/common/XRManager.js b/src/renderers/common/XRManager.js index 0979c6a49b24d6..a75efb24e2c888 100644 --- a/src/renderers/common/XRManager.js +++ b/src/renderers/common/XRManager.js @@ -1,6 +1,5 @@ import { ArrayCamera } from '../../cameras/ArrayCamera.js'; import { EventDispatcher } from '../../core/EventDispatcher.js'; -import { RenderTarget } from '../../core/RenderTarget.js'; import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js'; import { RAD2DEG } from '../../math/MathUtils.js'; import { Vector2 } from '../../math/Vector2.js'; @@ -9,6 +8,7 @@ import { Vector4 } from '../../math/Vector4.js'; import { WebXRController } from '../webxr/WebXRController.js'; import { DepthFormat, DepthStencilFormat, RGBAFormat, UnsignedByteType, UnsignedInt248Type, UnsignedIntType } from '../../constants.js'; import { DepthTexture } from '../../textures/DepthTexture.js'; +import { XRRenderTarget } from './XRRenderTarget.js'; const _cameraLPos = /*@__PURE__*/ new Vector3(); const _cameraRPos = /*@__PURE__*/ new Vector3(); @@ -316,7 +316,7 @@ class XRManager extends EventDispatcher { this._xrFrame = null; /** - * Whether to use projection layers or not. + * Whether to use the WebXR Layers API or not. * * @private * @type {Boolean} @@ -624,7 +624,7 @@ class XRManager extends EventDispatcher { renderer.setPixelRatio( 1 ); renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false ); - this._xrRenderTarget = new RenderTarget( + this._xrRenderTarget = new XRRenderTarget( glProjLayer.textureWidth, glProjLayer.textureHeight, { @@ -657,7 +657,7 @@ class XRManager extends EventDispatcher { renderer.setPixelRatio( 1 ); renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false ); - this._xrRenderTarget = new RenderTarget( + this._xrRenderTarget = new XRRenderTarget( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, { @@ -670,8 +670,6 @@ class XRManager extends EventDispatcher { } - this._xrRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 - // this.setFoveation( this.getFoveation() ); @@ -1116,7 +1114,7 @@ function onAnimationFrame( time, frame ) { // For side-by-side projection, we only produce a single texture for both eyes. if ( i === 0 ) { - backend.setRenderTargetTextures( + backend.setXRRenderTargetTextures( this._xrRenderTarget, glSubImage.colorTexture, this._glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture diff --git a/src/renderers/common/XRRenderTarget.js b/src/renderers/common/XRRenderTarget.js new file mode 100644 index 00000000000000..d038cfa32f0c6f --- /dev/null +++ b/src/renderers/common/XRRenderTarget.js @@ -0,0 +1,74 @@ +import { RenderTarget } from '../../core/RenderTarget.js'; + +/** + * A special type of render target that is used when rendering + * with the WebXR Device API. + * + * @private + * @augments RenderTarget + */ +class XRRenderTarget extends RenderTarget { + + /** + * Constructs a new XR render target. + * + * @param {Number} [width=1] - The width of the render target. + * @param {Number} [height=1] - The height of the render target. + * @param {Object} [options={}] - The configuration options. + */ + constructor( width = 1, height = 1, options = {} ) { + + super( width, height, options ); + + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isXRRenderTarget = true; + + /** + * Whether the attachments of the render target + * are defined by external textures. This flag is + * set to `true` when using the WebXR Layers API. + * + * @type {Boolean} + * @default false + */ + this.hasExternalTextures = false; + + /** + * Whether a depth buffer should automatically be allocated + * for this XR render target or not. + * + * Allocating a depth buffer is the default behavior of XR render + * targets. However, when using the WebXR Layers API, this flag + * must be set to `false` when the `ignoreDepthValues` property of + * the projection layers evaluates to `true`. + * + * Reference: {@link https://www.w3.org/TR/webxrlayers-1/#dom-xrprojectionlayer-ignoredepthvalues}. + * + * @type {Boolean} + * @default true + */ + this.autoAllocateDepthBuffer = true; + + } + + copy( source ) { + + super.copy( source ); + + this.hasExternalTextures = source.hasExternalTextures; + this.autoAllocateDepthBuffer = source.autoAllocateDepthBuffer; + + return this; + + } + + +} + +export { XRRenderTarget }; diff --git a/src/renderers/webgl-fallback/WebGLBackend.js b/src/renderers/webgl-fallback/WebGLBackend.js index f0a7dab3d6e72f..c0a7ac091c6c14 100644 --- a/src/renderers/webgl-fallback/WebGLBackend.js +++ b/src/renderers/webgl-fallback/WebGLBackend.js @@ -323,13 +323,15 @@ class WebGLBackend extends Backend { } /** - * Configures the render target with external textures. + * Configures the given XR render target with external textures. * - * @param {RenderTarget} renderTarget - The render target. + * This method is only relevant when using the WebXR Layers API. + * + * @param {XRRenderTarget} renderTarget - The XR render target. * @param {WebGLTexture} colorTexture - A native color texture. * @param {WebGLTexture?} [depthTexture=null] - A native depth texture. */ - setRenderTargetTextures( renderTarget, colorTexture, depthTexture = null ) { + setXRRenderTargetTextures( renderTarget, colorTexture, depthTexture = null ) { this.set( renderTarget.texture, { textureGPU: colorTexture } ); @@ -1929,7 +1931,7 @@ class WebGLBackend extends Backend { const isRenderTarget3D = renderTarget.isRenderTarget3D === true; const isRenderTargetArray = renderTarget.isRenderTargetArray === true; const isXRRenderTarget = renderTarget.isXRRenderTarget === true; - const hasExternalTextures = renderTarget.hasExternalTextures === true; + const hasExternalTextures = ( isXRRenderTarget === true && renderTarget.hasExternalTextures === true ); let msaaFb = renderTargetContextData.msaaFrameBuffer; let depthRenderbuffer = renderTargetContextData.depthRenderbuffer; From 6f2a92db1da663c61aa7c23b4ed5d1395e4afa4c Mon Sep 17 00:00:00 2001 From: Renaud Rohlinger Date: Tue, 21 Jan 2025 19:32:45 +0900 Subject: [PATCH 2/3] WebGPURenderer: Add mat2 uniform support (#30368) * WebGPURenderer: Add mat2 uniform support * feedbacks * Update Uniform.js Clean up. --------- Co-authored-by: Michael Herzog --- src/nodes/core/NodeBuilder.js | 3 +- src/renderers/common/Uniform.js | 38 ++++++++++++++- src/renderers/common/nodes/NodeUniform.js | 56 ++++++++++++++++++++++- 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/nodes/core/NodeBuilder.js b/src/nodes/core/NodeBuilder.js index c7b1166203aa03..c279819e4d9f7f 100644 --- a/src/nodes/core/NodeBuilder.js +++ b/src/nodes/core/NodeBuilder.js @@ -13,7 +13,7 @@ import { NodeUpdateType, defaultBuildStages, shaderStages } from './constants.js import { NumberNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform, - ColorNodeUniform, Matrix3NodeUniform, Matrix4NodeUniform + ColorNodeUniform, Matrix2NodeUniform, Matrix3NodeUniform, Matrix4NodeUniform } from '../../renderers/common/nodes/NodeUniform.js'; import { stack } from './StackNode.js'; @@ -2366,6 +2366,7 @@ class NodeBuilder { if ( type === 'vec3' || type === 'ivec3' || type === 'uvec3' ) return new Vector3NodeUniform( uniformNode ); if ( type === 'vec4' || type === 'ivec4' || type === 'uvec4' ) return new Vector4NodeUniform( uniformNode ); if ( type === 'color' ) return new ColorNodeUniform( uniformNode ); + if ( type === 'mat2' ) return new Matrix2NodeUniform( uniformNode ); if ( type === 'mat3' ) return new Matrix3NodeUniform( uniformNode ); if ( type === 'mat4' ) return new Matrix4NodeUniform( uniformNode ); diff --git a/src/renderers/common/Uniform.js b/src/renderers/common/Uniform.js index 3a6229c15a0259..86afa877dbc35c 100644 --- a/src/renderers/common/Uniform.js +++ b/src/renderers/common/Uniform.js @@ -1,4 +1,5 @@ import { Color } from '../../math/Color.js'; +import { Matrix2 } from '../../math/Matrix2.js'; import { Matrix3 } from '../../math/Matrix3.js'; import { Matrix4 } from '../../math/Matrix4.js'; import { Vector2 } from '../../math/Vector2.js'; @@ -256,6 +257,41 @@ class ColorUniform extends Uniform { } +/** + * Represents a Matrix2 uniform. + * + * @private + * @augments Uniform + */ +class Matrix2Uniform extends Uniform { + + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Matrix2} value - The uniform's value. + */ + constructor( name, value = new Matrix2() ) { + + super( name, value ); + + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isMatrix2Uniform = true; + + this.boundary = 16; + this.itemSize = 4; + + } + +} + + /** * Represents a Matrix3 uniform. * @@ -327,5 +363,5 @@ class Matrix4Uniform extends Uniform { export { NumberUniform, Vector2Uniform, Vector3Uniform, Vector4Uniform, ColorUniform, - Matrix3Uniform, Matrix4Uniform + Matrix2Uniform, Matrix3Uniform, Matrix4Uniform }; diff --git a/src/renderers/common/nodes/NodeUniform.js b/src/renderers/common/nodes/NodeUniform.js index 9043e539f309a1..83e75410b196e2 100644 --- a/src/renderers/common/nodes/NodeUniform.js +++ b/src/renderers/common/nodes/NodeUniform.js @@ -1,6 +1,6 @@ import { NumberUniform, Vector2Uniform, Vector3Uniform, Vector4Uniform, - ColorUniform, Matrix3Uniform, Matrix4Uniform + ColorUniform, Matrix2Uniform, Matrix3Uniform, Matrix4Uniform } from '../Uniform.js'; /** @@ -258,6 +258,58 @@ class ColorNodeUniform extends ColorUniform { } + +/** + * A special form of Matrix2 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Matrix2Uniform + */ +class Matrix2NodeUniform extends Matrix2Uniform { + + /** + * Constructs a new node-based Matrix2 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ + constructor( nodeUniform ) { + + super( nodeUniform.name, nodeUniform.value ); + + /** + * The node uniform. + * + * @type {NodeUniform} + */ + this.nodeUniform = nodeUniform; + + } + + /** + * Overwritten to return the value of the node uniform. + * + * @return {Matrix2} The value. + */ + getValue() { + + return this.nodeUniform.value; + + } + + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ + getType() { + + return this.nodeUniform.type; + + } + +} + /** * A special form of Matrix3 uniform binding type. * It's value is managed by a node object. @@ -362,5 +414,5 @@ class Matrix4NodeUniform extends Matrix4Uniform { export { NumberNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform, - ColorNodeUniform, Matrix3NodeUniform, Matrix4NodeUniform + ColorNodeUniform, Matrix2NodeUniform, Matrix3NodeUniform, Matrix4NodeUniform }; From 7e76dc4499c9d252a74bc25d7196f87c2c7ee139 Mon Sep 17 00:00:00 2001 From: Renaud Rohlinger Date: Tue, 21 Jan 2025 19:33:08 +0900 Subject: [PATCH 3/3] TSL: Add missing Support (#30371) --- src/Three.TSL.js | 1 + src/nodes/gpgpu/AtomicFunctionNode.js | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Three.TSL.js b/src/Three.TSL.js index eb8decaaa591c6..a33b6ecd980574 100644 --- a/src/Three.TSL.js +++ b/src/Three.TSL.js @@ -57,6 +57,7 @@ export const atomicOr = TSL.atomicOr; export const atomicStore = TSL.atomicStore; export const atomicSub = TSL.atomicSub; export const atomicXor = TSL.atomicXor; +export const atomicLoad = TSL.atomicLoad; export const attenuationColor = TSL.attenuationColor; export const attenuationDistance = TSL.attenuationDistance; export const attribute = TSL.attribute; diff --git a/src/nodes/gpgpu/AtomicFunctionNode.js b/src/nodes/gpgpu/AtomicFunctionNode.js index ae821021956e1e..b04dbecf01208d 100644 --- a/src/nodes/gpgpu/AtomicFunctionNode.js +++ b/src/nodes/gpgpu/AtomicFunctionNode.js @@ -103,7 +103,13 @@ class AtomicFunctionNode extends TempNode { const params = []; params.push( `&${ a.build( builder, inputType ) }` ); - params.push( b.build( builder, inputType ) ); + + if ( b !== null ) { + + params.push( b.build( builder, inputType ) ); + + + } const methodSnippet = `${ builder.getMethod( method, type ) }( ${params.join( ', ' )} )`; @@ -166,6 +172,16 @@ export const atomicFunc = ( method, pointerNode, valueNode, storeNode = null ) = }; +/** + * Loads the value stored in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ +export const atomicLoad = ( pointerNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_LOAD, pointerNode, null, storeNode ); + /** * Stores a value in the atomic variable. *