diff --git a/build/three.module.js b/build/three.module.js index a3c4ac6009c9d8..496b74f3557b7a 100644 --- a/build/three.module.js +++ b/build/three.module.js @@ -16410,6 +16410,14 @@ class WebGLRenderer { } + let extensions, capabilities, state, info; + let properties, textures, environments, attributes, geometries, objects; + let programCache, materials, renderLists, renderStates, clipping, shadowMap; + + let background, morphtargets, bufferRenderer, indexedBufferRenderer; + + let utils, bindingStates, uniformsGroups; + try { const contextAttributes = { @@ -16453,21 +16461,19 @@ class WebGLRenderer { } + initGLContext(); + } catch ( e ) { + canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); + canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + error( 'WebGLRenderer: ' + e.message ); throw e; } - let extensions, capabilities, state, info; - let properties, textures, environments, attributes, geometries, objects; - let programCache, materials, renderLists, renderStates, clipping, shadowMap; - - let background, morphtargets, bufferRenderer, indexedBufferRenderer; - - let utils, bindingStates, uniformsGroups; - function initGLContext() { extensions = new WebGLExtensions( _gl ); @@ -16589,8 +16595,6 @@ class WebGLRenderer { } - initGLContext(); - // initialize internal render target for non-UnsignedByteType color buffer if ( _outputBufferType !== UnsignedByteType ) { diff --git a/build/three.webgpu.js b/build/three.webgpu.js index eaf1ddad13cd7a..8070602a8f7807 100644 --- a/build/three.webgpu.js +++ b/build/three.webgpu.js @@ -3,7 +3,7 @@ * Copyright 2010-2026 Three.js Authors * SPDX-License-Identifier: MIT */ -import { DynamicDrawUsage, RenderObjectRefreshType, Color, Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, UnsignedIntType, IntType, error, RedFormat, RedIntegerFormat, DepthFormat, DepthStencilFormat, AlphaFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBIntegerFormat, EventDispatcher, MathUtils, warn, WebGLCoordinateSystem, WebGPUCoordinateSystem, ColorManagement, SRGBTransfer, NoToneMapping, StaticDrawUsage, InterleavedBufferAttribute, InterleavedBuffer, NoColorSpace, log as log$1, warnOnce, Texture, Compatibility, LessCompare, LessEqualCompare, GreaterCompare, GreaterEqualCompare, NearestFilter, Sphere, BackSide, DoubleSide, CubeTexture, CubeReflectionMapping, CubeRefractionMapping, TangentSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking, ObjectSpaceNormalMap, RED_GREEN_RGTC2_Format, RG11_EAC_Format, InstancedBufferAttribute, InstancedInterleavedBuffer, DataTexture, RGBAFormat, FloatType, DataArrayTexture, FramebufferTexture, LinearMipmapLinearFilter, DepthTexture, Material, LineBasicMaterial, LineDashedMaterial, NoBlending, MeshNormalMaterial, SRGBColorSpace, RenderTarget, BoxGeometry, Mesh, Scene, LinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, AddOperation, MixOperation, MultiplyOperation, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, HalfFloatType, ClampToEdgeWrapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, LinearSRGBColorSpace, CubeUVReflectionMapping, BufferAttribute, MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial, MeshMatcapMaterial, SpriteMaterial, PointsMaterial, ShadowMaterial, Uint32BufferAttribute, Uint16BufferAttribute, ByteType, UnsignedByteType, ShortType, UnsignedShortType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, NormalBlending, SrcAlphaFactor, OneMinusSrcAlphaFactor, AddEquation, MaterialBlending, Object3D, LinearMipMapLinearFilter, Plane, Float32BufferAttribute, UVMapping, PCFShadowMap, VSMShadowMap, BasicShadowMap, CubeDepthTexture, SphereGeometry, LinearMipmapNearestFilter, NearestMipmapLinearFilter, Float16BufferAttribute, yieldToMain, REVISION, ArrayCamera, PlaneGeometry, FrontSide, CustomBlending, ZeroFactor, CylinderGeometry, Quaternion, WebXRController, RAD2DEG, PCFSoftShadowMap, FrustumArray, Frustum, RGBAIntegerFormat, TimestampQuery, createCanvasElement, MaxEquation, MinEquation, ReverseSubtractEquation, SubtractEquation, OneMinusConstantAlphaFactor, ConstantAlphaFactor, OneMinusConstantColorFactor, ConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcColorFactor, OneFactor, CullFaceNone, CullFaceBack, CullFaceFront, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, ReversedDepthFuncs, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, SIGNED_RED_GREEN_RGTC2_Format, MirroredRepeatWrapping, RepeatWrapping, NearestMipmapNearestFilter, NotEqualCompare, EqualCompare, AlwaysCompare, NeverCompare, LinearTransfer, getByteLength, isTypedArray, NotEqualStencilFunc, GreaterStencilFunc, GreaterEqualStencilFunc, EqualStencilFunc, LessEqualStencilFunc, LessStencilFunc, AlwaysStencilFunc, NeverStencilFunc, DecrementWrapStencilOp, IncrementWrapStencilOp, DecrementStencilOp, IncrementStencilOp, InvertStencilOp, ReplaceStencilOp, ZeroStencilOp, KeepStencilOp, SpotLight, PointLight, DirectionalLight, RectAreaLight, AmbientLight, HemisphereLight, LightProbe, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping, Group, Loader, FileLoader, MaterialLoader, ObjectLoader } from './three.core.js'; +import { DynamicDrawUsage, RenderObjectRefreshType, Color, Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, UnsignedIntType, IntType, error, RedFormat, RedIntegerFormat, DepthFormat, DepthStencilFormat, AlphaFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBIntegerFormat, EventDispatcher, MathUtils, warn, WebGLCoordinateSystem, WebGPUCoordinateSystem, ColorManagement, SRGBTransfer, NoToneMapping, StaticDrawUsage, InterleavedBufferAttribute, InterleavedBuffer, NoColorSpace, log as log$1, warnOnce, Texture, Compatibility, LessCompare, LessEqualCompare, GreaterCompare, GreaterEqualCompare, NearestFilter, Sphere, BackSide, DoubleSide, CubeTexture, CubeReflectionMapping, CubeRefractionMapping, TangentSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking, ObjectSpaceNormalMap, RED_GREEN_RGTC2_Format, RG11_EAC_Format, InstancedBufferAttribute, InstancedInterleavedBuffer, DataTexture, RGBAFormat, FloatType, DataArrayTexture, FramebufferTexture, LinearMipmapLinearFilter, DepthTexture, Material, LineBasicMaterial, LineDashedMaterial, NoBlending, MeshNormalMaterial, SRGBColorSpace, RenderTarget, BoxGeometry, Mesh, Scene, LinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, AddOperation, MixOperation, MultiplyOperation, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, HalfFloatType, ClampToEdgeWrapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, LinearSRGBColorSpace, CubeUVReflectionMapping, BufferAttribute, MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial, MeshMatcapMaterial, SpriteMaterial, PointsMaterial, ShadowMaterial, Uint32BufferAttribute, Uint16BufferAttribute, ByteType, UnsignedByteType, ShortType, UnsignedShortType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, NormalBlending, SrcAlphaFactor, OneMinusSrcAlphaFactor, AddEquation, MaterialBlending, Object3D, LinearMipMapLinearFilter, Plane, Float32BufferAttribute, UVMapping, VSMShadowMap, PCFShadowMap, BasicShadowMap, CubeDepthTexture, SphereGeometry, LinearMipmapNearestFilter, NearestMipmapLinearFilter, Float16BufferAttribute, yieldToMain, REVISION, ArrayCamera, PlaneGeometry, FrontSide, CustomBlending, ZeroFactor, CylinderGeometry, Quaternion, WebXRController, RAD2DEG, PCFSoftShadowMap, FrustumArray, Frustum, RGBAIntegerFormat, TimestampQuery, createCanvasElement, MaxEquation, MinEquation, ReverseSubtractEquation, SubtractEquation, OneMinusConstantAlphaFactor, ConstantAlphaFactor, OneMinusConstantColorFactor, ConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcColorFactor, OneFactor, CullFaceNone, CullFaceBack, CullFaceFront, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, ReversedDepthFuncs, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, SIGNED_RED_GREEN_RGTC2_Format, MirroredRepeatWrapping, RepeatWrapping, NearestMipmapNearestFilter, NotEqualCompare, EqualCompare, AlwaysCompare, NeverCompare, LinearTransfer, getByteLength, isTypedArray, NotEqualStencilFunc, GreaterStencilFunc, GreaterEqualStencilFunc, EqualStencilFunc, LessEqualStencilFunc, LessStencilFunc, AlwaysStencilFunc, NeverStencilFunc, DecrementWrapStencilOp, IncrementWrapStencilOp, DecrementStencilOp, IncrementStencilOp, InvertStencilOp, ReplaceStencilOp, ZeroStencilOp, KeepStencilOp, SpotLight, PointLight, DirectionalLight, RectAreaLight, AmbientLight, HemisphereLight, LightProbe, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping, Group, Loader, FileLoader, MaterialLoader, ObjectLoader } from './three.core.js'; export { AdditiveAnimationBlendMode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BatchedMesh, BezierInterpolant, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, Controls, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CustomToneMapping, Cylindrical, Data3DTexture, DataTextureLoader, DataUtils, DefaultLoadingManager, DetachedBindMode, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, Euler, ExternalTexture, ExtrudeGeometry, Fog, FogExp2, GLBufferAttribute, GLSL1, GLSL3, GridHelper, HTMLTexture, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, InstancedBufferGeometry, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, Interpolant, InterpolateBezier, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, KeyframeTrack, LOD, LatheGeometry, Layers, Light, Line, Line3, LineCurve, LineCurve3, LineLoop, LineSegments, LinearInterpolant, LinearMipMapNearestFilter, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, MeshDepthMaterial, MeshDistanceMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NormalAnimationBlendMode, NumberKeyframeTrack, OctahedronGeometry, Path, PlaneHelper, PointLightHelper, Points, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBADepthPacking, RGBDepthPacking, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RenderTarget3D, RingGeometry, ShaderMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Spherical, SphericalHarmonics3, SplineCurve, SpotLightHelper, Sprite, StaticCopyUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SunLight, TOUCH, TetrahedronGeometry, TextureLoader, TextureSource, TextureUtils, Timer, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLRenderTarget, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, getConsoleFunction, setConsoleFunction } from './three.core.js'; const refreshUniforms = [ @@ -39009,11 +39009,19 @@ class RTTNode extends TextureNode { * @param {Node} node - The node to render a texture with. * @param {?number} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. * @param {?number} [height=null] - The height of the internal render target. - * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @param {Object} [options={}] - The options for the internal render target. + * @param {number} [options.type=HalfFloatType] - The texture type. + * @param {boolean} [options.autoUpdate=true] - Whether the texture should automatically be updated or not. + * @param {number} [options.resolutionScale=1] - The resolution scale. */ - constructor( node, width = null, height = null, options = { type: HalfFloatType } ) { + constructor( node, width = null, height = null, options = {} ) { - const renderTarget = new RenderTarget( width, height, options ); + const { + autoUpdate = true, + resolutionScale = 1 + } = options; + + const renderTarget = new RenderTarget( width, height, { type: HalfFloatType, ...options } ); super( renderTarget.texture, uv$1() ); @@ -39071,7 +39079,7 @@ class RTTNode extends TextureNode { * @type {boolean} * @default true */ - this.autoUpdate = true; + this.autoUpdate = autoUpdate; /** * The resolution scale @@ -39080,7 +39088,7 @@ class RTTNode extends TextureNode { * @type {number} * @default 1 */ - this._resolutionScale = 1; + this._resolutionScale = resolutionScale; /** * The internal quad mesh for RTT. @@ -39243,7 +39251,10 @@ class RTTNode extends TextureNode { * @param {Node} node - The node to render a texture with. * @param {?number} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. * @param {?number} [height=null] - The height of the internal render target. - * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @param {Object} [options={}] - The options for the internal render target. + * @param {number} [options.type=HalfFloatType] - The texture type. + * @param {boolean} [options.autoUpdate=true] - Whether the texture should automatically be updated or not. + * @param {number} [options.resolutionScale=1] - The resolution scale. * @returns {RTTNode} */ const rtt = ( node, ...params ) => new RTTNode( nodeObject( node ), ...params ); @@ -39256,7 +39267,10 @@ const rtt = ( node, ...params ) => new RTTNode( nodeObject( node ), ...params ); * @param {Node} node - The node to render a texture with. * @param {?number} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. * @param {?number} [height=null] - The height of the internal render target. - * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @param {Object} [options={}] - The options for the internal render target. + * @param {number} [options.type=HalfFloatType] - The texture type. + * @param {boolean} [options.autoUpdate=true] - Whether the texture should automatically be updated or not. + * @param {number} [options.resolutionScale=1] - The resolution scale. * @returns {RTTNode} */ const convertToTexture = ( node, ...params ) => { @@ -45045,6 +45059,118 @@ class LightsNode extends Node { */ const lights = ( lights = [] ) => new LightsNode().setLights( lights ); +const _shadowMaterialLib = /*@__PURE__*/ new WeakMap(); +const _shadowRenderObjectLibrary = /*@__PURE__*/ new ChainMap(); +const _shadowRenderObjectKeys = []; + +/** + * Retrieves or creates a shadow material for the given light source. + * + * This function checks if a shadow material already exists for the provided light. + * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it + * in the `shadowMaterialLib` for future use. + * + * @private + * @function + * @param {Light} light - The light source for which the shadow material is needed. + * If the light is a point light, a depth node is calculated + * using the linear shadow distance. + * @returns {NodeMaterial} The shadow material associated with the given light. + */ +const _getShadowMaterial = ( light ) => { + + let material = _shadowMaterialLib.get( light ); + + if ( material === undefined ) { + + material = new NodeMaterial(); + material.colorNode = vec4( 0, 0, 0, 1 ); + material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode + material.name = 'ShadowMaterial'; + material.blending = NoBlending; + material.fog = false; + + _shadowMaterialLib.set( light, material ); + + } + + return material; + +}; + +/** + * Disposes the shadow material for the given light source. + * + * @private + * @param {Light} light - The light source. + */ +const _disposeShadowMaterial = ( light ) => { + + const material = _shadowMaterialLib.get( light ); + + if ( material !== undefined ) { + + material.dispose(); + _shadowMaterialLib.delete( light ); + + } + +}; + +/** + * Creates a function to render shadow objects in a scene. + * + * @private + * @function + * @param {Renderer} renderer - The renderer. + * @param {LightShadow} shadow - The light shadow object containing shadow properties. + * @param {number} shadowType - The type of shadow map (e.g., BasicShadowMap). + * @param {boolean} useVelocity - Whether to use velocity data for rendering. + * @return {shadowRenderObjectFunction} A function that renders shadow objects. + */ +const _getShadowRenderObjectFunction = ( renderer, shadow, shadowType, useVelocity ) => { + + _shadowRenderObjectKeys[ 0 ] = renderer; + _shadowRenderObjectKeys[ 1 ] = shadow; + + let renderObjectFunction = _shadowRenderObjectLibrary.get( _shadowRenderObjectKeys ); + + if ( renderObjectFunction === undefined || ( renderObjectFunction.shadowType !== shadowType || renderObjectFunction.useVelocity !== useVelocity ) ) { + + renderObjectFunction = ( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ) => { + + if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { + + if ( useVelocity ) { + + getDataFromObject( object ).useVelocity = true; + + } + + object.onBeforeShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); + + renderer.renderObject( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ); + + object.onAfterShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); + + } + + }; + + renderObjectFunction.shadowType = shadowType; + renderObjectFunction.useVelocity = useVelocity; + + _shadowRenderObjectLibrary.set( _shadowRenderObjectKeys, renderObjectFunction ); + + } + + _shadowRenderObjectKeys[ 0 ] = null; + _shadowRenderObjectKeys[ 1 ] = null; + + return renderObjectFunction; + +}; + /** * Base class for all shadow nodes. * @@ -45097,6 +45223,47 @@ class ShadowBaseNode extends Node { } + /** + * Retrieves or creates a shadow material for the shadow casting light source. + * + * This method checks if a shadow material already exists for the provided light in the internal library. + * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it for future use. + * + * @return {NodeMaterial} The shadow material associated with the given light. + */ + getShadowMaterial() { + + return _getShadowMaterial( this.light ); + + } + + /** + * Disposes the shadow material for the shadow casting light source. + */ + disposeShadowMaterial() { + + _disposeShadowMaterial( this.light ); + + } + + /** + * Returns a function to render shadow objects in a scene for the given light shadow and renderer. + * + * @param {Renderer} renderer - The renderer. + * @param {LightShadow} [shadow=this.light.shadow] - The light shadow object containing shadow properties. + * @return {Function} A function that renders shadow objects. + */ + getShadowRenderObjectFunction( renderer, shadow = this.light.shadow ) { + + const shadowType = renderer.shadowMap.type; + + const currentMRT = renderer.getMRT(); + const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; + + return _getShadowRenderObjectFunction( renderer, shadow, shadowType, useVelocity ); + + } + /** * Setups the shadow position node which is by default the predefined TSL node object `shadowPositionWorld`. * @@ -45332,8 +45499,6 @@ var RendererUtils = /*#__PURE__*/Object.freeze({ saveSceneState: saveSceneState }); -const shadowMaterialLib = /*@__PURE__*/ new WeakMap(); - /** * A shadow filtering function performing basic filtering. This is in fact an unfiltered version of the shadow map * with a binary `[0,1]` result. @@ -45454,118 +45619,6 @@ const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, depthLa } ); -/** - * Retrieves or creates a shadow material for the given light source. - * - * This function checks if a shadow material already exists for the provided light. - * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it - * in the `shadowMaterialLib` for future use. - * - * @tsl - * @function - * @param {Light} light - The light source for which the shadow material is needed. - * If the light is a point light, a depth node is calculated - * using the linear shadow distance. - * @returns {NodeMaterial} The shadow material associated with the given light. - */ -const getShadowMaterial = ( light ) => { - - let material = shadowMaterialLib.get( light ); - - if ( material === undefined ) { - - material = new NodeMaterial(); - material.colorNode = vec4( 0, 0, 0, 1 ); - material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode - material.name = 'ShadowMaterial'; - material.blending = NoBlending; - material.fog = false; - - shadowMaterialLib.set( light, material ); - - } - - return material; - -}; - -/** - * Disposes the shadow material for the given light source. - * - * @param {Light} light - The light source. - */ -const disposeShadowMaterial = ( light ) => { - - const material = shadowMaterialLib.get( light ); - - if ( material !== undefined ) { - - material.dispose(); - shadowMaterialLib.delete( light ); - - } - -}; - -// - -const _shadowRenderObjectLibrary = /*@__PURE__*/ new ChainMap(); -const _shadowRenderObjectKeys = []; - -/** - * Creates a function to render shadow objects in a scene. - * - * @tsl - * @function - * @param {Renderer} renderer - The renderer. - * @param {LightShadow} shadow - The light shadow object containing shadow properties. - * @param {number} shadowType - The type of shadow map (e.g., BasicShadowMap). - * @param {boolean} useVelocity - Whether to use velocity data for rendering. - * @return {shadowRenderObjectFunction} A function that renders shadow objects. - */ -const getShadowRenderObjectFunction = ( renderer, shadow, shadowType, useVelocity ) => { - - _shadowRenderObjectKeys[ 0 ] = renderer; - _shadowRenderObjectKeys[ 1 ] = shadow; - - let renderObjectFunction = _shadowRenderObjectLibrary.get( _shadowRenderObjectKeys ); - - if ( renderObjectFunction === undefined || ( renderObjectFunction.shadowType !== shadowType || renderObjectFunction.useVelocity !== useVelocity ) ) { - - renderObjectFunction = ( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ) => { - - if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { - - if ( useVelocity ) { - - getDataFromObject( object ).useVelocity = true; - - } - - object.onBeforeShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); - - renderer.renderObject( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ); - - object.onAfterShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); - - } - - }; - - renderObjectFunction.shadowType = shadowType; - renderObjectFunction.useVelocity = useVelocity; - - _shadowRenderObjectLibrary.set( _shadowRenderObjectKeys, renderObjectFunction ); - - } - - _shadowRenderObjectKeys[ 0 ] = null; - _shadowRenderObjectKeys[ 1 ] = null; - - return renderObjectFunction; - -}; - /** * Represents the shader code for the first VSM render pass. * @@ -46208,7 +46261,7 @@ class ShadowNode extends ShadowBaseNode { */ updateShadow( frame ) { - const { shadowMap, light, shadow } = this; + const { shadowMap, shadow } = this; const { renderer, scene, camera } = frame; const shadowType = renderer.shadowMap.type; @@ -46226,14 +46279,11 @@ class ShadowNode extends ShadowBaseNode { const currentRenderObjectFunction = renderer.getRenderObjectFunction(); - const currentMRT = renderer.getMRT(); - const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; - _rendererState = resetRendererAndSceneState( renderer, scene, _rendererState ); - scene.overrideMaterial = getShadowMaterial( light ); + scene.overrideMaterial = this.getShadowMaterial(); - renderer.setRenderObjectFunction( getShadowRenderObjectFunction( renderer, shadow, shadowType, useVelocity ) ); + renderer.setRenderObjectFunction( this.getShadowRenderObjectFunction( renderer, this.shadow || this.light.shadow ) ); renderer.setClearColor( 0x000000, 0 ); @@ -46300,7 +46350,7 @@ class ShadowNode extends ShadowBaseNode { this._currentShadowType = null; - disposeShadowMaterial( this.light ); + this.disposeShadowMaterial(); if ( this.shadowMap ) { @@ -46374,19 +46424,6 @@ class ShadowNode extends ShadowBaseNode { } -/** - * Shadow Render Object Function. - * - * @function shadowRenderObjectFunction - * @param {Object3D} object - The 3D object to render. - * @param {Scene} scene - The scene containing the object. - * @param {Camera} _camera - The camera used for rendering. - * @param {BufferGeometry} geometry - The geometry of the object. - * @param {Material} material - The material of the object. - * @param {Group} group - The group the object belongs to. - * @param {...any} params - Additional parameters for rendering. - */ - /** * TSL function for creating an instance of `ShadowNode`. * @@ -49467,7 +49504,6 @@ var TSL = /*#__PURE__*/Object.freeze({ directionToColor: directionToColor, directionToFaceDirection: directionToFaceDirection, dispersion: dispersion, - disposeShadowMaterial: disposeShadowMaterial, distance: distance, div: div, dot: dot, @@ -49507,8 +49543,6 @@ var TSL = /*#__PURE__*/Object.freeze({ getScreenPosition: getScreenPosition, getScreenPositionFromClip: getScreenPositionFromClip, getShIrradianceAt: getShIrradianceAt, - getShadowMaterial: getShadowMaterial, - getShadowRenderObjectFunction: getShadowRenderObjectFunction, getTextureIndex: getTextureIndex, getViewPosition: getViewPosition, globalId: globalId, @@ -89175,6 +89209,10 @@ class WebGPURenderer extends Renderer { * are considered as one render bundle and processed as such by * the renderer. * + * Only renderable 3D objects are allowed in a bundle group. Other + * types like lights are not supported and must be added to the scene + * outside of the group. + * * This module is only fully supported by `WebGPURenderer` with a WebGPU backend. * With a WebGL backend, the group can technically be rendered but without * any performance improvements. diff --git a/build/three.webgpu.nodes.js b/build/three.webgpu.nodes.js index 516e1d1e227207..bf792dc6b1c86e 100644 --- a/build/three.webgpu.nodes.js +++ b/build/three.webgpu.nodes.js @@ -3,7 +3,7 @@ * Copyright 2010-2026 Three.js Authors * SPDX-License-Identifier: MIT */ -import { DynamicDrawUsage, RenderObjectRefreshType, Color, Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, UnsignedIntType, IntType, error, RedFormat, RedIntegerFormat, DepthFormat, DepthStencilFormat, AlphaFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBIntegerFormat, EventDispatcher, MathUtils, warn, WebGLCoordinateSystem, WebGPUCoordinateSystem, ColorManagement, SRGBTransfer, NoToneMapping, StaticDrawUsage, InterleavedBufferAttribute, InterleavedBuffer, NoColorSpace, log as log$1, warnOnce, Texture, Compatibility, LessCompare, LessEqualCompare, GreaterCompare, GreaterEqualCompare, NearestFilter, Sphere, BackSide, DoubleSide, CubeTexture, CubeReflectionMapping, CubeRefractionMapping, TangentSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking, ObjectSpaceNormalMap, RED_GREEN_RGTC2_Format, RG11_EAC_Format, InstancedBufferAttribute, InstancedInterleavedBuffer, DataTexture, RGBAFormat, FloatType, DataArrayTexture, FramebufferTexture, LinearMipmapLinearFilter, DepthTexture, Material, LineBasicMaterial, LineDashedMaterial, NoBlending, MeshNormalMaterial, SRGBColorSpace, RenderTarget, BoxGeometry, Mesh, Scene, LinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, AddOperation, MixOperation, MultiplyOperation, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, HalfFloatType, ClampToEdgeWrapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, LinearSRGBColorSpace, CubeUVReflectionMapping, BufferAttribute, MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial, MeshMatcapMaterial, SpriteMaterial, PointsMaterial, ShadowMaterial, Uint32BufferAttribute, Uint16BufferAttribute, ByteType, UnsignedByteType, ShortType, UnsignedShortType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, NormalBlending, SrcAlphaFactor, OneMinusSrcAlphaFactor, AddEquation, MaterialBlending, Object3D, LinearMipMapLinearFilter, Plane, Float32BufferAttribute, UVMapping, PCFShadowMap, VSMShadowMap, BasicShadowMap, CubeDepthTexture, SphereGeometry, LinearMipmapNearestFilter, NearestMipmapLinearFilter, Float16BufferAttribute, yieldToMain, REVISION, ArrayCamera, PlaneGeometry, FrontSide, CustomBlending, ZeroFactor, CylinderGeometry, Quaternion, WebXRController, RAD2DEG, PCFSoftShadowMap, FrustumArray, Frustum, RGBAIntegerFormat, TimestampQuery, createCanvasElement, MaxEquation, MinEquation, ReverseSubtractEquation, SubtractEquation, OneMinusConstantAlphaFactor, ConstantAlphaFactor, OneMinusConstantColorFactor, ConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcColorFactor, OneFactor, CullFaceNone, CullFaceBack, CullFaceFront, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, ReversedDepthFuncs, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, SIGNED_RED_GREEN_RGTC2_Format, MirroredRepeatWrapping, RepeatWrapping, NearestMipmapNearestFilter, NotEqualCompare, EqualCompare, AlwaysCompare, NeverCompare, LinearTransfer, getByteLength, isTypedArray, NotEqualStencilFunc, GreaterStencilFunc, GreaterEqualStencilFunc, EqualStencilFunc, LessEqualStencilFunc, LessStencilFunc, AlwaysStencilFunc, NeverStencilFunc, DecrementWrapStencilOp, IncrementWrapStencilOp, DecrementStencilOp, IncrementStencilOp, InvertStencilOp, ReplaceStencilOp, ZeroStencilOp, KeepStencilOp, SpotLight, PointLight, DirectionalLight, RectAreaLight, AmbientLight, HemisphereLight, LightProbe, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping, Group, Loader, FileLoader, MaterialLoader, ObjectLoader } from './three.core.js'; +import { DynamicDrawUsage, RenderObjectRefreshType, Color, Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, UnsignedIntType, IntType, error, RedFormat, RedIntegerFormat, DepthFormat, DepthStencilFormat, AlphaFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBIntegerFormat, EventDispatcher, MathUtils, warn, WebGLCoordinateSystem, WebGPUCoordinateSystem, ColorManagement, SRGBTransfer, NoToneMapping, StaticDrawUsage, InterleavedBufferAttribute, InterleavedBuffer, NoColorSpace, log as log$1, warnOnce, Texture, Compatibility, LessCompare, LessEqualCompare, GreaterCompare, GreaterEqualCompare, NearestFilter, Sphere, BackSide, DoubleSide, CubeTexture, CubeReflectionMapping, CubeRefractionMapping, TangentSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking, ObjectSpaceNormalMap, RED_GREEN_RGTC2_Format, RG11_EAC_Format, InstancedBufferAttribute, InstancedInterleavedBuffer, DataTexture, RGBAFormat, FloatType, DataArrayTexture, FramebufferTexture, LinearMipmapLinearFilter, DepthTexture, Material, LineBasicMaterial, LineDashedMaterial, NoBlending, MeshNormalMaterial, SRGBColorSpace, RenderTarget, BoxGeometry, Mesh, Scene, LinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, AddOperation, MixOperation, MultiplyOperation, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, HalfFloatType, ClampToEdgeWrapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, LinearSRGBColorSpace, CubeUVReflectionMapping, BufferAttribute, MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial, MeshMatcapMaterial, SpriteMaterial, PointsMaterial, ShadowMaterial, Uint32BufferAttribute, Uint16BufferAttribute, ByteType, UnsignedByteType, ShortType, UnsignedShortType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, NormalBlending, SrcAlphaFactor, OneMinusSrcAlphaFactor, AddEquation, MaterialBlending, Object3D, LinearMipMapLinearFilter, Plane, Float32BufferAttribute, UVMapping, VSMShadowMap, PCFShadowMap, BasicShadowMap, CubeDepthTexture, SphereGeometry, LinearMipmapNearestFilter, NearestMipmapLinearFilter, Float16BufferAttribute, yieldToMain, REVISION, ArrayCamera, PlaneGeometry, FrontSide, CustomBlending, ZeroFactor, CylinderGeometry, Quaternion, WebXRController, RAD2DEG, PCFSoftShadowMap, FrustumArray, Frustum, RGBAIntegerFormat, TimestampQuery, createCanvasElement, MaxEquation, MinEquation, ReverseSubtractEquation, SubtractEquation, OneMinusConstantAlphaFactor, ConstantAlphaFactor, OneMinusConstantColorFactor, ConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcColorFactor, OneFactor, CullFaceNone, CullFaceBack, CullFaceFront, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, ReversedDepthFuncs, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, SIGNED_RED_GREEN_RGTC2_Format, MirroredRepeatWrapping, RepeatWrapping, NearestMipmapNearestFilter, NotEqualCompare, EqualCompare, AlwaysCompare, NeverCompare, LinearTransfer, getByteLength, isTypedArray, NotEqualStencilFunc, GreaterStencilFunc, GreaterEqualStencilFunc, EqualStencilFunc, LessEqualStencilFunc, LessStencilFunc, AlwaysStencilFunc, NeverStencilFunc, DecrementWrapStencilOp, IncrementWrapStencilOp, DecrementStencilOp, IncrementStencilOp, InvertStencilOp, ReplaceStencilOp, ZeroStencilOp, KeepStencilOp, SpotLight, PointLight, DirectionalLight, RectAreaLight, AmbientLight, HemisphereLight, LightProbe, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping, Group, Loader, FileLoader, MaterialLoader, ObjectLoader } from './three.core.js'; export { AdditiveAnimationBlendMode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BatchedMesh, BezierInterpolant, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, Controls, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CustomToneMapping, Cylindrical, Data3DTexture, DataTextureLoader, DataUtils, DefaultLoadingManager, DetachedBindMode, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, Euler, ExternalTexture, ExtrudeGeometry, Fog, FogExp2, GLBufferAttribute, GLSL1, GLSL3, GridHelper, HTMLTexture, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, InstancedBufferGeometry, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, Interpolant, InterpolateBezier, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, KeyframeTrack, LOD, LatheGeometry, Layers, Light, Line, Line3, LineCurve, LineCurve3, LineLoop, LineSegments, LinearInterpolant, LinearMipMapNearestFilter, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, MeshDepthMaterial, MeshDistanceMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NormalAnimationBlendMode, NumberKeyframeTrack, OctahedronGeometry, Path, PlaneHelper, PointLightHelper, Points, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBADepthPacking, RGBDepthPacking, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RenderTarget3D, RingGeometry, ShaderMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Spherical, SphericalHarmonics3, SplineCurve, SpotLightHelper, Sprite, StaticCopyUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SunLight, TOUCH, TetrahedronGeometry, TextureLoader, TextureSource, TextureUtils, Timer, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLRenderTarget, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, getConsoleFunction, setConsoleFunction } from './three.core.js'; const refreshUniforms = [ @@ -39009,11 +39009,19 @@ class RTTNode extends TextureNode { * @param {Node} node - The node to render a texture with. * @param {?number} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. * @param {?number} [height=null] - The height of the internal render target. - * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @param {Object} [options={}] - The options for the internal render target. + * @param {number} [options.type=HalfFloatType] - The texture type. + * @param {boolean} [options.autoUpdate=true] - Whether the texture should automatically be updated or not. + * @param {number} [options.resolutionScale=1] - The resolution scale. */ - constructor( node, width = null, height = null, options = { type: HalfFloatType } ) { + constructor( node, width = null, height = null, options = {} ) { - const renderTarget = new RenderTarget( width, height, options ); + const { + autoUpdate = true, + resolutionScale = 1 + } = options; + + const renderTarget = new RenderTarget( width, height, { type: HalfFloatType, ...options } ); super( renderTarget.texture, uv$1() ); @@ -39071,7 +39079,7 @@ class RTTNode extends TextureNode { * @type {boolean} * @default true */ - this.autoUpdate = true; + this.autoUpdate = autoUpdate; /** * The resolution scale @@ -39080,7 +39088,7 @@ class RTTNode extends TextureNode { * @type {number} * @default 1 */ - this._resolutionScale = 1; + this._resolutionScale = resolutionScale; /** * The internal quad mesh for RTT. @@ -39243,7 +39251,10 @@ class RTTNode extends TextureNode { * @param {Node} node - The node to render a texture with. * @param {?number} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. * @param {?number} [height=null] - The height of the internal render target. - * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @param {Object} [options={}] - The options for the internal render target. + * @param {number} [options.type=HalfFloatType] - The texture type. + * @param {boolean} [options.autoUpdate=true] - Whether the texture should automatically be updated or not. + * @param {number} [options.resolutionScale=1] - The resolution scale. * @returns {RTTNode} */ const rtt = ( node, ...params ) => new RTTNode( nodeObject( node ), ...params ); @@ -39256,7 +39267,10 @@ const rtt = ( node, ...params ) => new RTTNode( nodeObject( node ), ...params ); * @param {Node} node - The node to render a texture with. * @param {?number} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. * @param {?number} [height=null] - The height of the internal render target. - * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @param {Object} [options={}] - The options for the internal render target. + * @param {number} [options.type=HalfFloatType] - The texture type. + * @param {boolean} [options.autoUpdate=true] - Whether the texture should automatically be updated or not. + * @param {number} [options.resolutionScale=1] - The resolution scale. * @returns {RTTNode} */ const convertToTexture = ( node, ...params ) => { @@ -45045,6 +45059,118 @@ class LightsNode extends Node { */ const lights = ( lights = [] ) => new LightsNode().setLights( lights ); +const _shadowMaterialLib = /*@__PURE__*/ new WeakMap(); +const _shadowRenderObjectLibrary = /*@__PURE__*/ new ChainMap(); +const _shadowRenderObjectKeys = []; + +/** + * Retrieves or creates a shadow material for the given light source. + * + * This function checks if a shadow material already exists for the provided light. + * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it + * in the `shadowMaterialLib` for future use. + * + * @private + * @function + * @param {Light} light - The light source for which the shadow material is needed. + * If the light is a point light, a depth node is calculated + * using the linear shadow distance. + * @returns {NodeMaterial} The shadow material associated with the given light. + */ +const _getShadowMaterial = ( light ) => { + + let material = _shadowMaterialLib.get( light ); + + if ( material === undefined ) { + + material = new NodeMaterial(); + material.colorNode = vec4( 0, 0, 0, 1 ); + material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode + material.name = 'ShadowMaterial'; + material.blending = NoBlending; + material.fog = false; + + _shadowMaterialLib.set( light, material ); + + } + + return material; + +}; + +/** + * Disposes the shadow material for the given light source. + * + * @private + * @param {Light} light - The light source. + */ +const _disposeShadowMaterial = ( light ) => { + + const material = _shadowMaterialLib.get( light ); + + if ( material !== undefined ) { + + material.dispose(); + _shadowMaterialLib.delete( light ); + + } + +}; + +/** + * Creates a function to render shadow objects in a scene. + * + * @private + * @function + * @param {Renderer} renderer - The renderer. + * @param {LightShadow} shadow - The light shadow object containing shadow properties. + * @param {number} shadowType - The type of shadow map (e.g., BasicShadowMap). + * @param {boolean} useVelocity - Whether to use velocity data for rendering. + * @return {shadowRenderObjectFunction} A function that renders shadow objects. + */ +const _getShadowRenderObjectFunction = ( renderer, shadow, shadowType, useVelocity ) => { + + _shadowRenderObjectKeys[ 0 ] = renderer; + _shadowRenderObjectKeys[ 1 ] = shadow; + + let renderObjectFunction = _shadowRenderObjectLibrary.get( _shadowRenderObjectKeys ); + + if ( renderObjectFunction === undefined || ( renderObjectFunction.shadowType !== shadowType || renderObjectFunction.useVelocity !== useVelocity ) ) { + + renderObjectFunction = ( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ) => { + + if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { + + if ( useVelocity ) { + + getDataFromObject( object ).useVelocity = true; + + } + + object.onBeforeShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); + + renderer.renderObject( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ); + + object.onAfterShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); + + } + + }; + + renderObjectFunction.shadowType = shadowType; + renderObjectFunction.useVelocity = useVelocity; + + _shadowRenderObjectLibrary.set( _shadowRenderObjectKeys, renderObjectFunction ); + + } + + _shadowRenderObjectKeys[ 0 ] = null; + _shadowRenderObjectKeys[ 1 ] = null; + + return renderObjectFunction; + +}; + /** * Base class for all shadow nodes. * @@ -45097,6 +45223,47 @@ class ShadowBaseNode extends Node { } + /** + * Retrieves or creates a shadow material for the shadow casting light source. + * + * This method checks if a shadow material already exists for the provided light in the internal library. + * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it for future use. + * + * @return {NodeMaterial} The shadow material associated with the given light. + */ + getShadowMaterial() { + + return _getShadowMaterial( this.light ); + + } + + /** + * Disposes the shadow material for the shadow casting light source. + */ + disposeShadowMaterial() { + + _disposeShadowMaterial( this.light ); + + } + + /** + * Returns a function to render shadow objects in a scene for the given light shadow and renderer. + * + * @param {Renderer} renderer - The renderer. + * @param {LightShadow} [shadow=this.light.shadow] - The light shadow object containing shadow properties. + * @return {Function} A function that renders shadow objects. + */ + getShadowRenderObjectFunction( renderer, shadow = this.light.shadow ) { + + const shadowType = renderer.shadowMap.type; + + const currentMRT = renderer.getMRT(); + const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; + + return _getShadowRenderObjectFunction( renderer, shadow, shadowType, useVelocity ); + + } + /** * Setups the shadow position node which is by default the predefined TSL node object `shadowPositionWorld`. * @@ -45332,8 +45499,6 @@ var RendererUtils = /*#__PURE__*/Object.freeze({ saveSceneState: saveSceneState }); -const shadowMaterialLib = /*@__PURE__*/ new WeakMap(); - /** * A shadow filtering function performing basic filtering. This is in fact an unfiltered version of the shadow map * with a binary `[0,1]` result. @@ -45454,118 +45619,6 @@ const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, depthLa } ); -/** - * Retrieves or creates a shadow material for the given light source. - * - * This function checks if a shadow material already exists for the provided light. - * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it - * in the `shadowMaterialLib` for future use. - * - * @tsl - * @function - * @param {Light} light - The light source for which the shadow material is needed. - * If the light is a point light, a depth node is calculated - * using the linear shadow distance. - * @returns {NodeMaterial} The shadow material associated with the given light. - */ -const getShadowMaterial = ( light ) => { - - let material = shadowMaterialLib.get( light ); - - if ( material === undefined ) { - - material = new NodeMaterial(); - material.colorNode = vec4( 0, 0, 0, 1 ); - material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode - material.name = 'ShadowMaterial'; - material.blending = NoBlending; - material.fog = false; - - shadowMaterialLib.set( light, material ); - - } - - return material; - -}; - -/** - * Disposes the shadow material for the given light source. - * - * @param {Light} light - The light source. - */ -const disposeShadowMaterial = ( light ) => { - - const material = shadowMaterialLib.get( light ); - - if ( material !== undefined ) { - - material.dispose(); - shadowMaterialLib.delete( light ); - - } - -}; - -// - -const _shadowRenderObjectLibrary = /*@__PURE__*/ new ChainMap(); -const _shadowRenderObjectKeys = []; - -/** - * Creates a function to render shadow objects in a scene. - * - * @tsl - * @function - * @param {Renderer} renderer - The renderer. - * @param {LightShadow} shadow - The light shadow object containing shadow properties. - * @param {number} shadowType - The type of shadow map (e.g., BasicShadowMap). - * @param {boolean} useVelocity - Whether to use velocity data for rendering. - * @return {shadowRenderObjectFunction} A function that renders shadow objects. - */ -const getShadowRenderObjectFunction = ( renderer, shadow, shadowType, useVelocity ) => { - - _shadowRenderObjectKeys[ 0 ] = renderer; - _shadowRenderObjectKeys[ 1 ] = shadow; - - let renderObjectFunction = _shadowRenderObjectLibrary.get( _shadowRenderObjectKeys ); - - if ( renderObjectFunction === undefined || ( renderObjectFunction.shadowType !== shadowType || renderObjectFunction.useVelocity !== useVelocity ) ) { - - renderObjectFunction = ( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ) => { - - if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { - - if ( useVelocity ) { - - getDataFromObject( object ).useVelocity = true; - - } - - object.onBeforeShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); - - renderer.renderObject( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ); - - object.onAfterShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); - - } - - }; - - renderObjectFunction.shadowType = shadowType; - renderObjectFunction.useVelocity = useVelocity; - - _shadowRenderObjectLibrary.set( _shadowRenderObjectKeys, renderObjectFunction ); - - } - - _shadowRenderObjectKeys[ 0 ] = null; - _shadowRenderObjectKeys[ 1 ] = null; - - return renderObjectFunction; - -}; - /** * Represents the shader code for the first VSM render pass. * @@ -46208,7 +46261,7 @@ class ShadowNode extends ShadowBaseNode { */ updateShadow( frame ) { - const { shadowMap, light, shadow } = this; + const { shadowMap, shadow } = this; const { renderer, scene, camera } = frame; const shadowType = renderer.shadowMap.type; @@ -46226,14 +46279,11 @@ class ShadowNode extends ShadowBaseNode { const currentRenderObjectFunction = renderer.getRenderObjectFunction(); - const currentMRT = renderer.getMRT(); - const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; - _rendererState = resetRendererAndSceneState( renderer, scene, _rendererState ); - scene.overrideMaterial = getShadowMaterial( light ); + scene.overrideMaterial = this.getShadowMaterial(); - renderer.setRenderObjectFunction( getShadowRenderObjectFunction( renderer, shadow, shadowType, useVelocity ) ); + renderer.setRenderObjectFunction( this.getShadowRenderObjectFunction( renderer, this.shadow || this.light.shadow ) ); renderer.setClearColor( 0x000000, 0 ); @@ -46300,7 +46350,7 @@ class ShadowNode extends ShadowBaseNode { this._currentShadowType = null; - disposeShadowMaterial( this.light ); + this.disposeShadowMaterial(); if ( this.shadowMap ) { @@ -46374,19 +46424,6 @@ class ShadowNode extends ShadowBaseNode { } -/** - * Shadow Render Object Function. - * - * @function shadowRenderObjectFunction - * @param {Object3D} object - The 3D object to render. - * @param {Scene} scene - The scene containing the object. - * @param {Camera} _camera - The camera used for rendering. - * @param {BufferGeometry} geometry - The geometry of the object. - * @param {Material} material - The material of the object. - * @param {Group} group - The group the object belongs to. - * @param {...any} params - Additional parameters for rendering. - */ - /** * TSL function for creating an instance of `ShadowNode`. * @@ -49467,7 +49504,6 @@ var TSL = /*#__PURE__*/Object.freeze({ directionToColor: directionToColor, directionToFaceDirection: directionToFaceDirection, dispersion: dispersion, - disposeShadowMaterial: disposeShadowMaterial, distance: distance, div: div, dot: dot, @@ -49507,8 +49543,6 @@ var TSL = /*#__PURE__*/Object.freeze({ getScreenPosition: getScreenPosition, getScreenPositionFromClip: getScreenPositionFromClip, getShIrradianceAt: getShIrradianceAt, - getShadowMaterial: getShadowMaterial, - getShadowRenderObjectFunction: getShadowRenderObjectFunction, getTextureIndex: getTextureIndex, getViewPosition: getViewPosition, globalId: globalId, @@ -89122,6 +89156,10 @@ class WebGPURenderer extends Renderer { * are considered as one render bundle and processed as such by * the renderer. * + * Only renderable 3D objects are allowed in a bundle group. Other + * types like lights are not supported and must be added to the scene + * outside of the group. + * * This module is only fully supported by `WebGPURenderer` with a WebGPU backend. * With a WebGL backend, the group can technically be rendered but without * any performance improvements. diff --git a/examples/jsm/inspector/extensions/color-grading/LUT3DStyle.js b/examples/jsm/inspector/extensions/color-grading/LUT3DStyle.js index dc23f2cc99cee3..95905d6efa3a90 100644 --- a/examples/jsm/inspector/extensions/color-grading/LUT3DStyle.js +++ b/examples/jsm/inspector/extensions/color-grading/LUT3DStyle.js @@ -24,6 +24,7 @@ export class LUT3DStyle { flex-direction: column; gap: 8px; box-sizing: border-box; + color-scheme: dark; /* Ultra-Subtle Transparent Blueprint / Checkerboard Grid Background */ background-color: transparent; @@ -96,13 +97,16 @@ export class LUT3DStyle { border: none !important; outline: none; cursor: pointer; + color-scheme: dark; transition: color 0.15s; } .lut-dock-select option, - .lut-container select option { - background-color: #1e1e24; - color: #e0e0e0; + .lut-select option, + select option, + option { + background-color: #1e1e24 !important; + color: var(--text-primary, #e0e0e0) !important; } .lut-dock-select:hover { @@ -620,7 +624,7 @@ export class LUT3DStyle { flex-shrink: 0; } - .lut-select, .lut-container select, .lut-toolbar select { + .lut-select, .lut-container select, .lut-toolbar select, select { height: 22px; font-family: var(--font-family, sans-serif); font-size: 11px; @@ -630,10 +634,17 @@ export class LUT3DStyle { padding: 0 4px; outline: none; cursor: pointer; + color-scheme: dark; flex-shrink: 1; min-width: 40px; } + .lut-select option, + select option { + background-color: #1e1e24 !important; + color: var(--text-primary, #e0e0e0) !important; + } + .lut-select-compact { height: 20px; font-size: 10.5px; diff --git a/examples/jsm/inspector/tabs/Viewer.js b/examples/jsm/inspector/tabs/Viewer.js index 72450aa751e3b6..ca1b6a5bb31cbb 100644 --- a/examples/jsm/inspector/tabs/Viewer.js +++ b/examples/jsm/inspector/tabs/Viewer.js @@ -624,6 +624,7 @@ class Viewer extends Tab { this.splitActive = true; this.splitCanvasData = canvasData; + this.splitX = 0.5; const renderer = this.inspector.getRenderer(); const mainCanvas = renderer.domElement; @@ -756,13 +757,11 @@ class Viewer extends Tab { } else { - const thickness = float( 1 ).div( this.splitUniforms.viewportWidth ); - const isLine = screenUV.x.sub( this.splitUniforms.splitX ).abs().lessThan( thickness ); finalColor = Fn( () => { screenUV.x.lessThan( this.splitUniforms.splitX ).discard(); - return isLine.select( vec4( 0.29, 0.29, 0.35, 1.0 ), targetColorCtx ); + return targetColorCtx; } )(); @@ -978,7 +977,7 @@ class Viewer extends Tab { } - if ( this.splitCanvasTarget.domElement.width !== rect.width || this.splitCanvasTarget.domElement.height !== rect.height ) { + if ( this.splitCanvasTarget.width !== rect.width || this.splitCanvasTarget.height !== rect.height ) { this.splitCanvasTarget.setSize( rect.width, rect.height ); diff --git a/examples/jsm/inspector/ui/Style.js b/examples/jsm/inspector/ui/Style.js index 861ef6195a2350..f0da31cf05f275 100644 --- a/examples/jsm/inspector/ui/Style.js +++ b/examples/jsm/inspector/ui/Style.js @@ -29,6 +29,7 @@ export class Style { pointer-events: none; z-index: 1000; overflow: hidden; + color-scheme: dark; } :scope * { @@ -1437,6 +1438,7 @@ export class Style { font-family: var(--font-mono); width: 100%; box-sizing: border-box; + color-scheme: dark; } .param-control input:focus { @@ -2019,6 +2021,16 @@ export class Style { background-color: rgba(255, 255, 255, 0.05); } + select { + color-scheme: dark; + } + + select option, + option { + background-color: #1e1e24; + color: var(--text-primary); + } + .select { background: var(--profiler-background); border: 1px solid var(--profiler-border); @@ -2029,6 +2041,7 @@ export class Style { font-size: 12px; outline: none; cursor: pointer; + color-scheme: dark; appearance: none; -webkit-appearance: none; -moz-appearance: none; @@ -2099,14 +2112,14 @@ export class Style { position: absolute; top: 0; bottom: 0; - width: 4px; - margin-left: -2px; + width: 0; left: 50%; - background: var(--profiler-border); + background: transparent; cursor: ew-resize; pointer-events: auto !important; z-index: 10; touch-action: none; + transform: translateX(-50%); } .split-screen-line::before { @@ -2114,12 +2127,38 @@ export class Style { position: absolute; top: 0; bottom: 0; - left: -10px; + left: -12px; width: 24px; background: transparent; cursor: ew-resize; } + .split-screen-line::after { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: -7px; + width: 14px; + pointer-events: none; + background-image: + url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='8' viewBox='0 0 14 8'%3E%3Cpath d='M0 0 L14 0 L7 8 Z' fill='%239a9aab'/%3E%3C/svg%3E"), + url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='8' viewBox='0 0 14 8'%3E%3Cpath d='M0 8 L14 8 L7 0 Z' fill='%239a9aab'/%3E%3C/svg%3E"); + background-position: top center, bottom center; + background-repeat: no-repeat; + opacity: 0.8; + filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6)); + transition: opacity 0.2s, filter 0.2s; + } + + .split-screen-line:hover::after { + opacity: 1; + background-image: + url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='8' viewBox='0 0 14 8'%3E%3Cpath d='M0 0 L14 0 L7 8 Z' fill='%2300aaff'/%3E%3C/svg%3E"), + url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='8' viewBox='0 0 14 8'%3E%3Cpath d='M0 8 L14 8 L7 0 Z' fill='%2300aaff'/%3E%3C/svg%3E"); + filter: drop-shadow(0 0 4px rgba(0, 170, 255, 0.8)); + } + /* Grid Mode styles for List component */ .list-scroll-wrapper:has(> .list-container.grid-mode) { width: 100% !important; diff --git a/examples/jsm/loaders/usd/USDAParser.js b/examples/jsm/loaders/usd/USDAParser.js index 7c23df4c50e29d..fbe60dff840c20 100644 --- a/examples/jsm/loaders/usd/USDAParser.js +++ b/examples/jsm/loaders/usd/USDAParser.js @@ -2,6 +2,8 @@ const DEF_MATCH_REGEX = /^def\s+(?:(\w+)\s+)?"?([^"]+)"?$/; const VARIANT_STRING_REGEX = /^string\s+(\w+)$/; const ATTR_MATCH_REGEX = /^(?:uniform\s+)?(\w+(?:\[\])?)\s+(.+)$/; +// Preserve metadata blocks without changing the legacy parseText value shape. +const VALUE_METADATA = Symbol( 'valueMetadata' ); // Spec types (must match USDCParser/USDComposer) const SpecType = { @@ -55,10 +57,12 @@ class USDAParser { // see #28631 - const values = rhs.slice( 0, - 1 ); + const values = rhs.slice( 0, - 1 ).trim(); target[ lhs ] = values; const meta = {}; + if ( target[ VALUE_METADATA ] === undefined ) target[ VALUE_METADATA ] = {}; + target[ VALUE_METADATA ][ lhs ] = meta; stack.push( meta ); target = meta; @@ -621,9 +625,18 @@ class USDAParser { const relName = key.slice( 4 ); const relPath = path + '.' + relName; const target = data[ key ].replace( /[<>]/g, '' ); + const metadata = data[ VALUE_METADATA ]?.[ key ]; + const fields = { targetPaths: [ target ] }; + + if ( metadata?.bindMaterialAs !== undefined ) { + + fields.bindMaterialAs = this._parseString( String( metadata.bindMaterialAs ).trim() ); + + } + specsByPath[ relPath ] = { specType: SpecType.Relationship, - fields: { targetPaths: [ target ] } + fields }; continue; diff --git a/examples/jsm/loaders/usd/USDCParser.js b/examples/jsm/loaders/usd/USDCParser.js index 5ca52a504acfce..47f2eb8599c2db 100644 --- a/examples/jsm/loaders/usd/USDCParser.js +++ b/examples/jsm/loaders/usd/USDCParser.js @@ -656,10 +656,7 @@ class USDCParser { const reader = this.reader; reader.seek( section.start ); - // Strings section has an 8-byte count prefix, but string indices stored - // elsewhere in the file are relative to the section start (not the data). - // So we read the entire section as uint32 values to maintain correct indexing. - const numStrings = Math.floor( section.size / 4 ); + const numStrings = reader.readUint64(); this.strings = []; for ( let i = 0; i < numStrings; i ++ ) { diff --git a/examples/jsm/loaders/usd/USDComposer.js b/examples/jsm/loaders/usd/USDComposer.js index 5de046b2ab54aa..be4ca92d1a110a 100644 --- a/examples/jsm/loaders/usd/USDComposer.js +++ b/examples/jsm/loaders/usd/USDComposer.js @@ -1081,6 +1081,47 @@ class USDComposer { } + /** + * Resolve an attribute's authored value, following connections before using + * local fallback values. + */ + _resolveAttributeValue( path, visited = new Set() ) { + + const cleanPath = String( path ).replace( /<|>/g, '' ); + if ( visited.has( cleanPath ) ) return undefined; + + const fields = this.specsByPath[ cleanPath ]?.fields; + if ( ! fields ) return undefined; + + const nextVisited = new Set( visited ); + nextVisited.add( cleanPath ); + + if ( fields.connectionPaths ) { + + for ( const connectionPath of fields.connectionPaths ) { + + const value = this._resolveAttributeValue( connectionPath, nextVisited ); + if ( value !== undefined ) return value; + + } + + } + + if ( fields.default !== undefined ) return fields.default; + + const { times, values } = fields.timeSamples || {}; + if ( times && values && times.length > 0 ) { + + // Find time 0, or use the first available time (rest pose). + const index = times.indexOf( 0 ); + return values[ index >= 0 ? index : 0 ]; + + } + + return undefined; + + } + /** * Get attributes for a path from attribute specs. */ @@ -1141,21 +1182,10 @@ class USDComposer { for ( const [ attrName, attrSpec ] of attrMap ) { - if ( attrSpec.fields?.default !== undefined ) { + const value = this._resolveAttributeValue( path + '.' + attrName ); + if ( value !== undefined ) { - attrs[ attrName ] = attrSpec.fields.default; - - } else if ( attrSpec.fields?.timeSamples ) { - - // For animated attributes without default, use the first time sample (rest pose) - const { times, values } = attrSpec.fields.timeSamples; - if ( times && values && times.length > 0 ) { - - // Find time 0, or use the first available time - const idx = times.indexOf( 0 ); - attrs[ attrName ] = idx >= 0 ? values[ idx ] : values[ 0 ]; - - } + attrs[ attrName ] = value; } @@ -1634,22 +1664,16 @@ class USDComposer { } /** - * Get material binding target path, checking variant paths if needed. + * Get the material binding relationship for a prim, including overrides from + * active variants. */ - _getMaterialBindingTarget( primPath ) { + _getMaterialBindingSpec( primPath ) { const attrName = 'material:binding'; - - // First check direct path const directPath = primPath + '.' + attrName; - const directSpec = this.specsByPath[ directPath ]; - if ( directSpec?.fields?.targetPaths?.length > 0 ) { + let bindingSpec = this.specsByPath[ directPath ] || null; - return directSpec.fields.targetPaths[ 0 ]; - - } - - // Check variant paths at ancestor levels + // A variant on any ancestor may override this prim's relationship. const parts = primPath.split( '/' ); for ( let i = 1; i < parts.length; i ++ ) { @@ -1664,7 +1688,7 @@ class USDComposer { if ( overrideSpec?.fields?.targetPaths?.length > 0 ) { - return overrideSpec.fields.targetPaths[ 0 ]; + bindingSpec = overrideSpec; } @@ -1672,7 +1696,35 @@ class USDComposer { } - return null; + return bindingSpec; + + } + + /** + * Get the resolved material binding target for a prim. Material bindings are + * inherited, and an ancestor marked strongerThanDescendants takes precedence + * over bindings authored on its descendants. + */ + _getMaterialBindingTarget( primPath ) { + + const parts = primPath.split( '/' ).filter( Boolean ); + let resolvedBinding = null; + + for ( let i = 0; i < parts.length; i ++ ) { + + const ancestorPath = '/' + parts.slice( 0, i + 1 ).join( '/' ); + const bindingSpec = this._getMaterialBindingSpec( ancestorPath ); + if ( ! bindingSpec?.fields?.targetPaths?.length ) continue; + + if ( ! resolvedBinding || resolvedBinding.fields?.bindMaterialAs !== 'strongerThanDescendants' ) { + + resolvedBinding = bindingSpec; + + } + + } + + return resolvedBinding?.fields.targetPaths[ 0 ] || null; } @@ -2917,21 +2969,7 @@ class USDComposer { */ _applyMaterialBinding( mesh, primPath ) { - // Look for material:binding on this prim - const bindingPath = primPath + '.material:binding'; - const bindingSpec = this.specsByPath[ bindingPath ]; - - if ( ! bindingSpec ) return; - - let materialPath = null; - const targetPaths = bindingSpec.fields?.targetPaths || bindingSpec.fields?.default; - - if ( targetPaths ) { - - materialPath = Array.isArray( targetPaths ) ? targetPaths[ 0 ] : targetPaths; - - } - + let materialPath = this._getMaterialBindingTarget( primPath ); if ( ! materialPath ) return; // Clean the material path diff --git a/examples/jsm/tsl/shadows/TileShadowNode.js b/examples/jsm/tsl/shadows/TileShadowNode.js index eb0874fafcb9ca..bd18e939adbbf1 100644 --- a/examples/jsm/tsl/shadows/TileShadowNode.js +++ b/examples/jsm/tsl/shadows/TileShadowNode.js @@ -14,7 +14,7 @@ import { Quaternion } from 'three/webgpu'; -import { min, Fn, shadow, NodeUpdateType, getShadowMaterial, getShadowRenderObjectFunction } from 'three/tsl'; +import { min, Fn, shadow, NodeUpdateType } from 'three/tsl'; const { resetRendererAndSceneState, restoreRendererAndSceneState } = RendererUtils; let _rendererState; @@ -273,14 +273,11 @@ class TileShadowNode extends ShadowBaseNode { const depthVersion = shadowMap.depthTexture.version; this._depthVersionCached = depthVersion; const currentRenderObjectFunction = renderer.getRenderObjectFunction(); - const currentMRT = renderer.getMRT(); - const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; _rendererState = resetRendererAndSceneState( renderer, scene, _rendererState ); - scene.overrideMaterial = getShadowMaterial( light ); + scene.overrideMaterial = this.getShadowMaterial(); renderer.setRenderTarget( this.shadowMap ); - for ( let index = 0; index < this.lights.length; index ++ ) { const light = this.lights[ index ]; @@ -297,7 +294,7 @@ class TileShadowNode extends ShadowBaseNode { shadow.updateMatrices( light ); - renderer.setRenderObjectFunction( getShadowRenderObjectFunction( renderer, shadow, shadowType, useVelocity ) ); + renderer.setRenderObjectFunction( this.getShadowRenderObjectFunction( renderer, shadow ) ); this.shadowMap.setSize( shadow.mapSize.width, shadow.mapSize.height, shadowMap.depth ); } @@ -447,6 +444,7 @@ class TileShadowNode extends ShadowBaseNode { // Dispose lights, nodes, and shadow map this.disposeLightsAndNodes(); + this.disposeShadowMaterial(); super.dispose(); } diff --git a/src/Three.TSL.js b/src/Three.TSL.js index abe079e6a91daa..c9e7abee3ec722 100644 --- a/src/Three.TSL.js +++ b/src/Three.TSL.js @@ -2,6 +2,7 @@ import { TSL } from 'three/webgpu'; export const BRDF_GGX = TSL.BRDF_GGX; export const BRDF_Lambert = TSL.BRDF_Lambert; +export const BRDF_Sheen = TSL.BRDF_Sheen; export const BasicPointShadowFilter = TSL.BasicPointShadowFilter; export const BasicShadowFilter = TSL.BasicShadowFilter; export const Break = TSL.Break; @@ -9,10 +10,13 @@ export const Const = TSL.Const; export const Continue = TSL.Continue; export const DFGLUT = TSL.DFGLUT; export const D_GGX = TSL.D_GGX; +export const D_GGX_Anisotropic = TSL.D_GGX_Anisotropic; export const Discard = TSL.Discard; export const EPSILON = TSL.EPSILON; +export const EnvironmentBRDF = TSL.EnvironmentBRDF; export const F_Schlick = TSL.F_Schlick; export const Fn = TSL.Fn; +export const HALF_PI = TSL.HALF_PI; export const INFINITY = TSL.INFINITY; export const If = TSL.If; export const Loop = TSL.Loop; @@ -20,11 +24,18 @@ export const NodeAccess = TSL.NodeAccess; export const NodeShaderStage = TSL.NodeShaderStage; export const NodeType = TSL.NodeType; export const NodeUpdateType = TSL.NodeUpdateType; +export const OnAfterObjectUpdate = TSL.OnAfterObjectUpdate; +export const OnAfterRenderPipeline = TSL.OnAfterRenderPipeline; +export const OnBeforeFrameUpdate = TSL.OnBeforeFrameUpdate; +export const OnBeforeMaterialUpdate = TSL.OnBeforeMaterialUpdate; +export const OnBeforeObjectUpdate = TSL.OnBeforeObjectUpdate; +export const OnBeforeRenderPipeline = TSL.OnBeforeRenderPipeline; +export const OnFrameUpdate = TSL.OnFrameUpdate; +export const OnMaterialUpdate = TSL.OnMaterialUpdate; +export const OnObjectUpdate = TSL.OnObjectUpdate; export const PCFShadowFilter = TSL.PCFShadowFilter; export const PI = TSL.PI; export const PI2 = TSL.PI2; -export const TWO_PI = TSL.TWO_PI; -export const HALF_PI = TSL.HALF_PI; export const PointShadowFilter = TSL.PointShadowFilter; export const Return = TSL.Return; export const Schlick_to_F0 = TSL.Schlick_to_F0; @@ -32,8 +43,10 @@ export const ShaderNode = TSL.ShaderNode; export const Stack = TSL.Stack; export const Switch = TSL.Switch; export const TBNViewMatrix = TSL.TBNViewMatrix; +export const TWO_PI = TSL.TWO_PI; export const VSMShadowFilter = TSL.VSMShadowFilter; export const V_GGX_SmithCorrelated = TSL.V_GGX_SmithCorrelated; +export const V_GGX_SmithCorrelated_Anisotropic = TSL.V_GGX_SmithCorrelated_Anisotropic; export const Var = TSL.Var; export const VarIntent = TSL.VarIntent; export const abs = TSL.abs; @@ -76,6 +89,7 @@ export const backgroundBlurriness = TSL.backgroundBlurriness; export const backgroundIntensity = TSL.backgroundIntensity; export const backgroundRotation = TSL.backgroundRotation; export const batch = TSL.batch; +export const batchColor = TSL.batchColor; export const batchIndirectIndex = TSL.batchIndirectIndex; export const bentNormalView = TSL.bentNormalView; export const billboarding = TSL.billboarding; @@ -86,6 +100,7 @@ export const bitXor = TSL.bitXor; export const bitangentGeometry = TSL.bitangentGeometry; export const bitangentLocal = TSL.bitangentLocal; export const bitangentView = TSL.bitangentView; +export const bitangentViewFrame = TSL.bitangentViewFrame; export const bitangentWorld = TSL.bitangentWorld; export const bitcast = TSL.bitcast; export const blendBurn = TSL.blendBurn; @@ -96,10 +111,10 @@ export const blendScreen = TSL.blendScreen; 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 builtinAOContext = TSL.builtinAOContext; export const builtinShadowContext = TSL.builtinShadowContext; +export const bumpMap = TSL.bumpMap; export const bvec2 = TSL.bvec2; export const bvec3 = TSL.bvec3; export const bvec4 = TSL.bvec4; @@ -126,6 +141,8 @@ export const clearcoat = TSL.clearcoat; export const clearcoatNormalView = TSL.clearcoatNormalView; export const clearcoatRoughness = TSL.clearcoatRoughness; export const clipSpace = TSL.clipSpace; +export const clipping = TSL.clipping; +export const clippingAlpha = TSL.clippingAlpha; export const code = TSL.code; export const color = TSL.color; export const colorSpaceToWorking = TSL.colorSpaceToWorking; @@ -137,11 +154,11 @@ export const context = TSL.context; export const convert = TSL.convert; export const convertColorSpace = TSL.convertColorSpace; export const convertToTexture = TSL.convertToTexture; +export const cos = TSL.cos; +export const cosh = TSL.cosh; export const countLeadingZeros = TSL.countLeadingZeros; export const countOneBits = TSL.countOneBits; export const countTrailingZeros = TSL.countTrailingZeros; -export const cos = TSL.cos; -export const cosh = TSL.cosh; export const cross = TSL.cross; export const cubeTexture = TSL.cubeTexture; export const cubeTextureBase = TSL.cubeTextureBase; @@ -156,13 +173,13 @@ export const defaultShaderStages = TSL.defaultShaderStages; export const defined = TSL.defined; export const degrees = TSL.degrees; export const deltaTime = TSL.deltaTime; -export const densityFog = TSL.densityFog; export const densityFogFactor = TSL.densityFogFactor; export const depth = TSL.depth; export const depthPass = TSL.depthPass; export const determinant = TSL.determinant; export const difference = TSL.difference; export const diffuseColor = TSL.diffuseColor; +export const diffuseContribution = TSL.diffuseContribution; export const directPointLight = TSL.directPointLight; export const directionToColor = TSL.directionToColor; export const directionToFaceDirection = TSL.directionToFaceDirection; @@ -201,15 +218,11 @@ export const getCurrentStack = TSL.getCurrentStack; export const getDistanceAttenuation = TSL.getDistanceAttenuation; export const getGeometryRoughness = TSL.getGeometryRoughness; export const getNormalFromDepth = TSL.getNormalFromDepth; -export const interleavedGradientNoise = TSL.interleavedGradientNoise; -export const vogelDiskSample = TSL.vogelDiskSample; export const getParallaxCorrectNormal = TSL.getParallaxCorrectNormal; export const getRoughness = TSL.getRoughness; export const getScreenPosition = TSL.getScreenPosition; export const getScreenPositionFromClip = TSL.getScreenPositionFromClip; export const getShIrradianceAt = TSL.getShIrradianceAt; -export const getShadowMaterial = TSL.getShadowMaterial; -export const getShadowRenderObjectFunction = TSL.getShadowRenderObjectFunction; export const getTextureIndex = TSL.getTextureIndex; export const getViewPosition = TSL.getViewPosition; export const globalId = TSL.globalId; @@ -218,13 +231,16 @@ export const glslFn = TSL.glslFn; export const grayscale = TSL.grayscale; export const greaterThan = TSL.greaterThan; export const greaterThanEqual = TSL.greaterThanEqual; +export const hardwareClipping = TSL.hardwareClipping; export const hash = TSL.hash; export const highpModelNormalViewMatrix = TSL.highpModelNormalViewMatrix; export const highpModelViewMatrix = TSL.highpModelViewMatrix; export const hue = TSL.hue; export const increment = TSL.increment; export const incrementBefore = TSL.incrementBefore; +export const inspect = TSL.inspect; export const instance = TSL.instance; +export const instanceColor = TSL.instanceColor; export const instanceIndex = TSL.instanceIndex; export const instancedArray = TSL.instancedArray; export const instancedBufferAttribute = TSL.instancedBufferAttribute; @@ -232,6 +248,7 @@ export const instancedDynamicBufferAttribute = TSL.instancedDynamicBufferAttribu export const instancedMesh = TSL.instancedMesh; export const int = TSL.int; export const intBitsToFloat = TSL.intBitsToFloat; +export const interleavedGradientNoise = TSL.interleavedGradientNoise; export const inverse = TSL.inverse; export const inverseSqrt = TSL.inverseSqrt; export const inversesqrt = TSL.inversesqrt; @@ -241,6 +258,7 @@ export const ior = TSL.ior; export const iridescence = TSL.iridescence; export const iridescenceIOR = TSL.iridescenceIOR; export const iridescenceThickness = TSL.iridescenceThickness; +export const isolate = TSL.isolate; export const ivec2 = TSL.ivec2; export const ivec3 = TSL.ivec3; export const ivec4 = TSL.ivec4; @@ -340,8 +358,8 @@ export const mx_cell_noise_float = TSL.mx_cell_noise_float; export const mx_cell_noise_vec3 = TSL.mx_cell_noise_vec3; export const mx_contrast = TSL.mx_contrast; export const mx_divide = TSL.mx_divide; -export const mx_fractal_noise_float_2d = TSL.mx_fractal_noise_float_2d; export const mx_fractal_noise_float = TSL.mx_fractal_noise_float; +export const mx_fractal_noise_float_2d = TSL.mx_fractal_noise_float_2d; export const mx_fractal_noise_vec2 = TSL.mx_fractal_noise_vec2; export const mx_fractal_noise_vec3 = TSL.mx_fractal_noise_vec3; export const mx_fractal_noise_vec4 = TSL.mx_fractal_noise_vec4; @@ -391,6 +409,7 @@ export const nodeObject = TSL.nodeObject; export const nodeObjectIntent = TSL.nodeObjectIntent; export const nodeObjects = TSL.nodeObjects; export const nodeProxy = TSL.nodeProxy; +export const nodeProxyConstructor = TSL.nodeProxyConstructor; export const nodeProxyIntent = TSL.nodeProxyIntent; export const normalFlat = TSL.normalFlat; export const normalGeometry = TSL.normalGeometry; @@ -411,13 +430,6 @@ export const objectRadius = TSL.objectRadius; export const objectScale = TSL.objectScale; export const objectViewPosition = TSL.objectViewPosition; export const objectWorldMatrix = TSL.objectWorldMatrix; -export const OnAfterObjectUpdate = TSL.OnAfterObjectUpdate; -export const OnBeforeObjectUpdate = TSL.OnBeforeObjectUpdate; -export const OnBeforeMaterialUpdate = TSL.OnBeforeMaterialUpdate; -export const OnBeforeRenderPipeline = TSL.OnBeforeRenderPipeline; -export const OnAfterRenderPipeline = TSL.OnAfterRenderPipeline; -export const OnObjectUpdate = TSL.OnObjectUpdate; -export const OnMaterialUpdate = TSL.OnMaterialUpdate; export const oneMinus = TSL.oneMinus; export const or = TSL.or; export const orthographicDepthToViewZ = TSL.orthographicDepthToViewZ; @@ -431,11 +443,11 @@ export const overloadingFn = TSL.overloadingFn; export const overrideNode = TSL.overrideNode; export const overrideNodes = TSL.overrideNodes; export const packHalf2x16 = TSL.packHalf2x16; +export const packNormalToRGB = TSL.packNormalToRGB; export const packSnorm2x16 = TSL.packSnorm2x16; -export const packUnorm2x16 = TSL.packUnorm2x16; export const packSnorm4x8 = TSL.packSnorm4x8; +export const packUnorm2x16 = TSL.packUnorm2x16; export const packUnorm4x8 = TSL.packUnorm4x8; -export const packNormalToRGB = TSL.packNormalToRGB; export const parabola = TSL.parabola; export const parallaxDirection = TSL.parallaxDirection; export const parallaxUV = TSL.parallaxUV; @@ -462,10 +474,13 @@ export const pow3 = TSL.pow3; export const pow4 = TSL.pow4; export const premultiplyAlpha = TSL.premultiplyAlpha; export const property = TSL.property; +export const quadBroadcast = TSL.quadBroadcast; +export const quadSwapDiagonal = TSL.quadSwapDiagonal; +export const quadSwapX = TSL.quadSwapX; +export const quadSwapY = TSL.quadSwapY; export const radians = TSL.radians; export const rand = TSL.rand; export const range = TSL.range; -export const rangeFog = TSL.rangeFog; export const rangeFogFactor = TSL.rangeFogFactor; export const reciprocal = TSL.reciprocal; export const reference = TSL.reference; @@ -478,13 +493,13 @@ export const refract = TSL.refract; export const refractVector = TSL.refractVector; export const refractView = TSL.refractView; export const reinhardToneMapping = TSL.reinhardToneMapping; -export const retroreflectivity = TSL.retroreflectivity; export const remap = TSL.remap; export const remapClamp = TSL.remapClamp; export const renderGroup = TSL.renderGroup; export const renderOutput = TSL.renderOutput; export const rendererReference = TSL.rendererReference; export const replaceDefaultUV = TSL.replaceDefaultUV; +export const retroreflectivity = TSL.retroreflectivity; export const rotate = TSL.rotate; export const rotateUV = TSL.rotateUV; export const roughness = TSL.roughness; @@ -497,7 +512,6 @@ export const sampler = TSL.sampler; export const samplerComparison = TSL.samplerComparison; export const saturate = TSL.saturate; export const saturation = TSL.saturation; -export const screen = TSL.screen; export const screenCoordinate = TSL.screenCoordinate; export const screenDPR = TSL.screenDPR; export const screenSize = TSL.screenSize; @@ -517,12 +531,13 @@ export const shiftRight = TSL.shiftRight; export const shininess = TSL.shininess; export const sign = TSL.sign; export const sin = TSL.sin; -export const sinh = TSL.sinh; export const sinc = TSL.sinc; +export const sinh = TSL.sinh; export const skinning = TSL.skinning; export const smoothstep = TSL.smoothstep; export const smoothstepElement = TSL.smoothstepElement; export const specularColor = TSL.specularColor; +export const specularColorBlended = TSL.specularColorBlended; export const specularF90 = TSL.specularF90; export const spherizeUV = TSL.spherizeUV; export const split = TSL.split; @@ -533,10 +548,12 @@ export const step = TSL.step; export const stepElement = TSL.stepElement; export const storage = TSL.storage; export const storageBarrier = TSL.storageBarrier; +export const storageElement = TSL.storageElement; export const storageTexture = TSL.storageTexture; export const storageTexture3D = TSL.storageTexture3D; export const struct = TSL.struct; export const sub = TSL.sub; +export const subBuild = TSL.subBuild; export const subgroupAdd = TSL.subgroupAdd; export const subgroupAll = TSL.subgroupAll; export const subgroupAnd = TSL.subgroupAnd; @@ -544,7 +561,6 @@ export const subgroupAny = TSL.subgroupAny; export const subgroupBallot = TSL.subgroupBallot; export const subgroupBroadcast = TSL.subgroupBroadcast; export const subgroupBroadcastFirst = TSL.subgroupBroadcastFirst; -export const subBuild = TSL.subBuild; export const subgroupElect = TSL.subgroupElect; export const subgroupExclusiveAdd = TSL.subgroupExclusiveAdd; export const subgroupExclusiveMul = TSL.subgroupExclusiveMul; @@ -562,19 +578,22 @@ export const subgroupShuffleXor = TSL.subgroupShuffleXor; export const subgroupSize = TSL.subgroupSize; export const subgroupXor = TSL.subgroupXor; export const tan = TSL.tan; -export const tanh = TSL.tanh; export const tangentGeometry = TSL.tangentGeometry; export const tangentLocal = TSL.tangentLocal; export const tangentView = TSL.tangentView; +export const tangentViewFrame = TSL.tangentViewFrame; export const tangentWorld = TSL.tangentWorld; +export const tanh = TSL.tanh; export const texture = TSL.texture; export const texture3D = TSL.texture3D; +export const texture3DLevel = TSL.texture3DLevel; +export const texture3DLoad = TSL.texture3DLoad; export const textureBarrier = TSL.textureBarrier; export const textureBicubic = TSL.textureBicubic; export const textureBicubicLevel = TSL.textureBicubicLevel; +export const textureLevel = TSL.textureLevel; export const textureLoad = TSL.textureLoad; export const textureSize = TSL.textureSize; -export const textureLevel = TSL.textureLevel; export const textureStore = TSL.textureStore; export const thickness = TSL.thickness; export const time = TSL.time; @@ -600,15 +619,16 @@ export const uintBitsToFloat = TSL.uintBitsToFloat; export const uniform = TSL.uniform; export const uniformArray = TSL.uniformArray; export const uniformCubeTexture = TSL.uniformCubeTexture; -export const uniformGroup = TSL.uniformGroup; export const uniformFlow = TSL.uniformFlow; +export const uniformGroup = TSL.uniformGroup; export const uniformTexture = TSL.uniformTexture; export const unpackHalf2x16 = TSL.unpackHalf2x16; +export const unpackNormal = TSL.unpackNormal; +export const unpackRGBToNormal = TSL.unpackRGBToNormal; export const unpackSnorm2x16 = TSL.unpackSnorm2x16; -export const unpackUnorm2x16 = TSL.unpackUnorm2x16; export const unpackSnorm4x8 = TSL.unpackSnorm4x8; +export const unpackUnorm2x16 = TSL.unpackUnorm2x16; export const unpackUnorm4x8 = TSL.unpackUnorm4x8; -export const unpackRGBToNormal = TSL.unpackRGBToNormal; export const unpremultiplyAlpha = TSL.unpremultiplyAlpha; export const userData = TSL.userData; export const uv = TSL.uv; @@ -642,6 +662,7 @@ export const viewportSharedTexture = TSL.viewportSharedTexture; export const viewportSize = TSL.viewportSize; export const viewportTexture = TSL.viewportTexture; export const viewportUV = TSL.viewportUV; +export const vogelDiskSample = TSL.vogelDiskSample; export const wgsl = TSL.wgsl; export const wgslFn = TSL.wgslFn; export const workgroupArray = TSL.workgroupArray; @@ -649,17 +670,3 @@ export const workgroupBarrier = TSL.workgroupBarrier; export const workgroupId = TSL.workgroupId; export const workingToColorSpace = TSL.workingToColorSpace; export const xor = TSL.xor; - -/* -// Use this code to generate the export statements dynamically - -let code = ''; - -for ( const key of Object.keys( THREE.TSL ) ) { - - code += `export const ${ key } = TSL.${ key };\n`; - -} - -log( code ); -//*/ diff --git a/src/nodes/TSL.js b/src/nodes/TSL.js index 649e6a2e399433..25e1cfbfdd2a6c 100644 --- a/src/nodes/TSL.js +++ b/src/nodes/TSL.js @@ -49,6 +49,7 @@ export * from './utils/RTTNode.js'; export * from './utils/PostProcessingUtils.js'; export * from './utils/SampleNode.js'; export * from './utils/EventNode.js'; +export * from './utils/StorageArrayElementNode.js'; // three.js shading language export * from './tsl/TSLBase.js'; @@ -58,6 +59,8 @@ export * from './accessors/AccessorsUtils.js'; export * from './accessors/Arrays.js'; export * from './accessors/UniformArrayNode.js'; export * from './accessors/Bitangent.js'; +export * from './accessors/ClippingNode.js'; +export * from './accessors/TangentUtils.js'; export * from './accessors/BufferAttributeNode.js'; export * from './accessors/BufferNode.js'; export * from './accessors/BuiltinNode.js'; @@ -140,8 +143,8 @@ export * from './accessors/Lights.js'; export * from './lighting/LightsNode.js'; export * from './lighting/LightingContextNode.js'; export * from './lighting/ShadowBaseNode.js'; -export * from './lighting/ShadowNode.js'; -export * from './lighting/ShadowFilterNode.js'; +export { shadow } from './lighting/ShadowNode.js'; +export { BasicShadowFilter, PCFShadowFilter, VSMShadowFilter } from './lighting/ShadowFilterNode.js'; export * from './lighting/PointShadowNode.js'; export * from './lighting/PointLightNode.js'; @@ -160,11 +163,15 @@ export * from './materialx/MaterialXNodes.js'; // functions export { default as BRDF_GGX } from './functions/BSDF/BRDF_GGX.js'; export { default as BRDF_Lambert } from './functions/BSDF/BRDF_Lambert.js'; +export { default as BRDF_Sheen } from './functions/BSDF/BRDF_Sheen.js'; export { default as D_GGX } from './functions/BSDF/D_GGX.js'; +export { default as D_GGX_Anisotropic } from './functions/BSDF/D_GGX_Anisotropic.js'; export { default as DFGLUT } from './functions/BSDF/DFGLUT.js'; +export { default as EnvironmentBRDF } from './functions/BSDF/EnvironmentBRDF.js'; export { default as F_Schlick } from './functions/BSDF/F_Schlick.js'; export { default as Schlick_to_F0 } from './functions/BSDF/Schlick_to_F0.js'; export { default as V_GGX_SmithCorrelated } from './functions/BSDF/V_GGX_SmithCorrelated.js'; +export { default as V_GGX_SmithCorrelated_Anisotropic } from './functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js'; export * from './lighting/LightUtils.js'; diff --git a/src/nodes/core/InspectorNode.js b/src/nodes/core/InspectorNode.js index 44ea52bed0db62..dab984cfe68615 100644 --- a/src/nodes/core/InspectorNode.js +++ b/src/nodes/core/InspectorNode.js @@ -117,7 +117,7 @@ export default InspectorNode; * @param {Function|null} [callback=null] - Optional callback to modify the node during setup. * @returns {Node} The inspector node. */ -export function inspector( node, name = '', callback = null ) { +export function inspect( node, name = '', callback = null ) { node = nodeObject( node ); @@ -125,4 +125,4 @@ export function inspector( node, name = '', callback = null ) { } -addMethodChaining( 'toInspector', inspector ); +addMethodChaining( 'toInspector', inspect ); diff --git a/src/nodes/lighting/ShadowBaseNode.js b/src/nodes/lighting/ShadowBaseNode.js index dc1db209d8f5fa..c12f49fd3cc89d 100644 --- a/src/nodes/lighting/ShadowBaseNode.js +++ b/src/nodes/lighting/ShadowBaseNode.js @@ -1,7 +1,123 @@ import Node from '../core/Node.js'; +import NodeMaterial from '../../materials/nodes/NodeMaterial.js'; +import ChainMap from '../../renderers/common/ChainMap.js'; +import { getDataFromObject } from '../core/NodeUtils.js'; import { NodeUpdateType } from '../core/constants.js'; -import { property } from '../tsl/TSLBase.js'; +import { property, vec4 } from '../tsl/TSLBase.js'; import { positionWorld } from '../accessors/Position.js'; +import { NoBlending, VSMShadowMap } from '../../constants.js'; + +const _shadowMaterialLib = /*@__PURE__*/ new WeakMap(); +const _shadowRenderObjectLibrary = /*@__PURE__*/ new ChainMap(); +const _shadowRenderObjectKeys = []; + +/** + * Retrieves or creates a shadow material for the given light source. + * + * This function checks if a shadow material already exists for the provided light. + * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it + * in the `shadowMaterialLib` for future use. + * + * @private + * @function + * @param {Light} light - The light source for which the shadow material is needed. + * If the light is a point light, a depth node is calculated + * using the linear shadow distance. + * @returns {NodeMaterial} The shadow material associated with the given light. + */ +const _getShadowMaterial = ( light ) => { + + let material = _shadowMaterialLib.get( light ); + + if ( material === undefined ) { + + material = new NodeMaterial(); + material.colorNode = vec4( 0, 0, 0, 1 ); + material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode + material.name = 'ShadowMaterial'; + material.blending = NoBlending; + material.fog = false; + + _shadowMaterialLib.set( light, material ); + + } + + return material; + +}; + +/** + * Disposes the shadow material for the given light source. + * + * @private + * @param {Light} light - The light source. + */ +const _disposeShadowMaterial = ( light ) => { + + const material = _shadowMaterialLib.get( light ); + + if ( material !== undefined ) { + + material.dispose(); + _shadowMaterialLib.delete( light ); + + } + +}; + +/** + * Creates a function to render shadow objects in a scene. + * + * @private + * @function + * @param {Renderer} renderer - The renderer. + * @param {LightShadow} shadow - The light shadow object containing shadow properties. + * @param {number} shadowType - The type of shadow map (e.g., BasicShadowMap). + * @param {boolean} useVelocity - Whether to use velocity data for rendering. + * @return {shadowRenderObjectFunction} A function that renders shadow objects. + */ +const _getShadowRenderObjectFunction = ( renderer, shadow, shadowType, useVelocity ) => { + + _shadowRenderObjectKeys[ 0 ] = renderer; + _shadowRenderObjectKeys[ 1 ] = shadow; + + let renderObjectFunction = _shadowRenderObjectLibrary.get( _shadowRenderObjectKeys ); + + if ( renderObjectFunction === undefined || ( renderObjectFunction.shadowType !== shadowType || renderObjectFunction.useVelocity !== useVelocity ) ) { + + renderObjectFunction = ( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ) => { + + if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { + + if ( useVelocity ) { + + getDataFromObject( object ).useVelocity = true; + + } + + object.onBeforeShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); + + renderer.renderObject( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ); + + object.onAfterShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); + + } + + }; + + renderObjectFunction.shadowType = shadowType; + renderObjectFunction.useVelocity = useVelocity; + + _shadowRenderObjectLibrary.set( _shadowRenderObjectKeys, renderObjectFunction ); + + } + + _shadowRenderObjectKeys[ 0 ] = null; + _shadowRenderObjectKeys[ 1 ] = null; + + return renderObjectFunction; + +}; /** * Base class for all shadow nodes. @@ -55,6 +171,47 @@ class ShadowBaseNode extends Node { } + /** + * Retrieves or creates a shadow material for the shadow casting light source. + * + * This method checks if a shadow material already exists for the provided light in the internal library. + * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it for future use. + * + * @return {NodeMaterial} The shadow material associated with the given light. + */ + getShadowMaterial() { + + return _getShadowMaterial( this.light ); + + } + + /** + * Disposes the shadow material for the shadow casting light source. + */ + disposeShadowMaterial() { + + _disposeShadowMaterial( this.light ); + + } + + /** + * Returns a function to render shadow objects in a scene for the given light shadow and renderer. + * + * @param {Renderer} renderer - The renderer. + * @param {LightShadow} [shadow=this.light.shadow] - The light shadow object containing shadow properties. + * @return {Function} A function that renders shadow objects. + */ + getShadowRenderObjectFunction( renderer, shadow = this.light.shadow ) { + + const shadowType = renderer.shadowMap.type; + + const currentMRT = renderer.getMRT(); + const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; + + return _getShadowRenderObjectFunction( renderer, shadow, shadowType, useVelocity ); + + } + /** * Setups the shadow position node which is by default the predefined TSL node object `shadowPositionWorld`. * diff --git a/src/nodes/lighting/ShadowFilterNode.js b/src/nodes/lighting/ShadowFilterNode.js index 4521906c41d8e1..fbae4c65e260f5 100644 --- a/src/nodes/lighting/ShadowFilterNode.js +++ b/src/nodes/lighting/ShadowFilterNode.js @@ -1,15 +1,11 @@ -import { float, vec2, vec4, If, Fn } from '../tsl/TSLBase.js'; +import { float, vec2, If, Fn } from '../tsl/TSLBase.js'; import { reference } from '../accessors/ReferenceNode.js'; import { texture } from '../accessors/TextureNode.js'; import { step, max, clamp } from '../math/MathNode.js'; import { add, sub } from '../math/OperatorNode.js'; import { renderGroup } from '../core/UniformGroupNode.js'; -import NodeMaterial from '../../materials/nodes/NodeMaterial.js'; import { screenCoordinate } from '../display/ScreenNode.js'; import { interleavedGradientNoise, vogelDiskSample } from '../utils/PostProcessingUtils.js'; -import { NoBlending } from '../../constants.js'; - -const shadowMaterialLib = /*@__PURE__*/ new WeakMap(); /** * A shadow filtering function performing basic filtering. This is in fact an unfiltered version of the shadow map @@ -131,55 +127,3 @@ export const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, } ); -/** - * Retrieves or creates a shadow material for the given light source. - * - * This function checks if a shadow material already exists for the provided light. - * If not, it creates a new `NodeMaterial` configured for shadow rendering and stores it - * in the `shadowMaterialLib` for future use. - * - * @tsl - * @function - * @param {Light} light - The light source for which the shadow material is needed. - * If the light is a point light, a depth node is calculated - * using the linear shadow distance. - * @returns {NodeMaterial} The shadow material associated with the given light. - */ -export const getShadowMaterial = ( light ) => { - - let material = shadowMaterialLib.get( light ); - - if ( material === undefined ) { - - material = new NodeMaterial(); - material.colorNode = vec4( 0, 0, 0, 1 ); - material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode - material.name = 'ShadowMaterial'; - material.blending = NoBlending; - material.fog = false; - - shadowMaterialLib.set( light, material ); - - } - - return material; - -}; - -/** - * Disposes the shadow material for the given light source. - * - * @param {Light} light - The light source. - */ -export const disposeShadowMaterial = ( light ) => { - - const material = shadowMaterialLib.get( light ); - - if ( material !== undefined ) { - - material.dispose(); - shadowMaterialLib.delete( light ); - - } - -}; diff --git a/src/nodes/lighting/ShadowNode.js b/src/nodes/lighting/ShadowNode.js index cf3081eb645fdc..7912654fdadc8c 100644 --- a/src/nodes/lighting/ShadowNode.js +++ b/src/nodes/lighting/ShadowNode.js @@ -1,6 +1,5 @@ import NodeMaterial from '../../materials/nodes/NodeMaterial.js'; import QuadMesh from '../../renderers/common/QuadMesh.js'; -import ChainMap from '../../renderers/common/ChainMap.js'; import ShadowBaseNode, { shadowPositionWorld } from './ShadowBaseNode.js'; import { float, vec2, vec3, vec4, int, Fn } from '../tsl/TSLCore.js'; import { reference } from '../accessors/ReferenceNode.js'; @@ -17,72 +16,12 @@ import { renderGroup } from '../core/UniformGroupNode.js'; import { viewZToLogarithmicDepth, perspectiveDepthToViewZ, orthographicDepthToViewZ, viewZToOrthographicDepth } from '../display/ViewportDepthNode.js'; import { lightShadowMatrix } from '../accessors/Lights.js'; import { resetRendererAndSceneState, restoreRendererAndSceneState } from '../../renderers/common/RendererUtils.js'; -import { getDataFromObject } from '../core/NodeUtils.js'; -import { getShadowMaterial, disposeShadowMaterial, BasicShadowFilter, PCFShadowFilter, VSMShadowFilter } from './ShadowFilterNode.js'; +import { BasicShadowFilter, PCFShadowFilter, VSMShadowFilter } from './ShadowFilterNode.js'; import { positionLocal } from '../accessors/Position.js'; import { uniform } from '../core/UniformNode.js'; import { equirectDirection } from '../utils/EquirectUV.js'; import { context } from '../core/ContextNode.js'; -// - -const _shadowRenderObjectLibrary = /*@__PURE__*/ new ChainMap(); -const _shadowRenderObjectKeys = []; - -/** - * Creates a function to render shadow objects in a scene. - * - * @tsl - * @function - * @param {Renderer} renderer - The renderer. - * @param {LightShadow} shadow - The light shadow object containing shadow properties. - * @param {number} shadowType - The type of shadow map (e.g., BasicShadowMap). - * @param {boolean} useVelocity - Whether to use velocity data for rendering. - * @return {shadowRenderObjectFunction} A function that renders shadow objects. - */ -export const getShadowRenderObjectFunction = ( renderer, shadow, shadowType, useVelocity ) => { - - _shadowRenderObjectKeys[ 0 ] = renderer; - _shadowRenderObjectKeys[ 1 ] = shadow; - - let renderObjectFunction = _shadowRenderObjectLibrary.get( _shadowRenderObjectKeys ); - - if ( renderObjectFunction === undefined || ( renderObjectFunction.shadowType !== shadowType || renderObjectFunction.useVelocity !== useVelocity ) ) { - - renderObjectFunction = ( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ) => { - - if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { - - if ( useVelocity ) { - - getDataFromObject( object ).useVelocity = true; - - } - - object.onBeforeShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); - - renderer.renderObject( object, scene, _camera, geometry, material, group, lightsNode, clippingContext, passId ); - - object.onAfterShadow( renderer, object, _camera, shadow.camera, geometry, scene.overrideMaterial, group ); - - } - - }; - - renderObjectFunction.shadowType = shadowType; - renderObjectFunction.useVelocity = useVelocity; - - _shadowRenderObjectLibrary.set( _shadowRenderObjectKeys, renderObjectFunction ); - - } - - _shadowRenderObjectKeys[ 0 ] = null; - _shadowRenderObjectKeys[ 1 ] = null; - - return renderObjectFunction; - -}; - /** * Represents the shader code for the first VSM render pass. * @@ -725,7 +664,7 @@ class ShadowNode extends ShadowBaseNode { */ updateShadow( frame ) { - const { shadowMap, light, shadow } = this; + const { shadowMap, shadow } = this; const { renderer, scene, camera } = frame; const shadowType = renderer.shadowMap.type; @@ -743,14 +682,11 @@ class ShadowNode extends ShadowBaseNode { const currentRenderObjectFunction = renderer.getRenderObjectFunction(); - const currentMRT = renderer.getMRT(); - const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; - _rendererState = resetRendererAndSceneState( renderer, scene, _rendererState ); - scene.overrideMaterial = getShadowMaterial( light ); + scene.overrideMaterial = this.getShadowMaterial(); - renderer.setRenderObjectFunction( getShadowRenderObjectFunction( renderer, shadow, shadowType, useVelocity ) ); + renderer.setRenderObjectFunction( this.getShadowRenderObjectFunction( renderer, this.shadow || this.light.shadow ) ); renderer.setClearColor( 0x000000, 0 ); @@ -817,7 +753,7 @@ class ShadowNode extends ShadowBaseNode { this._currentShadowType = null; - disposeShadowMaterial( this.light ); + this.disposeShadowMaterial(); if ( this.shadowMap ) { @@ -893,19 +829,6 @@ class ShadowNode extends ShadowBaseNode { export default ShadowNode; -/** - * Shadow Render Object Function. - * - * @function shadowRenderObjectFunction - * @param {Object3D} object - The 3D object to render. - * @param {Scene} scene - The scene containing the object. - * @param {Camera} _camera - The camera used for rendering. - * @param {BufferGeometry} geometry - The geometry of the object. - * @param {Material} material - The material of the object. - * @param {Group} group - The group the object belongs to. - * @param {...any} params - Additional parameters for rendering. - */ - /** * TSL function for creating an instance of `ShadowNode`. * diff --git a/test/unit/addons/loaders/USDLoader.tests.js b/test/unit/addons/loaders/USDLoader.tests.js index a493e2d7a50de7..35eaac20c1f7ad 100644 --- a/test/unit/addons/loaders/USDLoader.tests.js +++ b/test/unit/addons/loaders/USDLoader.tests.js @@ -1,4 +1,8 @@ +import { LoadingManager } from 'three'; import { USDLoader } from '../../../../examples/jsm/loaders/USDLoader.js'; +import { USDComposer, SpecType } from '../../../../examples/jsm/loaders/usd/USDComposer.js'; +import { USDAParser } from '../../../../examples/jsm/loaders/usd/USDAParser.js'; +import { USDCParser } from '../../../../examples/jsm/loaders/usd/USDCParser.js'; export default QUnit.module( 'Addons', () => { @@ -6,6 +10,195 @@ export default QUnit.module( 'Addons', () => { QUnit.module( 'USDLoader', () => { + QUnit.test( 'reads the USDC string table after its count prefix', ( assert ) => { + + const parser = new USDCParser(); + const stringIndices = [ 4, 7, 9 ]; + let readIndex = 0; + let seekOffset = null; + + parser.sections = { STRINGS: { start: 32, size: 20 } }; + parser.reader = { + seek( offset ) { + + seekOffset = offset; + + }, + readUint64() { + + return stringIndices.length; + + }, + readUint32() { + + return stringIndices[ readIndex ++ ]; + + } + }; + + parser._readStrings(); + + assert.strictEqual( seekOffset, 32, 'The string section start is used.' ); + assert.deepEqual( parser.strings, stringIndices, 'Only string indices after the count are read.' ); + + } ); + + QUnit.test( 'resolves inherited material bindings by strength', ( assert ) => { + + const composer = new USDComposer(); + const parentBinding = { + specType: SpecType.Relationship, + fields: { + bindMaterialAs: 'strongerThanDescendants', + targetPaths: [ '/Root/Materials/Green' ] + } + }; + + composer.externalVariantSelections = {}; + composer.specsByPath = { + '/Root': { + specType: SpecType.Prim, + fields: { + typeName: 'Xform', + variantSelection: { Material: 'Green' }, + variantSetChildren: [ 'Material' ] + } + }, + '/Root/{Material=Green}/Parent.material:binding': parentBinding, + '/Root/Parent/Mesh.material:binding': { + specType: SpecType.Relationship, + fields: { + bindMaterialAs: 'weakerThanDescendants', + targetPaths: [ '/Root/Materials/White' ] + } + } + }; + + assert.strictEqual( + composer._getMaterialBindingTarget( '/Root/Parent/Mesh' ), + '/Root/Materials/Green', + 'A stronger inherited variant binding overrides the descendant binding.' + ); + + parentBinding.fields.bindMaterialAs = 'weakerThanDescendants'; + assert.strictEqual( + composer._getMaterialBindingTarget( '/Root/Parent/Mesh' ), + '/Root/Materials/White', + 'A descendant binding overrides a weaker inherited binding.' + ); + + } ); + + QUnit.test( 'reads USDA material binding strength metadata', ( assert ) => { + + const usda = `#usda 1.0 + +def Xform "Root" +{ + def Xform "Parent" + { + rel material:binding = ( + bindMaterialAs = "strongerThanDescendants" + ) + + def Mesh "Mesh" + { + rel material:binding = ( + bindMaterialAs = "weakerThanDescendants" + ) + } + } +}`; + + const parsedData = new USDAParser().parseData( usda ); + const parentBinding = parsedData.specsByPath[ '/Root/Parent.material:binding' ]; + const childBinding = parsedData.specsByPath[ '/Root/Parent/Mesh.material:binding' ]; + + assert.strictEqual( + parentBinding.fields.bindMaterialAs, + 'strongerThanDescendants', + 'The parent relationship preserves stronger binding metadata.' + ); + assert.strictEqual( + childBinding.fields.bindMaterialAs, + 'weakerThanDescendants', + 'The child relationship preserves weaker binding metadata.' + ); + + const composer = new USDComposer(); + composer.externalVariantSelections = {}; + composer.specsByPath = parsedData.specsByPath; + + assert.strictEqual( + composer._getMaterialBindingTarget( '/Root/Parent/Mesh' ), + '/Root/Materials/Green', + 'A stronger USDA parent binding overrides the descendant binding.' + ); + + parentBinding.fields.bindMaterialAs = 'weakerThanDescendants'; + assert.strictEqual( + composer._getMaterialBindingTarget( '/Root/Parent/Mesh' ), + '/Root/Materials/White', + 'A USDA descendant binding overrides a weaker parent binding.' + ); + + } ); + + QUnit.test( 'resolves connected asset inputs before fallback values', ( assert ) => { + + const usda = `#usda 1.0 +( + defaultPrim = "Root" +) + +def Xform "Root" +{ + def Material "PlaneMaterial" + { + asset inputs:baseColorTexture = @base-color.png@ + token outputs:surface.connect = + + def Shader "BaseColor" + { + uniform token info:id = "UsdUVTexture" + asset inputs:file = @fallback-orm.png@ + asset inputs:file.connect = + float3 outputs:rgb + } + + def Shader "PreviewSurface" + { + uniform token info:id = "UsdPreviewSurface" + color3f inputs:diffuseColor.connect = + token outputs:surface + } + } + + def Cube "Plane" + { + rel material:binding = + } +}`; + + const requestedURLs = []; + const manager = new LoadingManager(); + manager.setURLModifier( ( url ) => { + + requestedURLs.push( url ); + return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='; + + } ); + + new USDLoader( manager ).parse( usda ); + + assert.deepEqual( + requestedURLs, + [ 'base-color.png' ], + 'The connected material input overrides the texture node fallback.' + ); + + } ); + QUnit.test( 'uses timeCodesPerSecond for USDA animation timing', ( assert ) => { const usda = `#usda 1.0