@gnsx/three 0.185.16 → 0.186.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/three.cjs +10 -82600
- package/build/three.core.js +1303 -728
- package/build/three.module.js +439 -338
- package/build/three.tsl.js +74 -44
- package/build/three.webgpu.js +6036 -2184
- package/build/three.webgpu.nodes.js +6020 -2184
- package/examples/jsm/Addons.js +6 -6
- package/examples/jsm/controls/ArcballControls.js +1 -1
- package/examples/jsm/controls/FirstPersonControls.js +44 -20
- package/examples/jsm/controls/OrbitControls.js +9 -0
- package/examples/jsm/controls/TrackballControls.js +109 -4
- package/examples/jsm/csm/CSMShadowNode.js +13 -0
- package/examples/jsm/exporters/GLTFExporter.js +23 -7
- package/examples/jsm/exporters/USDZExporter.js +2 -2
- package/examples/jsm/generators/CityGenerator.js +377 -45
- package/examples/jsm/generators/ForestGenerator.js +12 -12
- package/examples/jsm/generators/TerrainGenerator.js +49 -37
- package/examples/jsm/generators/TreeGenerator.js +70 -76
- package/examples/jsm/generators/city/BenchGenerator.js +127 -0
- package/examples/jsm/generators/city/CarGenerator.js +479 -0
- package/examples/jsm/generators/city/CityGeneratorUtils.js +31 -0
- package/examples/jsm/generators/city/HydrantGenerator.js +106 -0
- package/examples/jsm/generators/city/InstancedMeshGenerator.js +86 -0
- package/examples/jsm/generators/city/PersonGenerator.js +447 -0
- package/examples/jsm/generators/city/SidewalkGenerator.js +33 -38
- package/examples/jsm/generators/city/SkyscraperGenerator.js +448 -48
- package/examples/jsm/generators/city/StreetTreeGenerator.js +231 -0
- package/examples/jsm/generators/city/StreetlightGenerator.js +100 -0
- package/examples/jsm/generators/city/TrafficlightGenerator.js +106 -0
- package/examples/jsm/generators/city/TrashcanGenerator.js +100 -0
- package/examples/jsm/geometries/BoxLineGeometry.js +1 -1
- package/examples/jsm/geometries/ParametricGeometry.js +1 -1
- package/examples/jsm/geometries/RoundedBoxGeometry.js +1 -1
- package/examples/jsm/gpgpu/CountingSort.js +271 -0
- package/examples/jsm/helpers/LightProbeGridHelper.js +60 -239
- package/examples/jsm/helpers/LightProbeGridHelperWebGL.js +221 -0
- package/examples/jsm/inspector/Extension.js +94 -0
- package/examples/jsm/inspector/Inspector.js +145 -41
- package/examples/jsm/inspector/RendererInspector.js +100 -52
- package/examples/jsm/inspector/extensions/color-grading/ColorGrading.js +2609 -0
- package/examples/jsm/inspector/extensions/color-grading/ColorWheel.js +352 -0
- package/examples/jsm/inspector/extensions/color-grading/CurveEditor.js +599 -0
- package/examples/jsm/inspector/extensions/color-grading/LUT3DStyle.js +1201 -0
- package/examples/jsm/inspector/extensions/color-grading/LUTMath.js +788 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/BrightnessModule.js +72 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/ColorWheelModule.js +112 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/ContrastModule.js +82 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/CurvesModule.js +109 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/ExposureHueModule.js +110 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/ExposureModule.js +73 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/HueModule.js +78 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/ImportedCubeModule.js +89 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/Module.js +285 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/OutputModule.js +101 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/RendererModule.js +225 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/SatVibranceModule.js +102 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/SaturationModule.js +76 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/VibranceModule.js +76 -0
- package/examples/jsm/inspector/extensions/color-grading/modules/WhiteBalanceModule.js +86 -0
- package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphEditor.js +26 -31
- package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphLoader.js +1 -0
- package/examples/jsm/inspector/tabs/Memory.js +0 -2
- package/examples/jsm/inspector/tabs/Settings.js +4 -0
- package/examples/jsm/inspector/tabs/Timeline.js +223 -171
- package/examples/jsm/inspector/tabs/Viewer.js +515 -21
- package/examples/jsm/inspector/ui/List.js +15 -9
- package/examples/jsm/inspector/ui/Profiler.js +170 -14
- package/examples/jsm/inspector/ui/Style.js +269 -23
- package/examples/jsm/inspector/ui/Tab.js +2 -0
- package/examples/jsm/inspector/ui/Values.js +14 -2
- package/examples/jsm/interactive/HTMLMesh.js +19 -3
- package/examples/jsm/lighting/LightProbeGrid.js +484 -889
- package/examples/jsm/lighting/LightProbeGridUtils.js +107 -0
- package/examples/jsm/lighting/LightProbeGridWebGL.js +841 -0
- package/examples/jsm/lighting/vxgi/VXGIConeTracer.js +194 -0
- package/examples/jsm/lighting/vxgi/VXGINode.js +660 -0
- package/examples/jsm/lighting/vxgi/VXGISceneCollector.js +478 -0
- package/examples/jsm/lighting/vxgi/VXGIVolume.js +1430 -0
- package/examples/jsm/lights/SunLight.js +95 -0
- package/examples/jsm/lights/SunLightNode.js +56 -0
- package/examples/jsm/lights/SunLightShadow.js +319 -0
- package/examples/jsm/lights/SunShadowNode.js +312 -0
- package/examples/jsm/loaders/3DMLoader.js +150 -49
- package/examples/jsm/loaders/3MFLoader.js +202 -1
- package/examples/jsm/loaders/FBXLoader.js +81 -5
- package/examples/jsm/loaders/GLTFGaussianSplatLoaderExtension.js +330 -0
- package/examples/jsm/loaders/GLTFLoader.js +79 -14
- package/examples/jsm/loaders/GaussianSplatPLYLoader.js +386 -0
- package/examples/jsm/loaders/KSPLATLoader.js +463 -0
- package/examples/jsm/loaders/MaterialXLoader.js +111 -1010
- package/examples/jsm/loaders/PCDLoader.js +1 -1
- package/examples/jsm/loaders/SPLATLoader.js +139 -0
- package/examples/jsm/loaders/SPZLoader.js +561 -0
- package/examples/jsm/loaders/materialx/MaterialXArchive.js +108 -0
- package/examples/jsm/loaders/materialx/MaterialXDocument.js +878 -0
- package/examples/jsm/loaders/materialx/MaterialXHextile.js +183 -0
- package/examples/jsm/loaders/materialx/MaterialXInterfaceValidation.js +376 -0
- package/examples/jsm/loaders/materialx/MaterialXLog.js +75 -0
- package/examples/jsm/loaders/materialx/MaterialXNodeInterfaceRegistry.js +4 -0
- package/examples/jsm/loaders/materialx/MaterialXNodeLibrary.js +1021 -0
- package/examples/jsm/loaders/materialx/MaterialXSurfaceMappings.js +661 -0
- package/examples/jsm/loaders/materialx/MaterialXUtils.js +57 -0
- package/examples/jsm/loaders/materialx/compile/MaterialXCompileRegistry.js +997 -0
- package/examples/jsm/loaders/materialx/parse/MaterialXParser.js +28 -0
- package/examples/jsm/loaders/usd/USDAParser.js +15 -2
- package/examples/jsm/loaders/usd/USDCParser.js +1 -4
- package/examples/jsm/loaders/usd/USDComposer.js +80 -42
- package/examples/jsm/materials/WoodNodeMaterial.js +6 -108
- package/examples/jsm/misc/RollerCoaster.js +2 -2
- package/examples/jsm/misc/SculptGL.LICENSE.txt +21 -0
- package/examples/jsm/misc/Sculptor.js +1679 -0
- package/examples/jsm/misc/SculptorMesh.js +1504 -0
- package/examples/jsm/misc/SculptorTools.js +1180 -0
- package/examples/jsm/misc/SculptorUtils.js +345 -0
- package/examples/jsm/misc/TubePainter.js +28 -16
- package/examples/jsm/misc/VolumeSlice.js +24 -24
- package/examples/jsm/modifiers/SimplifyModifier.js +63 -556
- package/examples/jsm/objects/GaussianSplat.js +1039 -0
- package/examples/jsm/objects/Sky.js +66 -45
- package/examples/jsm/objects/SkyMesh.js +70 -51
- package/examples/jsm/physics/JoltPhysics.js +1 -1
- package/examples/jsm/postprocessing/AfterimagePass.js +4 -2
- package/examples/jsm/postprocessing/BloomPass.js +2 -2
- package/examples/jsm/postprocessing/GTAOPass.js +1 -1
- package/examples/jsm/postprocessing/OutlinePass.js +5 -5
- package/examples/jsm/postprocessing/SAOPass.js +1 -1
- package/examples/jsm/postprocessing/SSAOPass.js +1 -1
- package/examples/jsm/postprocessing/SSRPass.js +4 -2
- package/examples/jsm/postprocessing/SavePass.js +1 -1
- package/examples/jsm/postprocessing/TAARenderPass.js +1 -1
- package/examples/jsm/postprocessing/UnrealBloomPass.js +30 -13
- package/examples/jsm/renderers/CSS2DRenderer.js +29 -5
- package/examples/jsm/shaders/DepthLimitedBlurShader.js +4 -1
- package/examples/jsm/shaders/ExposureShader.js +1 -1
- package/examples/jsm/shaders/FilmShader.js +2 -1
- package/examples/jsm/transpiler/AST.js +21 -2
- package/examples/jsm/transpiler/GLSLDecoder.js +498 -8
- package/examples/jsm/transpiler/TSLEncoder.js +82 -10
- package/examples/jsm/transpiler/WGSLEncoder.js +33 -4
- package/examples/jsm/tsl/WebGLNodesHandler.js +29 -39
- package/examples/jsm/tsl/display/AfterImageNode.js +2 -0
- package/examples/jsm/tsl/display/AnaglyphPassNode.js +3 -2
- package/examples/jsm/tsl/display/BilateralBlurNode.js +5 -2
- package/examples/jsm/tsl/display/BloomNode.js +55 -30
- package/examples/jsm/tsl/display/DenoiseNode.js +21 -1
- package/examples/jsm/tsl/display/DepthOfFieldNode.js +24 -6
- package/examples/jsm/tsl/display/DotScreenNode.js +11 -11
- package/examples/jsm/tsl/display/FSR1Node.js +8 -4
- package/examples/jsm/tsl/display/GTAONode.js +199 -86
- package/examples/jsm/tsl/display/GaussianBlurNode.js +65 -52
- package/examples/jsm/tsl/display/GodraysNode.js +5 -2
- package/examples/jsm/tsl/display/ImportanceSampledEnvironment.js +2 -2
- package/examples/jsm/tsl/display/LensflareNode.js +5 -2
- package/examples/jsm/tsl/display/OITPassNode.js +352 -0
- package/examples/jsm/tsl/display/OutlineNode.js +2 -0
- package/examples/jsm/tsl/display/ParallaxBarrierPassNode.js +3 -2
- package/examples/jsm/tsl/display/RGBShiftNode.js +9 -9
- package/examples/jsm/tsl/display/RecurrentDenoiseNode.js +7 -4
- package/examples/jsm/tsl/display/RetroPassNode.js +1 -1
- package/examples/jsm/tsl/display/SMAANode.js +22 -61
- package/examples/jsm/tsl/display/SSAAPassNode.js +2 -4
- package/examples/jsm/tsl/display/SSAONode.js +436 -0
- package/examples/jsm/tsl/display/SSGINode.js +5 -2
- package/examples/jsm/tsl/display/SSRNode.js +7 -2
- package/examples/jsm/tsl/display/SSSNode.js +5 -2
- package/examples/jsm/tsl/display/SharpenNode.js +5 -4
- package/examples/jsm/tsl/display/StereoCompositePassNode.js +1 -3
- package/examples/jsm/tsl/display/StereoPassNode.js +1 -3
- package/examples/jsm/tsl/display/TAAUNode.js +22 -125
- package/examples/jsm/tsl/display/TRAANode.js +16 -142
- package/examples/jsm/tsl/display/TemporalReprojectNode.js +21 -15
- package/examples/jsm/tsl/display/depthAwareBlur.js +63 -0
- package/examples/jsm/tsl/display/hashBlur.js +3 -2
- package/examples/jsm/tsl/lighting/ClusteredLightsNode.js +38 -27
- package/examples/jsm/tsl/lighting/LightProbeGridNode.js +136 -0
- package/examples/jsm/tsl/math/voronoiNoise.js +112 -0
- package/examples/jsm/tsl/shadows/TileShadowNode.js +4 -6
- package/examples/jsm/tsl/utils/Raymarching.js +5 -5
- package/examples/jsm/tsl/utils/SoftParticles.js +60 -0
- package/examples/jsm/tsl/utils/TAAUtils.js +195 -0
- package/examples/jsm/utils/BufferGeometryUtils.js +14 -14
- package/examples/jsm/utils/GaussianSplatUtils.js +229 -0
- package/examples/jsm/utils/WebGLTextureUtils.js +1 -1
- package/examples/jsm/utils/WebGPUTextureUtils.js +1 -1
- package/examples/jsm/webxr/WebGLXRFallback.js +2 -16
- package/examples/jsm/webxr/XRControllerModelFactory.js +16 -4
- package/package.json +9 -16
- package/src/Three.Core.js +2 -1
- package/src/Three.TSL.js +73 -43
- package/src/Three.WebGPU.Nodes.js +1 -0
- package/src/Three.WebGPU.js +1 -0
- package/src/animation/AnimationClip.js +15 -2
- package/src/animation/AnimationObjectGroup.js +18 -6
- package/src/animation/AnimationUtils.js +26 -0
- package/src/animation/KeyframeTrack.js +37 -0
- package/src/constants.js +23 -1
- package/src/core/BufferAttribute.js +3 -2
- package/src/core/BufferGeometry.js +1 -1
- package/src/core/InterleavedBuffer.js +5 -1
- package/src/core/Object3D.js +40 -12
- package/src/core/Raycaster.js +4 -0
- package/src/core/RenderTarget.js +99 -9
- package/src/core/RenderTarget3D.js +12 -8
- package/src/extras/Controls.js +0 -8
- package/src/extras/PMREMGenerator.js +99 -205
- package/src/geometries/TorusGeometry.js +1 -1
- package/src/helpers/ArrowHelper.js +2 -0
- package/src/helpers/AxesHelper.js +2 -0
- package/src/helpers/Box3Helper.js +2 -0
- package/src/helpers/BoxHelper.js +2 -0
- package/src/helpers/CameraHelper.js +2 -0
- package/src/helpers/DirectionalLightHelper.js +2 -0
- package/src/helpers/GridHelper.js +2 -0
- package/src/helpers/HemisphereLightHelper.js +2 -0
- package/src/helpers/PlaneHelper.js +2 -0
- package/src/helpers/PointLightHelper.js +2 -0
- package/src/helpers/PolarGridHelper.js +2 -0
- package/src/helpers/SkeletonHelper.js +2 -0
- package/src/helpers/SpotLightHelper.js +2 -0
- package/src/lights/Light.js +0 -10
- package/src/lights/LightShadow.js +43 -12
- package/src/lights/SpotLightShadow.js +18 -0
- package/src/loaders/BufferGeometryLoader.js +5 -0
- package/src/loaders/ImageBitmapLoader.js +3 -1
- package/src/loaders/ObjectLoader.js +8 -5
- package/src/materials/Material.js +80 -57
- package/src/materials/MeshPhysicalMaterial.js +32 -0
- package/src/materials/nodes/Line2NodeMaterial.js +17 -8
- package/src/materials/nodes/MeshPhysicalNodeMaterial.js +42 -5
- package/src/materials/nodes/NodeMaterial.js +19 -13
- package/src/materials/nodes/PointsNodeMaterial.js +2 -1
- package/src/materials/nodes/manager/NodeMaterialObserver.js +282 -55
- package/src/math/Frustum.js +9 -0
- package/src/math/FrustumArray.js +1 -1
- package/src/math/MathUtils.js +5 -3
- package/src/math/Matrix4.js +2 -9
- package/src/math/Plane.js +30 -1
- package/src/math/Quaternion.js +0 -10
- package/src/math/Ray.js +95 -45
- package/src/math/Triangle.js +0 -2
- package/src/math/Vector3.js +2 -2
- package/src/math/Vector4.js +0 -4
- package/src/math/interpolants/BezierInterpolant.js +36 -23
- package/src/nodes/Nodes.js +2 -0
- package/src/nodes/TSL.js +11 -3
- package/src/nodes/accessors/Batch.js +85 -13
- package/src/nodes/accessors/BufferAttributeNode.js +1 -1
- package/src/nodes/accessors/BuiltinNode.js +1 -1
- package/src/nodes/accessors/Instance.js +19 -18
- package/src/nodes/accessors/MaterialNode.js +9 -0
- package/src/nodes/accessors/ModelNode.js +85 -9
- package/src/nodes/accessors/ReferenceBaseNode.js +1 -70
- package/src/nodes/accessors/ReferenceElementNode.js +72 -0
- package/src/nodes/accessors/ReferenceNode.js +1 -70
- package/src/nodes/accessors/Skinning.js +124 -12
- package/src/nodes/accessors/StorageTextureNode.js +7 -3
- package/src/nodes/accessors/Texture3DNode.js +1 -1
- package/src/nodes/accessors/TextureNode.js +51 -21
- package/src/nodes/accessors/TextureSizeNode.js +4 -2
- package/src/nodes/accessors/UniformArrayNode.js +30 -5
- package/src/nodes/code/CodeNode.js +1 -1
- package/src/nodes/code/FunctionNode.js +12 -2
- package/src/nodes/core/ArrayNode.js +2 -2
- package/src/nodes/core/ContextNode.js +57 -4
- package/src/nodes/core/IndexNode.js +69 -4
- package/src/nodes/core/InspectorNode.js +2 -2
- package/src/nodes/core/MRTNode.js +44 -2
- package/src/nodes/core/Node.js +6 -3
- package/src/nodes/core/NodeBuilder.js +65 -50
- package/src/nodes/core/NodeFrame.js +11 -3
- package/src/nodes/core/NodeUtils.js +88 -0
- package/src/nodes/core/PropertyNode.js +8 -0
- package/src/nodes/core/StackNode.js +0 -1
- package/src/nodes/core/StructNode.js +4 -3
- package/src/nodes/core/UniformGroupNode.js +3 -2
- package/src/nodes/core/UniformNode.js +26 -12
- package/src/nodes/core/VarNode.js +0 -1
- package/src/nodes/display/BumpMapNode.js +2 -2
- package/src/nodes/display/ColorAdjustment.js +1 -1
- package/src/nodes/display/PassNode.js +76 -15
- package/src/nodes/display/ScreenNode.js +22 -65
- package/src/nodes/fog/Fog.js +4 -4
- package/src/nodes/functions/BSDF/BRDF_GGX.js +6 -6
- package/src/nodes/functions/BSDF/BRDF_Sheen.js +1 -1
- package/src/nodes/functions/BSDF/DFGLUT.js +2 -1
- package/src/nodes/functions/BSDF/LTC.js +1 -1
- package/src/nodes/functions/PhongLightingModel.js +1 -1
- package/src/nodes/functions/PhysicalLightingModel.js +83 -25
- package/src/nodes/functions/ToonLightingModel.js +2 -2
- package/src/nodes/functions/material/getParallaxCorrectNormal.js +3 -3
- package/src/nodes/gpgpu/AtomicFunctionNode.js +64 -13
- package/src/nodes/gpgpu/BarrierNode.js +13 -4
- package/src/nodes/gpgpu/ComputeBuiltinNode.js +1 -1
- package/src/nodes/gpgpu/ComputeNode.js +20 -17
- package/src/nodes/gpgpu/SubgroupFunctionNode.js +165 -37
- package/src/nodes/gpgpu/WorkgroupInfoNode.js +44 -6
- package/src/nodes/lighting/EnvironmentNode.js +40 -4
- package/src/nodes/lighting/LightsNode.js +20 -4
- package/src/nodes/lighting/ShadowBaseNode.js +158 -1
- package/src/nodes/lighting/ShadowFilterNode.js +2 -106
- package/src/nodes/lighting/ShadowNode.js +22 -91
- package/src/nodes/materialx/{lib/mx_hsv.js → MaterialXColor.js} +3 -6
- package/src/nodes/materialx/{lib/mx_transform_color.js → MaterialXColorTransform.js} +3 -6
- package/src/nodes/materialx/MaterialXCore.js +37 -0
- package/src/nodes/materialx/MaterialXNodes.js +64 -72
- package/src/nodes/materialx/{lib/mx_noise.js → MaterialXNoise.js} +426 -197
- package/src/nodes/math/BitcountNode.js +24 -4
- package/src/nodes/math/MathNode.js +4 -4
- package/src/nodes/math/MathUtils.js +15 -4
- package/src/nodes/math/OperatorNode.js +2 -2
- package/src/nodes/math/PackFloatNode.js +29 -1
- package/src/nodes/math/Packed4x8IntegerNode.js +433 -0
- package/src/nodes/math/UnpackFloatNode.js +30 -2
- package/src/nodes/parsers/GLSLNodeFunction.js +1 -1
- package/src/nodes/pmrem/PMREMNode.js +1 -1
- package/src/nodes/pmrem/PMREMUtils.js +31 -74
- package/src/nodes/shapes/Shapes.js +1 -1
- package/src/nodes/tsl/TSLCore.js +1 -31
- package/src/nodes/utils/EventNode.js +75 -0
- package/src/nodes/utils/LoopNode.js +54 -13
- package/src/nodes/utils/PostProcessingUtils.js +23 -2
- package/src/nodes/utils/RTTNode.js +97 -32
- package/src/nodes/utils/ReflectorNode.js +8 -4
- package/src/nodes/utils/RotateNode.js +85 -8
- package/src/nodes/utils/SpriteUtils.js +58 -23
- package/src/objects/BatchedMesh.js +6 -0
- package/src/objects/InstancedMesh.js +1 -1
- package/src/objects/LOD.js +1 -1
- package/src/objects/Line.js +12 -0
- package/src/objects/Mesh.js +12 -0
- package/src/objects/Points.js +12 -0
- package/src/objects/Sprite.js +12 -0
- package/src/renderers/WebGLRenderer.js +93 -27
- package/src/renderers/common/Animation.js +12 -2
- package/src/renderers/common/Backend.js +38 -10
- package/src/renderers/common/BindGroup.js +0 -1
- package/src/renderers/common/Bindings.js +50 -4
- package/src/renderers/common/BundleGroup.js +4 -0
- package/src/renderers/common/ClippingContext.js +11 -1
- package/src/renderers/common/Color4.js +9 -0
- package/src/renderers/common/Constants.js +0 -5
- package/src/renderers/common/DirectRenderPipeline.js +233 -0
- package/src/renderers/common/Geometries.js +24 -3
- package/src/renderers/common/Info.js +3 -3
- package/src/renderers/common/InspectorBase.js +37 -8
- package/src/renderers/common/Lighting.js +11 -4
- package/src/renderers/common/Pipelines.js +6 -4
- package/src/renderers/common/QuadMesh.js +16 -2
- package/src/renderers/common/RenderContext.js +8 -0
- package/src/renderers/common/RenderList.js +53 -19
- package/src/renderers/common/RenderLists.js +58 -11
- package/src/renderers/common/RenderObject.js +14 -0
- package/src/renderers/common/RenderObjects.js +14 -9
- package/src/renderers/common/RenderPipeline.js +52 -44
- package/src/renderers/common/Renderer.js +226 -55
- package/src/renderers/common/Storage3DTexture.js +16 -0
- package/src/renderers/common/Textures.js +3 -3
- package/src/renderers/common/XRManager.js +79 -72
- package/src/renderers/common/extras/PMREMGenerator.js +76 -144
- package/src/renderers/common/nodes/NodeManager.js +144 -6
- package/src/renderers/common/nodes/NodeStorageBuffer.js +3 -1
- package/src/renderers/common/nodes/NodeUniformBuffer.js +3 -1
- package/src/renderers/shaders/DFGLUTData.js +2 -1
- package/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +4 -2
- package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +48 -0
- package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +53 -4
- package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +20 -2
- package/src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js +20 -0
- package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +6 -0
- package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +61 -57
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +82 -0
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js +9 -0
- package/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js +8 -1
- package/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js +15 -0
- package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +4 -0
- package/src/renderers/shaders/ShaderLib.js +1 -0
- package/src/renderers/shaders/UniformsLib.js +16 -0
- package/src/renderers/webgl/WebGLAnimation.js +2 -2
- package/src/renderers/webgl/WebGLCapabilities.js +2 -2
- package/src/renderers/webgl/WebGLLights.js +74 -4
- package/src/renderers/webgl/WebGLMaterials.js +6 -0
- package/src/renderers/webgl/WebGLOutput.js +36 -24
- package/src/renderers/webgl/WebGLProgram.js +3 -0
- package/src/renderers/webgl/WebGLPrograms.js +8 -0
- package/src/renderers/webgl/WebGLRenderLists.js +6 -10
- package/src/renderers/webgl/WebGLShadowMap.js +47 -44
- package/src/renderers/webgl/WebGLTextures.js +7 -7
- package/src/renderers/webgl-fallback/WebGLBackend.js +153 -45
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +83 -29
- package/src/renderers/webgl-fallback/utils/WebGLState.js +163 -17
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +32 -5
- package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +11 -4
- package/src/renderers/webgpu/WebGPUBackend.js +513 -145
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +99 -20
- package/src/renderers/webgpu/nodes/WGSLNodeFunction.js +2 -1
- package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +3 -12
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +24 -14
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +80 -14
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +62 -7
- package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +9 -3
- package/src/renderers/webgpu/utils/WebGPUUtils.js +16 -4
- package/src/renderers/webxr/WebXRManager.js +25 -2
- package/src/scenes/Scene.js +3 -3
- package/src/textures/CompressedArrayTexture.js +16 -0
- package/src/textures/Data3DTexture.js +16 -0
- package/src/textures/DataArrayTexture.js +16 -0
- package/src/textures/DepthTexture.js +3 -3
- package/src/textures/Texture.js +3 -3
- package/src/textures/{Source.js → TextureSource.js} +39 -8
- package/build/three.core.min.js +0 -6
- package/build/three.module.min.js +0 -6
- package/build/three.tsl.min.js +0 -6
- package/build/three.webgpu.min.js +0 -6
- package/build/three.webgpu.nodes.min.js +0 -6
- package/examples/jsm/libs/ecsy.module.js +0 -1792
- package/examples/jsm/loaders/LottieLoader.js +0 -130
- package/src/nodes/functions/BSDF/BRDF_GGX_Multiscatter.js +0 -52
|
@@ -1,122 +1,288 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Box3,
|
|
3
3
|
CubeCamera,
|
|
4
|
+
CubeRenderTarget,
|
|
4
5
|
FloatType,
|
|
5
6
|
HalfFloatType,
|
|
7
|
+
Light,
|
|
6
8
|
LinearFilter,
|
|
7
|
-
|
|
9
|
+
MathUtils,
|
|
8
10
|
NearestFilter,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
NodeMaterial,
|
|
12
|
+
QuadMesh,
|
|
13
|
+
RenderTarget,
|
|
14
|
+
RenderTarget3D,
|
|
12
15
|
RGBAFormat,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Vector4,
|
|
17
|
-
WebGL3DRenderTarget,
|
|
18
|
-
WebGLCubeRenderTarget,
|
|
19
|
-
WebGLRenderTarget
|
|
20
|
-
} from '@gnsx/three';
|
|
21
|
-
// WITH_GENESYS
|
|
22
|
-
import { CubeRenderTarget, Storage3DTexture } from '@gnsx/three/webgpu';
|
|
16
|
+
Vector3
|
|
17
|
+
} from '@gnsx/three/webgpu';
|
|
18
|
+
|
|
23
19
|
import {
|
|
24
|
-
|
|
25
|
-
If,
|
|
26
|
-
Loop,
|
|
27
|
-
PI,
|
|
28
|
-
convert,
|
|
20
|
+
array,
|
|
29
21
|
cubeTexture,
|
|
30
22
|
float,
|
|
23
|
+
Fn,
|
|
31
24
|
int,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
ivec2,
|
|
26
|
+
Loop,
|
|
27
|
+
screenCoordinate,
|
|
28
|
+
texture,
|
|
35
29
|
uniform,
|
|
36
|
-
uint,
|
|
37
|
-
uvec3,
|
|
38
30
|
vec3,
|
|
39
31
|
vec4
|
|
40
32
|
} from '@gnsx/three/tsl';
|
|
41
|
-
// !WITH_GENESYS
|
|
42
33
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
let _camera = null;
|
|
46
|
-
let _mesh = null;
|
|
34
|
+
import { LightProbeGridNode, ATLAS_PADDING } from '../tsl/lighting/LightProbeGridNode.js';
|
|
35
|
+
import { replaceSunLights, restoreSunLights } from './LightProbeGridUtils.js';
|
|
47
36
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
let _lastCubemapSize = 0;
|
|
37
|
+
// Shared fullscreen-quad for the bake passes.
|
|
38
|
+
const _quad = /*@__PURE__*/ new QuadMesh();
|
|
51
39
|
|
|
52
|
-
//
|
|
40
|
+
// Reusable temp objects.
|
|
41
|
+
const _position = /*@__PURE__*/ new Vector3();
|
|
42
|
+
const _size = /*@__PURE__*/ new Vector3();
|
|
43
|
+
const _copyRegion = /*@__PURE__*/ new Box3();
|
|
44
|
+
|
|
45
|
+
// Bake materials, shared across grids so the shaders compile once, not per bake.
|
|
46
|
+
let _shMaterial = null;
|
|
47
|
+
let _shSampleCount = - 1;
|
|
48
|
+
let _cubeNode = null;
|
|
49
|
+
let _batchNode = null;
|
|
50
|
+
let _resolutionUniform = null;
|
|
51
|
+
let _sliceZUniform = null;
|
|
53
52
|
let _repackMaterials = null;
|
|
54
53
|
|
|
55
|
-
//
|
|
54
|
+
// Bake render targets, pooled by size so rebakes don't churn allocations.
|
|
56
55
|
let _cubeRenderTarget = null;
|
|
57
56
|
let _cubeCamera = null;
|
|
58
|
-
let
|
|
59
|
-
let _cachedNear = 0;
|
|
60
|
-
let _cachedFar = 0;
|
|
61
|
-
|
|
62
|
-
// WITH_GENESYS
|
|
63
|
-
// Cached WebGPU bake resources. The WebGPU path projects cubemaps on the GPU
|
|
64
|
-
// via TSL compute and writes directly into a Storage3DTexture atlas.
|
|
65
|
-
let _webgpuCubeRenderTarget = null;
|
|
66
|
-
let _webgpuCubeCamera = null;
|
|
67
|
-
let _webgpuCachedCubemapSize = 0;
|
|
68
|
-
let _webgpuCachedNear = 0;
|
|
69
|
-
let _webgpuCachedFar = 0;
|
|
70
|
-
let _webgpuComputeNode = null;
|
|
71
|
-
let _webgpuComputeCubemapSize = 0;
|
|
72
|
-
let _webgpuComputeAtlas = null;
|
|
73
|
-
let _webgpuComputeEnvMap = null;
|
|
74
|
-
let _webgpuProbeUniforms = null;
|
|
75
|
-
// !WITH_GENESYS
|
|
76
|
-
|
|
77
|
-
// Cached batch render target
|
|
57
|
+
let _cubeKey = '';
|
|
78
58
|
let _batchTarget = null;
|
|
79
|
-
let
|
|
59
|
+
let _batchProbes = - 1;
|
|
80
60
|
|
|
81
|
-
//
|
|
82
|
-
const
|
|
83
|
-
const _size = /*@__PURE__*/ new Vector3();
|
|
84
|
-
const _currentViewport = /*@__PURE__*/ new Vector4();
|
|
85
|
-
const _currentScissor = /*@__PURE__*/ new Vector4();
|
|
61
|
+
// Golden-angle increment for the equal-area Fibonacci sphere.
|
|
62
|
+
const GOLDEN_ANGLE = Math.PI * ( 3.0 - Math.sqrt( 5.0 ) );
|
|
86
63
|
|
|
87
|
-
|
|
88
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Returns the output node for the spherical-harmonic projection pass. Each
|
|
66
|
+
* fragment of the 9-wide batch row computes a single SH coefficient by
|
|
67
|
+
* integrating the captured cubemap over an equal-area Fibonacci sphere,
|
|
68
|
+
* selecting the basis function for its column. Sampling the cubemap by world
|
|
69
|
+
* direction keeps the projection independent of the cube face layout.
|
|
70
|
+
*
|
|
71
|
+
* @private
|
|
72
|
+
* @param {Node} cube - The captured environment cubemap texture node.
|
|
73
|
+
* @param {number} sampleCount - Number of directions to integrate.
|
|
74
|
+
* @return {Node<vec4>} The projected coefficient.
|
|
75
|
+
*/
|
|
76
|
+
function projectSHNode( cube, sampleCount ) {
|
|
77
|
+
|
|
78
|
+
return Fn( () => {
|
|
79
|
+
|
|
80
|
+
const coefIndex = int( screenCoordinate.x ).toVar();
|
|
81
|
+
const accum = vec3( 0.0 ).toVar();
|
|
82
|
+
|
|
83
|
+
Loop( sampleCount, ( { i } ) => {
|
|
84
|
+
|
|
85
|
+
const fi = float( i );
|
|
86
|
+
|
|
87
|
+
// Equal-area Fibonacci sphere direction.
|
|
88
|
+
const z = float( 1.0 ).sub( fi.mul( 2.0 ).add( 1.0 ).div( sampleCount ) );
|
|
89
|
+
const r = z.mul( z ).oneMinus().max( 0.0 ).sqrt();
|
|
90
|
+
const phi = fi.mul( GOLDEN_ANGLE );
|
|
91
|
+
const dir = vec3( r.mul( phi.cos() ), z, r.mul( phi.sin() ) ).toVar();
|
|
92
|
+
|
|
93
|
+
const radiance = cube.sample( dir ).level( 0 ).rgb;
|
|
94
|
+
|
|
95
|
+
// The L2 SH basis function for this fragment's coefficient.
|
|
96
|
+
const x = dir.x, y = dir.y, zc = dir.z;
|
|
97
|
+
const basis = array( [
|
|
98
|
+
float( 0.282095 ),
|
|
99
|
+
y.mul( 0.488603 ),
|
|
100
|
+
zc.mul( 0.488603 ),
|
|
101
|
+
x.mul( 0.488603 ),
|
|
102
|
+
x.mul( y ).mul( 1.092548 ),
|
|
103
|
+
y.mul( zc ).mul( 1.092548 ),
|
|
104
|
+
zc.mul( zc ).mul( 3.0 ).sub( 1.0 ).mul( 0.315392 ),
|
|
105
|
+
x.mul( zc ).mul( 1.092548 ),
|
|
106
|
+
x.mul( x ).sub( y.mul( y ) ).mul( 0.546274 )
|
|
107
|
+
] ).element( coefIndex );
|
|
108
|
+
|
|
109
|
+
accum.addAssign( radiance.mul( basis ) );
|
|
110
|
+
|
|
111
|
+
} );
|
|
112
|
+
|
|
113
|
+
// Equal-area quadrature: each direction covers 4*PI / sampleCount.
|
|
114
|
+
const norm = float( 4.0 * Math.PI / sampleCount );
|
|
115
|
+
|
|
116
|
+
return vec4( accum.mul( norm ), 1.0 );
|
|
117
|
+
|
|
118
|
+
} )();
|
|
119
|
+
|
|
120
|
+
}
|
|
89
121
|
|
|
90
122
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
123
|
+
* Returns the repack output node for one of the seven SH textures. It reads the
|
|
124
|
+
* 9 projected coefficients from the batch texture for the probe at the current
|
|
125
|
+
* texel and packs the four floats stored by this texture index.
|
|
93
126
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
127
|
+
* @private
|
|
128
|
+
* @param {Node} batch - The batch texture node holding projected coefficients.
|
|
129
|
+
* @param {number} textureIndex - The output texture index (0–6).
|
|
130
|
+
* @param {Node<vec3>} resolution - The probe grid resolution uniform.
|
|
131
|
+
* @param {Node<int>} sliceZ - The current Z slice being written.
|
|
132
|
+
* @return {Node<vec4>} The packed texel.
|
|
133
|
+
*/
|
|
134
|
+
function repackNode( batch, textureIndex, resolution, sliceZ ) {
|
|
135
|
+
|
|
136
|
+
return Fn( () => {
|
|
137
|
+
|
|
138
|
+
const ix = int( screenCoordinate.x );
|
|
139
|
+
const iy = int( screenCoordinate.y );
|
|
140
|
+
|
|
141
|
+
const nx = int( resolution.x );
|
|
142
|
+
const ny = int( resolution.y );
|
|
143
|
+
const probeIndex = ix.add( iy.mul( nx ) ).add( sliceZ.mul( nx ).mul( ny ) );
|
|
144
|
+
|
|
145
|
+
const c0 = batch.load( ivec2( 0, probeIndex ) );
|
|
146
|
+
const c1 = batch.load( ivec2( 1, probeIndex ) );
|
|
147
|
+
const c2 = batch.load( ivec2( 2, probeIndex ) );
|
|
148
|
+
const c3 = batch.load( ivec2( 3, probeIndex ) );
|
|
149
|
+
const c4 = batch.load( ivec2( 4, probeIndex ) );
|
|
150
|
+
const c5 = batch.load( ivec2( 5, probeIndex ) );
|
|
151
|
+
const c6 = batch.load( ivec2( 6, probeIndex ) );
|
|
152
|
+
const c7 = batch.load( ivec2( 7, probeIndex ) );
|
|
153
|
+
const c8 = batch.load( ivec2( 8, probeIndex ) );
|
|
154
|
+
|
|
155
|
+
let packed;
|
|
156
|
+
|
|
157
|
+
switch ( textureIndex ) {
|
|
158
|
+
|
|
159
|
+
case 0: packed = vec4( c0.xyz, c1.x ); break;
|
|
160
|
+
case 1: packed = vec4( c1.yz, c2.xy ); break;
|
|
161
|
+
case 2: packed = vec4( c2.z, c3.xyz ); break;
|
|
162
|
+
case 3: packed = vec4( c4.xyz, c5.x ); break;
|
|
163
|
+
case 4: packed = vec4( c5.yz, c6.xy ); break;
|
|
164
|
+
case 5: packed = vec4( c6.z, c7.xyz ); break;
|
|
165
|
+
default: packed = vec4( c8.xyz, 0.0 ); break;
|
|
166
|
+
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return packed;
|
|
170
|
+
|
|
171
|
+
} )();
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Lazily pools the shared cube and batch render targets, recreating them only
|
|
177
|
+
* when their dimensions change.
|
|
96
178
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
179
|
+
* @private
|
|
180
|
+
* @param {number} cubemapSize - Resolution of each cubemap face.
|
|
181
|
+
* @param {number} near - Cube camera near plane.
|
|
182
|
+
* @param {number} far - Cube camera far plane.
|
|
183
|
+
* @param {number} totalProbes - Number of probes (batch target height).
|
|
184
|
+
*/
|
|
185
|
+
function ensureBakeTargets( cubemapSize, near, far, totalProbes ) {
|
|
186
|
+
|
|
187
|
+
const cubeKey = `${ cubemapSize },${ near },${ far }`;
|
|
188
|
+
|
|
189
|
+
if ( _cubeRenderTarget === null || _cubeKey !== cubeKey ) {
|
|
190
|
+
|
|
191
|
+
if ( _cubeRenderTarget !== null ) _cubeRenderTarget.dispose();
|
|
192
|
+
|
|
193
|
+
_cubeRenderTarget = new CubeRenderTarget( cubemapSize, { type: HalfFloatType, generateMipmaps: false } );
|
|
194
|
+
_cubeCamera = new CubeCamera( near, far, _cubeRenderTarget );
|
|
195
|
+
_cubeKey = cubeKey;
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if ( _batchTarget === null || _batchProbes !== totalProbes ) {
|
|
200
|
+
|
|
201
|
+
if ( _batchTarget !== null ) _batchTarget.dispose();
|
|
202
|
+
|
|
203
|
+
_batchTarget = new RenderTarget( 9, totalProbes, {
|
|
204
|
+
type: FloatType,
|
|
205
|
+
format: RGBAFormat,
|
|
206
|
+
minFilter: NearestFilter,
|
|
207
|
+
magFilter: NearestFilter,
|
|
208
|
+
depthBuffer: false
|
|
209
|
+
} );
|
|
210
|
+
|
|
211
|
+
_batchProbes = totalProbes;
|
|
212
|
+
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Lazily builds the shared bake materials and rebinds them to the current
|
|
219
|
+
* cube/batch textures. The SH projection material is rebuilt only when the
|
|
220
|
+
* sample count changes; the repack materials are static.
|
|
102
221
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
222
|
+
* @private
|
|
223
|
+
* @param {number} sampleCount - Number of directions integrated by the projection.
|
|
224
|
+
* @param {CubeTexture} cubeMap - The current cube render target texture.
|
|
225
|
+
* @param {Texture} batchMap - The current batch render target texture.
|
|
226
|
+
*/
|
|
227
|
+
function ensureBakeMaterials( sampleCount, cubeMap, batchMap ) {
|
|
228
|
+
|
|
229
|
+
if ( _repackMaterials === null ) {
|
|
230
|
+
|
|
231
|
+
_cubeNode = cubeTexture( cubeMap );
|
|
232
|
+
_batchNode = texture( batchMap );
|
|
233
|
+
_resolutionUniform = uniform( new Vector3() );
|
|
234
|
+
_sliceZUniform = uniform( 0, 'int' );
|
|
235
|
+
_repackMaterials = [];
|
|
236
|
+
|
|
237
|
+
for ( let t = 0; t < 7; t ++ ) {
|
|
238
|
+
|
|
239
|
+
const material = new NodeMaterial();
|
|
240
|
+
material.outputNode = repackNode( _batchNode, t, _resolutionUniform, _sliceZUniform );
|
|
241
|
+
material.depthTest = false;
|
|
242
|
+
material.depthWrite = false;
|
|
243
|
+
_repackMaterials.push( material );
|
|
244
|
+
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
} else {
|
|
248
|
+
|
|
249
|
+
_cubeNode.value = cubeMap;
|
|
250
|
+
_batchNode.value = batchMap;
|
|
251
|
+
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if ( _shMaterial === null || _shSampleCount !== sampleCount ) {
|
|
255
|
+
|
|
256
|
+
if ( _shMaterial !== null ) _shMaterial.dispose();
|
|
257
|
+
|
|
258
|
+
_shMaterial = new NodeMaterial();
|
|
259
|
+
_shMaterial.outputNode = projectSHNode( _cubeNode, sampleCount );
|
|
260
|
+
_shMaterial.depthTest = false;
|
|
261
|
+
_shMaterial.depthWrite = false;
|
|
262
|
+
_shSampleCount = sampleCount;
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* A 3D grid of L2 Spherical Harmonic irradiance probes that provides
|
|
270
|
+
* position-dependent diffuse global illumination.
|
|
271
|
+
*
|
|
272
|
+
* This is the {@link WebGPURenderer} version of `LightProbeGrid`. The grid is a
|
|
273
|
+
* {@link Light}, so adding it to the scene applies its baked irradiance to every
|
|
274
|
+
* lit node material automatically. When using {@link WebGLRenderer}, import the
|
|
275
|
+
* grid from `LightProbeGridWebGL.js` instead.
|
|
113
276
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
277
|
+
* The baked data is stored in a single RGBA `RenderTarget3D` atlas that packs
|
|
278
|
+
* the nine L2 SH coefficients into seven sub-volumes stacked along Z. Baking is
|
|
279
|
+
* fully GPU-resident: cubemap rendering, SH projection, and texture packing all
|
|
280
|
+
* happen on the GPU with zero CPU readback.
|
|
116
281
|
*
|
|
282
|
+
* @augments Light
|
|
117
283
|
* @three_import import { LightProbeGrid } from 'three/addons/lighting/LightProbeGrid.js';
|
|
118
284
|
*/
|
|
119
|
-
class LightProbeGrid extends
|
|
285
|
+
class LightProbeGrid extends Light {
|
|
120
286
|
|
|
121
287
|
/**
|
|
122
288
|
* Constructs a new irradiance probe grid.
|
|
@@ -132,7 +298,7 @@ class LightProbeGrid extends Object3D {
|
|
|
132
298
|
*/
|
|
133
299
|
constructor( width = 1, height = 1, depth = 1, widthProbes, heightProbes, depthProbes ) {
|
|
134
300
|
|
|
135
|
-
super();
|
|
301
|
+
super( 0xffffff, 1 );
|
|
136
302
|
|
|
137
303
|
/**
|
|
138
304
|
* This flag can be used for type testing.
|
|
@@ -143,6 +309,8 @@ class LightProbeGrid extends Object3D {
|
|
|
143
309
|
*/
|
|
144
310
|
this.isLightProbeGrid = true;
|
|
145
311
|
|
|
312
|
+
this.type = 'LightProbeGrid';
|
|
313
|
+
|
|
146
314
|
/**
|
|
147
315
|
* The full width of the volume along X.
|
|
148
316
|
*
|
|
@@ -184,48 +352,37 @@ class LightProbeGrid extends Object3D {
|
|
|
184
352
|
this.boundingBox = new Box3();
|
|
185
353
|
|
|
186
354
|
/**
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*/
|
|
192
|
-
this.texture = null;
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Internal render target for GPU-resident baking.
|
|
355
|
+
* Distance in world units over which the grid contribution fades out
|
|
356
|
+
* past the volume boundary. `0` applies the contribution everywhere
|
|
357
|
+
* (clamped), which matches a single-volume setup. Use a small positive
|
|
358
|
+
* value to blend multiple overlapping grids.
|
|
196
359
|
*
|
|
197
|
-
* @
|
|
198
|
-
* @
|
|
199
|
-
* @default null
|
|
360
|
+
* @type {number}
|
|
361
|
+
* @default 0
|
|
200
362
|
*/
|
|
201
|
-
this.
|
|
363
|
+
this.falloff = 0;
|
|
202
364
|
|
|
203
365
|
/**
|
|
204
|
-
*
|
|
205
|
-
*
|
|
366
|
+
* The single RGBA atlas 3D texture storing all seven packed SH
|
|
367
|
+
* sub-volumes stacked along Z.
|
|
206
368
|
*
|
|
207
|
-
* @type {?
|
|
369
|
+
* @type {?Data3DTexture}
|
|
208
370
|
* @default null
|
|
209
371
|
*/
|
|
210
|
-
this.
|
|
372
|
+
this.texture = null;
|
|
211
373
|
|
|
212
374
|
/**
|
|
213
|
-
*
|
|
375
|
+
* Internal render target for GPU-resident baking.
|
|
214
376
|
*
|
|
215
377
|
* @private
|
|
216
|
-
* @type {?
|
|
378
|
+
* @type {?RenderTarget3D}
|
|
217
379
|
* @default null
|
|
218
380
|
*/
|
|
219
|
-
this.
|
|
381
|
+
this._renderTarget = null;
|
|
220
382
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
* @private
|
|
225
|
-
* @type {?boolean}
|
|
226
|
-
* @default null
|
|
227
|
-
*/
|
|
228
|
-
this._cubeRenderTargetsWebGPU = null;
|
|
383
|
+
// Indirect captures read a snapshot while the live atlas is updated in place.
|
|
384
|
+
this._bounceGrid = null;
|
|
385
|
+
this._bouncePass = - 1;
|
|
229
386
|
|
|
230
387
|
this.updateBoundingBox();
|
|
231
388
|
|
|
@@ -242,11 +399,11 @@ class LightProbeGrid extends Object3D {
|
|
|
242
399
|
*/
|
|
243
400
|
getProbePosition( ix, iy, iz, target ) {
|
|
244
401
|
|
|
245
|
-
// const pos = this.position;
|
|
246
402
|
// WITH_GENESYS
|
|
247
403
|
const pos = _position;
|
|
248
404
|
this.getWorldPosition( pos );
|
|
249
405
|
// !WITH_GENESYS
|
|
406
|
+
// const pos = this.position;
|
|
250
407
|
const res = this.resolution;
|
|
251
408
|
const w = this.width, h = this.height, d = this.depth;
|
|
252
409
|
|
|
@@ -278,411 +435,346 @@ class LightProbeGrid extends Object3D {
|
|
|
278
435
|
}
|
|
279
436
|
|
|
280
437
|
/**
|
|
281
|
-
* Bakes
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
438
|
+
* Bakes probes by rendering cubemaps at each probe position and
|
|
439
|
+
* projecting to L2 SH. Optionally iterates additional passes to capture
|
|
440
|
+
* indirect bounces: each extra pass samples the previous pass's data as
|
|
441
|
+
* indirect light, accumulating one bounce per extra pass.
|
|
442
|
+
*
|
|
443
|
+
* Use `start` and `count` to bake a range and publish its cells immediately.
|
|
444
|
+
* Indices advance along X, then Z, then Y, filling horizontal layers from bottom
|
|
445
|
+
* to top. For incremental indirect bounces, finish the whole grid for `pass: 0`,
|
|
446
|
+
* then repeat with `pass: 1`, etc. Start each pass at index 0 to snapshot the
|
|
447
|
+
* previous pass before updating its cells.
|
|
286
448
|
*
|
|
287
|
-
*
|
|
449
|
+
* Shadow-casting instances of `SunLight` are temporarily replaced with
|
|
450
|
+
* equivalent directional lights, since their view-fitted shadow cascades
|
|
451
|
+
* cannot be frozen across probe renders.
|
|
452
|
+
*
|
|
453
|
+
* @param {WebGPURenderer} renderer - The renderer.
|
|
288
454
|
* @param {Scene} scene - The scene to render.
|
|
289
455
|
* @param {Object} [options] - Bake options.
|
|
290
456
|
* @param {number} [options.cubemapSize=8] - Resolution of each cubemap face.
|
|
291
457
|
* @param {number} [options.near=0.1] - Near plane for the cube camera.
|
|
292
458
|
* @param {number} [options.far=100] - Far plane for the cube camera.
|
|
293
|
-
* @param {number} [options.bounces=0] - Additional bounce passes
|
|
294
|
-
* @param {
|
|
295
|
-
* @
|
|
459
|
+
* @param {number} [options.bounces=0] - Additional bounce passes. Only available when baking the whole grid.
|
|
460
|
+
* @param {number} [options.sampleCount=512] - Directions integrated when projecting each cubemap to SH.
|
|
461
|
+
* @param {number} [options.start=0] - Index of the first probe to bake.
|
|
462
|
+
* @param {number} [options.count] - Number of probes to bake. Defaults to the remaining probes.
|
|
463
|
+
* @param {number} [options.pass=0] - Starting pass. Zero captures direct light; later passes sample the previous pass. Ranged calls require `bounces: 0`.
|
|
296
464
|
*/
|
|
297
|
-
|
|
465
|
+
bake( renderer, scene, options = {} ) {
|
|
466
|
+
|
|
467
|
+
// The bake is node based, so it needs a WebGPURenderer.
|
|
468
|
+
if ( renderer.isWebGPURenderer !== true ) {
|
|
298
469
|
|
|
299
|
-
|
|
300
|
-
const retainCubemaps = options.retainCubemaps === true;
|
|
470
|
+
throw new Error( 'THREE.LightProbeGrid: .bake() requires a WebGPURenderer. For WebGLRenderer, use LightProbeGridWebGL.' );
|
|
301
471
|
|
|
302
|
-
|
|
303
|
-
this.visible = false;
|
|
472
|
+
}
|
|
304
473
|
|
|
305
|
-
|
|
474
|
+
// The bake issues GPU work immediately, so the renderer must be ready.
|
|
475
|
+
if ( renderer.initialized === false ) {
|
|
306
476
|
|
|
307
|
-
|
|
308
|
-
if ( renderer.isWebGPURenderer === true ) {
|
|
477
|
+
throw new Error( 'THREE.LightProbeGrid: .bake() called before the renderer is initialized. Use "await renderer.init();" first.' );
|
|
309
478
|
|
|
310
|
-
|
|
479
|
+
}
|
|
311
480
|
|
|
312
|
-
|
|
481
|
+
// Register the light node with this renderer (idempotent).
|
|
482
|
+
if ( renderer.library.getLightNodeClass( LightProbeGrid ) === null ) {
|
|
313
483
|
|
|
314
|
-
|
|
315
|
-
const { cubeRenderTarget, cubeCamera } = _ensureBakeResources( options );
|
|
484
|
+
renderer.library.addLight( LightProbeGridNode, LightProbeGrid );
|
|
316
485
|
|
|
317
|
-
|
|
318
|
-
this.updateBoundingBox();
|
|
486
|
+
}
|
|
319
487
|
|
|
320
488
|
const res = this.resolution;
|
|
321
489
|
const totalProbes = res.x * res.y * res.z;
|
|
490
|
+
const {
|
|
491
|
+
cubemapSize = 8,
|
|
492
|
+
near = 0.1,
|
|
493
|
+
far = 100,
|
|
494
|
+
bounces = 0,
|
|
495
|
+
sampleCount = 512,
|
|
496
|
+
start = 0,
|
|
497
|
+
count = totalProbes - start,
|
|
498
|
+
pass: firstPass = 0
|
|
499
|
+
} = options;
|
|
500
|
+
const end = start + count;
|
|
501
|
+
|
|
502
|
+
if ( ! Number.isInteger( start ) || ! Number.isInteger( count ) || start < 0 || count < 0 || end > totalProbes ) {
|
|
503
|
+
|
|
504
|
+
throw new RangeError( 'THREE.LightProbeGrid: Invalid probe range.' );
|
|
322
505
|
|
|
323
|
-
|
|
324
|
-
const batchTarget = _ensureBatchTarget( totalProbes );
|
|
325
|
-
|
|
326
|
-
// Save renderer state
|
|
327
|
-
const currentRenderTarget = renderer.getRenderTarget();
|
|
328
|
-
renderer.getViewport( _currentViewport );
|
|
329
|
-
renderer.getScissor( _currentScissor );
|
|
330
|
-
const currentScissorTest = renderer.getScissorTest();
|
|
506
|
+
}
|
|
331
507
|
|
|
332
|
-
|
|
333
|
-
const currentMatrixWorldAutoUpdate = scene.matrixWorldAutoUpdate;
|
|
334
|
-
if ( currentMatrixWorldAutoUpdate === true ) {
|
|
508
|
+
if ( ! Number.isInteger( firstPass ) || firstPass < 0 || ! Number.isInteger( bounces ) || bounces < 0 ) {
|
|
335
509
|
|
|
336
|
-
|
|
337
|
-
scene.matrixWorldAutoUpdate = false;
|
|
510
|
+
throw new RangeError( 'THREE.LightProbeGrid: Pass and bounce counts must be non-negative integers.' );
|
|
338
511
|
|
|
339
512
|
}
|
|
340
513
|
|
|
341
|
-
|
|
342
|
-
// Force a single shadow update on the first render so maps are initialized.
|
|
343
|
-
const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
|
|
344
|
-
renderer.shadowMap.autoUpdate = false;
|
|
345
|
-
renderer.shadowMap.needsUpdate = true;
|
|
514
|
+
if ( bounces > 0 && count !== totalProbes ) {
|
|
346
515
|
|
|
347
|
-
|
|
516
|
+
throw new RangeError( 'THREE.LightProbeGrid: For ranged baking, use pass instead of bounces.' );
|
|
348
517
|
|
|
349
|
-
|
|
350
|
-
const rt = this._renderTarget;
|
|
518
|
+
}
|
|
351
519
|
|
|
352
|
-
|
|
520
|
+
if ( count === 0 ) return;
|
|
353
521
|
|
|
354
|
-
|
|
355
|
-
// the atlas at this point may be uninitialized or hold a prior bake).
|
|
356
|
-
// Each subsequent pass keeps the grid visible so the cube cameras read the
|
|
357
|
-
// previous pass's atlas as indirect light, accumulating one bounce per pass.
|
|
358
|
-
// Phase 1 writes to the batch target and Phase 2 only swaps it into the atlas
|
|
359
|
-
// at the very end of each pass, which gives an implicit ping-pong for free.
|
|
522
|
+
if ( firstPass > 0 && start > 0 && this._bouncePass !== firstPass ) {
|
|
360
523
|
|
|
361
|
-
|
|
524
|
+
throw new Error( 'THREE.LightProbeGrid: Start each indirect pass at probe 0.' );
|
|
362
525
|
|
|
363
|
-
|
|
526
|
+
}
|
|
364
527
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
batchTarget.viewport.set( 0, 0, 9, totalProbes );
|
|
368
|
-
renderer.setRenderTarget( batchTarget );
|
|
369
|
-
renderer.clear();
|
|
528
|
+
this._ensureTextures();
|
|
529
|
+
this.updateBoundingBox();
|
|
370
530
|
|
|
371
|
-
//
|
|
372
|
-
// Note: set viewport/scissor on the render target directly to avoid pixel ratio scaling
|
|
373
|
-
batchTarget.scissorTest = true;
|
|
531
|
+
// Bind the pooled bake resources to the current textures.
|
|
374
532
|
|
|
375
|
-
|
|
376
|
-
|
|
533
|
+
ensureBakeTargets( cubemapSize, near, far, totalProbes );
|
|
534
|
+
ensureBakeMaterials( sampleCount, _cubeRenderTarget.texture, _batchTarget.texture );
|
|
535
|
+
_resolutionUniform.value.copy( res );
|
|
377
536
|
|
|
378
|
-
|
|
537
|
+
// Save renderer / scene state to restore after the bake.
|
|
379
538
|
|
|
380
|
-
|
|
539
|
+
const currentRenderTarget = renderer.getRenderTarget();
|
|
540
|
+
const currentActiveCubeFace = renderer.getActiveCubeFace();
|
|
541
|
+
const currentActiveMipmapLevel = renderer.getActiveMipmapLevel();
|
|
542
|
+
const currentAutoClear = renderer.autoClear;
|
|
543
|
+
const currentXrEnabled = renderer.xr.enabled;
|
|
544
|
+
const currentInspectorEnabled = renderer.inspector.enabled;
|
|
545
|
+
const currentMatrixWorldAutoUpdate = scene.matrixWorldAutoUpdate;
|
|
546
|
+
const currentVisible = this.visible;
|
|
547
|
+
const renderTarget = this._renderTarget;
|
|
548
|
+
const currentViewport = renderTarget.viewport.clone();
|
|
549
|
+
const shadowStates = [];
|
|
550
|
+
let replacedSunLights = null;
|
|
381
551
|
|
|
382
|
-
|
|
552
|
+
try {
|
|
383
553
|
|
|
384
|
-
|
|
554
|
+
renderer.inspector.enabled = false;
|
|
555
|
+
this.visible = false;
|
|
385
556
|
|
|
386
|
-
|
|
387
|
-
this.cubeTextures = new Array( totalProbes );
|
|
557
|
+
// Scene is static during the bake: update once, disable auto-update.
|
|
388
558
|
|
|
389
|
-
|
|
559
|
+
if ( currentMatrixWorldAutoUpdate === true ) {
|
|
390
560
|
|
|
391
|
-
|
|
561
|
+
scene.updateMatrixWorld( true );
|
|
562
|
+
scene.matrixWorldAutoUpdate = false;
|
|
392
563
|
|
|
393
564
|
}
|
|
394
565
|
|
|
395
|
-
|
|
566
|
+
replacedSunLights = replaceSunLights( scene );
|
|
396
567
|
|
|
397
|
-
|
|
568
|
+
// Render each shadow map once, not once per cube face.
|
|
398
569
|
|
|
399
|
-
|
|
570
|
+
scene.traverse( ( object ) => {
|
|
400
571
|
|
|
401
|
-
|
|
572
|
+
if ( object.isLight && object.castShadow && object.shadow ) {
|
|
402
573
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
if ( retainCubemaps ) {
|
|
408
|
-
|
|
409
|
-
const retainedTarget = this._ensureRetainedCubeRenderTarget( probeIndex, options );
|
|
410
|
-
const retainedCamera = new CubeCamera(
|
|
411
|
-
options.near !== undefined ? options.near : 0.1,
|
|
412
|
-
options.far !== undefined ? options.far : 100,
|
|
413
|
-
retainedTarget
|
|
414
|
-
);
|
|
415
|
-
|
|
416
|
-
retainedCamera.position.copy( _position );
|
|
417
|
-
retainedCamera.update( renderer, scene );
|
|
418
|
-
|
|
419
|
-
envMapTexture = retainedTarget.texture;
|
|
420
|
-
this.cubeTextures[ probeIndex ] = retainedTarget.texture;
|
|
421
|
-
|
|
422
|
-
} else {
|
|
423
|
-
|
|
424
|
-
cubeCamera.position.copy( _position );
|
|
425
|
-
cubeCamera.update( renderer, scene );
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// SH projection
|
|
430
|
-
_shMaterial.uniforms.envMap.value = envMapTexture;
|
|
431
|
-
_mesh.material = _shMaterial;
|
|
432
|
-
batchTarget.viewport.set( 0, probeIndex, 9, 1 );
|
|
433
|
-
batchTarget.scissor.set( 0, probeIndex, 9, 1 );
|
|
434
|
-
renderer.setRenderTarget( batchTarget );
|
|
435
|
-
renderer.render( _scene, _camera );
|
|
574
|
+
const shadow = object.shadow;
|
|
575
|
+
shadowStates.push( { shadow, autoUpdate: shadow.autoUpdate } );
|
|
576
|
+
shadow.autoUpdate = false;
|
|
577
|
+
shadow.needsUpdate = true;
|
|
436
578
|
|
|
437
579
|
}
|
|
438
580
|
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// Phase 2: Repack SH data from batch target into the atlas 3D texture on the GPU.
|
|
444
|
-
//
|
|
445
|
-
// For each of the 7 packed sub-volumes (texture index t) we write:
|
|
446
|
-
// - A leading padding slice (copy of data slice iz = 0)
|
|
447
|
-
// - All nz data slices (iz = 0 to nz-1)
|
|
448
|
-
// - A trailing padding slice (copy of data slice iz = nz-1)
|
|
449
|
-
//
|
|
450
|
-
// In the atlas the slices for sub-volume t occupy the range:
|
|
451
|
-
// [ t * paddedSlices, t * paddedSlices + paddedSlices - 1 ]
|
|
452
|
-
// where paddedSlices = nz + 2 * ATLAS_PADDING.
|
|
453
|
-
|
|
454
|
-
rt.scissorTest = false;
|
|
455
|
-
rt.viewport.set( 0, 0, res.x, res.y );
|
|
456
|
-
|
|
457
|
-
for ( let t = 0; t < 7; t ++ ) {
|
|
458
|
-
|
|
459
|
-
_repackMaterials[ t ].uniforms.batchTexture.value = batchTarget.texture;
|
|
460
|
-
_repackMaterials[ t ].uniforms.resolution.value.copy( res );
|
|
581
|
+
} );
|
|
461
582
|
|
|
462
|
-
|
|
463
|
-
for ( let iz = 0; iz < res.z; iz ++ ) {
|
|
583
|
+
for ( let pass = firstPass; pass <= firstPass + bounces; pass ++ ) {
|
|
464
584
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
renderer.render( _scene, _camera );
|
|
585
|
+
this._updateBounceGrid( renderer, scene, pass, start );
|
|
586
|
+
this._captureProbes( renderer, scene, start, end );
|
|
587
|
+
this._repackProbes( renderer, start, end );
|
|
469
588
|
|
|
470
589
|
}
|
|
471
590
|
|
|
472
|
-
|
|
473
|
-
_repackMaterials[ t ].uniforms.sliceZ.value = 0;
|
|
474
|
-
_mesh.material = _repackMaterials[ t ];
|
|
475
|
-
renderer.setRenderTarget( rt, t * paddedSlices );
|
|
476
|
-
renderer.render( _scene, _camera );
|
|
591
|
+
} finally {
|
|
477
592
|
|
|
478
|
-
//
|
|
479
|
-
_repackMaterials[ t ].uniforms.sliceZ.value = res.z - 1;
|
|
480
|
-
_mesh.material = _repackMaterials[ t ];
|
|
481
|
-
renderer.setRenderTarget( rt, t * paddedSlices + ATLAS_PADDING + res.z );
|
|
482
|
-
renderer.render( _scene, _camera );
|
|
593
|
+
// Restore renderer / scene state (pooled targets and materials kept).
|
|
483
594
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
595
|
+
renderTarget.viewport.copy( currentViewport );
|
|
596
|
+
renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel );
|
|
597
|
+
renderer.autoClear = currentAutoClear;
|
|
598
|
+
renderer.xr.enabled = currentXrEnabled;
|
|
599
|
+
scene.matrixWorldAutoUpdate = currentMatrixWorldAutoUpdate;
|
|
487
600
|
|
|
488
|
-
|
|
601
|
+
for ( const { shadow, autoUpdate } of shadowStates ) shadow.autoUpdate = autoUpdate;
|
|
489
602
|
|
|
490
|
-
|
|
491
|
-
renderer.setRenderTarget( currentRenderTarget );
|
|
492
|
-
renderer.setViewport( _currentViewport );
|
|
493
|
-
renderer.setScissor( _currentScissor );
|
|
494
|
-
renderer.setScissorTest( currentScissorTest );
|
|
603
|
+
if ( replacedSunLights !== null ) restoreSunLights( scene, replacedSunLights );
|
|
495
604
|
|
|
496
|
-
|
|
605
|
+
this.visible = currentVisible;
|
|
606
|
+
if ( this._bounceGrid !== null ) this._bounceGrid.removeFromParent();
|
|
497
607
|
|
|
498
|
-
|
|
608
|
+
renderer.inspector.enabled = currentInspectorEnabled;
|
|
499
609
|
|
|
500
610
|
}
|
|
501
611
|
|
|
502
|
-
this.visible = wasVisible; // WITH_GENESYS
|
|
503
|
-
// this.visible = true;
|
|
504
|
-
|
|
505
612
|
}
|
|
506
613
|
|
|
507
|
-
// WITH_GENESYS
|
|
508
614
|
/**
|
|
509
|
-
*
|
|
615
|
+
* Snapshots each indirect pass before its first range overwrites the live atlas.
|
|
616
|
+
* A separate light keeps the capture and main-view texture bindings stable.
|
|
510
617
|
*
|
|
511
618
|
* @private
|
|
512
|
-
* @param {
|
|
513
|
-
* @param {
|
|
514
|
-
* @param {
|
|
515
|
-
* @
|
|
619
|
+
* @param {WebGPURenderer} renderer - The renderer.
|
|
620
|
+
* @param {Scene} scene - The scene to capture.
|
|
621
|
+
* @param {number} pass - The bounce pass.
|
|
622
|
+
* @param {number} start - The first probe index.
|
|
516
623
|
*/
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
const cubemapSize = options.cubemapSize !== undefined ? options.cubemapSize : 8;
|
|
624
|
+
_updateBounceGrid( renderer, scene, pass, start ) {
|
|
520
625
|
|
|
521
|
-
if (
|
|
626
|
+
if ( pass === 0 ) {
|
|
522
627
|
|
|
523
|
-
this.
|
|
628
|
+
if ( start === 0 ) this._bouncePass = - 1;
|
|
629
|
+
return;
|
|
524
630
|
|
|
525
631
|
}
|
|
526
632
|
|
|
527
|
-
if (
|
|
633
|
+
if ( start === 0 ) {
|
|
528
634
|
|
|
529
|
-
|
|
635
|
+
const renderTarget = this._renderTarget;
|
|
530
636
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
this._cubeRenderTargetsWebGPU = webgpu;
|
|
534
|
-
|
|
535
|
-
let target = this._cubeRenderTargets[ probeIndex ];
|
|
637
|
+
if ( this._bounceGrid === null ) {
|
|
536
638
|
|
|
537
|
-
|
|
639
|
+
const res = this.resolution;
|
|
640
|
+
this._bounceGrid = new LightProbeGrid( this.width, this.height, this.depth, res.x, res.y, res.z );
|
|
641
|
+
this._bounceGrid._ensureTextures();
|
|
538
642
|
|
|
539
|
-
|
|
643
|
+
}
|
|
540
644
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
645
|
+
renderer.initRenderTarget( renderTarget );
|
|
646
|
+
renderer.initRenderTarget( this._bounceGrid._renderTarget );
|
|
647
|
+
_copyRegion.min.set( 0, 0, 0 );
|
|
648
|
+
_copyRegion.max.set( renderTarget.width, renderTarget.height, renderTarget.depth );
|
|
649
|
+
renderer.copyTextureToTexture( renderTarget.texture, this._bounceGrid.texture, _copyRegion );
|
|
650
|
+
this._bouncePass = pass;
|
|
545
651
|
|
|
546
652
|
}
|
|
547
653
|
|
|
548
|
-
|
|
654
|
+
const bounceGrid = this._bounceGrid;
|
|
655
|
+
bounceGrid.boundingBox.copy( this.boundingBox );
|
|
656
|
+
bounceGrid.intensity = this.intensity;
|
|
657
|
+
bounceGrid.falloff = this.falloff;
|
|
658
|
+
scene.add( bounceGrid );
|
|
549
659
|
|
|
550
660
|
}
|
|
551
661
|
|
|
552
662
|
/**
|
|
553
|
-
*
|
|
663
|
+
* Captures cubemaps and projects their SH coefficients into the batch target.
|
|
554
664
|
*
|
|
555
665
|
* @private
|
|
666
|
+
* @param {WebGPURenderer} renderer - The renderer.
|
|
667
|
+
* @param {Scene} scene - The scene to capture.
|
|
668
|
+
* @param {number} start - The first probe index.
|
|
669
|
+
* @param {number} end - The exclusive end probe index.
|
|
556
670
|
*/
|
|
557
|
-
|
|
671
|
+
_captureProbes( renderer, scene, start, end ) {
|
|
558
672
|
|
|
559
|
-
|
|
673
|
+
const { x: nx, y: ny, z: nz } = this.resolution;
|
|
674
|
+
const probesPerLayer = nx * nz;
|
|
560
675
|
|
|
561
|
-
|
|
676
|
+
_quad.material = _shMaterial;
|
|
562
677
|
|
|
563
|
-
|
|
678
|
+
for ( let probeIndex = start; probeIndex < end; probeIndex ++ ) {
|
|
564
679
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
680
|
+
const ix = probeIndex % nx;
|
|
681
|
+
const iy = Math.floor( probeIndex / probesPerLayer );
|
|
682
|
+
const iz = Math.floor( probeIndex / nx ) % nz;
|
|
568
683
|
|
|
569
|
-
|
|
684
|
+
this.getProbePosition( ix, iy, iz, _position );
|
|
685
|
+
_cubeCamera.position.copy( _position );
|
|
570
686
|
|
|
571
|
-
|
|
572
|
-
|
|
687
|
+
// The cube faces must be cleared per face.
|
|
688
|
+
renderer.autoClear = true;
|
|
689
|
+
_cubeCamera.update( renderer, scene );
|
|
573
690
|
|
|
574
|
-
|
|
691
|
+
// Keep batch rows in texture order (X, Y, Z).
|
|
692
|
+
const batchRow = ix + iy * nx + iz * nx * ny;
|
|
575
693
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
694
|
+
renderer.autoClear = false;
|
|
695
|
+
_batchTarget.viewport.set( 0, batchRow, 9, 1 );
|
|
696
|
+
renderer.setRenderTarget( _batchTarget );
|
|
697
|
+
_quad.render( renderer );
|
|
580
698
|
|
|
581
|
-
|
|
699
|
+
}
|
|
582
700
|
|
|
583
701
|
}
|
|
584
702
|
|
|
585
703
|
/**
|
|
586
|
-
*
|
|
704
|
+
* Packs a probe range into the live atlas, including its boundary padding.
|
|
587
705
|
*
|
|
588
706
|
* @private
|
|
589
|
-
* @async
|
|
590
707
|
* @param {WebGPURenderer} renderer - The renderer.
|
|
591
|
-
* @param {
|
|
592
|
-
* @param {
|
|
593
|
-
* @return {Promise<void>} Resolves when baking has completed.
|
|
708
|
+
* @param {number} start - The first probe index.
|
|
709
|
+
* @param {number} end - The exclusive end probe index.
|
|
594
710
|
*/
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
const cubemapSize = options.cubemapSize !== undefined ? options.cubemapSize : 8;
|
|
598
|
-
const retainCubemaps = options.retainCubemaps === true;
|
|
599
|
-
const { cubeRenderTarget, cubeCamera } = _ensureWebGPUBakeResources( options );
|
|
600
|
-
|
|
601
|
-
this._ensureWebGPUTexture();
|
|
602
|
-
this.updateBoundingBox();
|
|
711
|
+
_repackProbes( renderer, start, end ) {
|
|
603
712
|
|
|
604
|
-
const
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
const
|
|
608
|
-
const nx = res.x, ny = res.y, nz = res.z;
|
|
609
|
-
const totalProbes = nx * ny * nz;
|
|
713
|
+
const { x: nx, y: ny, z: nz } = this.resolution;
|
|
714
|
+
const probesPerLayer = nx * nz;
|
|
715
|
+
const startY = Math.floor( start / probesPerLayer );
|
|
716
|
+
const endY = Math.floor( end / probesPerLayer );
|
|
610
717
|
const paddedSlices = nz + 2 * ATLAS_PADDING;
|
|
718
|
+
const renderTarget = this._renderTarget;
|
|
611
719
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
const savedShadowAutoUpdate = renderer.shadowMap.autoUpdate;
|
|
615
|
-
renderer.shadowMap.autoUpdate = false;
|
|
616
|
-
renderer.shadowMap.needsUpdate = true;
|
|
617
|
-
|
|
618
|
-
// Initialize cube textures array if retaining
|
|
619
|
-
if ( retainCubemaps ) {
|
|
720
|
+
// Map the horizontal bake range to contiguous rows in each Z slice.
|
|
721
|
+
for ( let iz = 0; iz < nz; iz ++ ) {
|
|
620
722
|
|
|
621
|
-
|
|
723
|
+
const sliceStart = startY * nx + MathUtils.clamp( start % probesPerLayer - iz * nx, 0, nx );
|
|
724
|
+
const sliceEnd = endY * nx + MathUtils.clamp( end % probesPerLayer - iz * nx, 0, nx );
|
|
622
725
|
|
|
623
|
-
|
|
726
|
+
for ( let probeIndex = sliceStart; probeIndex < sliceEnd; ) {
|
|
624
727
|
|
|
625
|
-
|
|
728
|
+
const ix = probeIndex % nx;
|
|
729
|
+
const iy = Math.floor( probeIndex / nx );
|
|
626
730
|
|
|
627
|
-
|
|
731
|
+
// Coalesce complete rows within a slice into one rectangle.
|
|
732
|
+
const width = Math.min( nx - ix, sliceEnd - probeIndex );
|
|
733
|
+
let height = 1;
|
|
628
734
|
|
|
629
|
-
|
|
630
|
-
this.cubeTextures = new Array( totalProbes );
|
|
631
|
-
this._cubeRenderTargets = new Array( totalProbes );
|
|
735
|
+
if ( width === nx ) {
|
|
632
736
|
|
|
633
|
-
|
|
737
|
+
height = Math.min( ny - iy, Math.floor( ( sliceEnd - probeIndex ) / nx ) );
|
|
634
738
|
|
|
635
|
-
|
|
739
|
+
}
|
|
636
740
|
|
|
637
|
-
|
|
741
|
+
renderTarget.viewport.set( ix, iy, width, height );
|
|
742
|
+
_sliceZUniform.value = iz;
|
|
638
743
|
|
|
639
|
-
|
|
744
|
+
for ( let t = 0; t < 7; t ++ ) {
|
|
640
745
|
|
|
641
|
-
|
|
746
|
+
_quad.material = _repackMaterials[ t ];
|
|
747
|
+
const base = t * paddedSlices;
|
|
642
748
|
|
|
643
|
-
|
|
749
|
+
renderer.setRenderTarget( renderTarget, base + ATLAS_PADDING + iz );
|
|
750
|
+
_quad.render( renderer );
|
|
644
751
|
|
|
645
|
-
|
|
646
|
-
cubeCamera.position.copy( _position );
|
|
647
|
-
cubeCamera.update( renderer, scene );
|
|
752
|
+
if ( iz === 0 ) {
|
|
648
753
|
|
|
649
|
-
|
|
754
|
+
renderer.setRenderTarget( renderTarget, base );
|
|
755
|
+
_quad.render( renderer );
|
|
650
756
|
|
|
651
|
-
|
|
652
|
-
const retainedCamera = new CubeCamera(
|
|
653
|
-
options.near !== undefined ? options.near : 0.1,
|
|
654
|
-
options.far !== undefined ? options.far : 100,
|
|
655
|
-
retainedTarget
|
|
656
|
-
);
|
|
757
|
+
}
|
|
657
758
|
|
|
658
|
-
|
|
659
|
-
retainedCamera.update( renderer, scene );
|
|
759
|
+
if ( iz === nz - 1 ) {
|
|
660
760
|
|
|
661
|
-
|
|
761
|
+
renderer.setRenderTarget( renderTarget, base + ATLAS_PADDING + nz );
|
|
762
|
+
_quad.render( renderer );
|
|
662
763
|
|
|
663
764
|
}
|
|
664
765
|
|
|
665
|
-
uniforms.probeIx.value = ix;
|
|
666
|
-
uniforms.probeIy.value = iy;
|
|
667
|
-
uniforms.probeIz.value = iz;
|
|
668
|
-
|
|
669
|
-
renderer.compute( computeNode );
|
|
670
|
-
|
|
671
766
|
}
|
|
672
767
|
|
|
768
|
+
probeIndex += width * height;
|
|
769
|
+
|
|
673
770
|
}
|
|
674
771
|
|
|
675
772
|
}
|
|
676
773
|
|
|
677
|
-
renderer.shadowMap.autoUpdate = savedShadowAutoUpdate;
|
|
678
|
-
|
|
679
|
-
await renderer.backend.device.queue.onSubmittedWorkDone();
|
|
680
|
-
|
|
681
774
|
}
|
|
682
|
-
// !WITH_GENESYS
|
|
683
775
|
|
|
684
776
|
/**
|
|
685
|
-
* Ensures the atlas 3D
|
|
777
|
+
* Ensures the atlas 3D texture exists with the correct dimensions.
|
|
686
778
|
*
|
|
687
779
|
* @private
|
|
688
780
|
*/
|
|
@@ -690,547 +782,50 @@ class LightProbeGrid extends Object3D {
|
|
|
690
782
|
|
|
691
783
|
if ( this._renderTarget !== null ) return;
|
|
692
784
|
|
|
693
|
-
// WITH_GENESYS
|
|
694
|
-
if ( this.texture !== null ) {
|
|
695
|
-
|
|
696
|
-
this.texture.dispose();
|
|
697
|
-
this.texture = null;
|
|
698
|
-
|
|
699
|
-
}
|
|
700
|
-
// !WITH_GENESYS
|
|
701
|
-
|
|
702
785
|
const res = this.resolution;
|
|
703
786
|
const nx = res.x, ny = res.y, nz = res.z;
|
|
704
787
|
|
|
705
|
-
// Atlas depth: 7 sub-volumes, each with ATLAS_PADDING slices at both ends
|
|
788
|
+
// Atlas depth: 7 sub-volumes, each with ATLAS_PADDING slices at both ends.
|
|
706
789
|
const atlasDepth = 7 * ( nz + 2 * ATLAS_PADDING );
|
|
707
790
|
|
|
708
|
-
|
|
791
|
+
this._renderTarget = new RenderTarget3D( nx, ny, atlasDepth, {
|
|
792
|
+
type: HalfFloatType,
|
|
709
793
|
format: RGBAFormat,
|
|
710
|
-
type: FloatType,
|
|
711
794
|
minFilter: LinearFilter,
|
|
712
795
|
magFilter: LinearFilter,
|
|
713
796
|
generateMipmaps: false,
|
|
714
797
|
depthBuffer: false
|
|
715
798
|
} );
|
|
716
799
|
|
|
717
|
-
this.
|
|
718
|
-
this.texture = rt.texture;
|
|
800
|
+
this.texture = this._renderTarget.texture;
|
|
719
801
|
|
|
720
802
|
}
|
|
721
803
|
|
|
722
|
-
// WITH_GENESYS
|
|
723
804
|
/**
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
* @private
|
|
805
|
+
* Frees GPU resources.
|
|
727
806
|
*/
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
if ( this._renderTarget !== null ) {
|
|
731
|
-
|
|
732
|
-
this._renderTarget.dispose();
|
|
733
|
-
this._renderTarget = null;
|
|
734
|
-
this.texture = null;
|
|
735
|
-
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
const res = this.resolution;
|
|
739
|
-
const nx = res.x, ny = res.y, nz = res.z;
|
|
740
|
-
const atlasDepth = 7 * ( nz + 2 * ATLAS_PADDING );
|
|
741
|
-
|
|
742
|
-
if ( this.texture !== null ) {
|
|
743
|
-
|
|
744
|
-
const image = this.texture.image;
|
|
745
|
-
|
|
746
|
-
if ( image.width === nx && image.height === ny && image.depth === atlasDepth ) {
|
|
747
|
-
|
|
748
|
-
return;
|
|
807
|
+
dispose() {
|
|
749
808
|
|
|
750
|
-
|
|
809
|
+
if ( this._bounceGrid !== null ) {
|
|
751
810
|
|
|
752
|
-
this.
|
|
753
|
-
this.
|
|
811
|
+
this._bounceGrid.dispose();
|
|
812
|
+
this._bounceGrid = null;
|
|
813
|
+
this._bouncePass = - 1;
|
|
754
814
|
|
|
755
815
|
}
|
|
756
816
|
|
|
757
|
-
const texture = new Storage3DTexture( nx, ny, atlasDepth );
|
|
758
|
-
|
|
759
|
-
texture.format = RGBAFormat;
|
|
760
|
-
texture.type = FloatType;
|
|
761
|
-
texture.minFilter = LinearFilter;
|
|
762
|
-
texture.magFilter = LinearFilter;
|
|
763
|
-
texture.generateMipmaps = false;
|
|
764
|
-
|
|
765
|
-
this.texture = texture;
|
|
766
|
-
|
|
767
|
-
}
|
|
768
|
-
// !WITH_GENESYS
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* Frees GPU resources.
|
|
772
|
-
*/
|
|
773
|
-
dispose() {
|
|
774
|
-
|
|
775
817
|
if ( this._renderTarget !== null ) {
|
|
776
818
|
|
|
777
819
|
this._renderTarget.dispose();
|
|
778
820
|
this._renderTarget = null;
|
|
779
821
|
this.texture = null;
|
|
780
822
|
|
|
781
|
-
} else if ( this.texture !== null ) { // WITH_GENESYS
|
|
782
|
-
|
|
783
|
-
this.texture.dispose();
|
|
784
|
-
this.texture = null;
|
|
785
|
-
|
|
786
|
-
} // !WITH_GENESYS
|
|
787
|
-
|
|
788
|
-
this._disposeRetainedCubemaps();
|
|
789
|
-
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
// Internal: Ensure the shared fullscreen-quad scene exists
|
|
795
|
-
function _ensureScene() {
|
|
796
|
-
|
|
797
|
-
if ( _scene === null ) {
|
|
798
|
-
|
|
799
|
-
_camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
|
|
800
|
-
_mesh = new Mesh( new PlaneGeometry( 2, 2 ) );
|
|
801
|
-
_scene = new Scene();
|
|
802
|
-
_scene.add( _mesh );
|
|
803
|
-
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
// Internal: Ensure GPU resources for SH projection are created
|
|
809
|
-
function _ensureGPUResources( cubemapSize ) {
|
|
810
|
-
|
|
811
|
-
_ensureScene();
|
|
812
|
-
|
|
813
|
-
// Recreate material when cubemap size changes
|
|
814
|
-
if ( cubemapSize !== _lastCubemapSize ) {
|
|
815
|
-
|
|
816
|
-
if ( _shMaterial !== null ) _shMaterial.dispose();
|
|
817
|
-
|
|
818
|
-
_shMaterial = new ShaderMaterial( {
|
|
819
|
-
precision: 'highp',
|
|
820
|
-
defines: {
|
|
821
|
-
CUBEMAP_SIZE: cubemapSize
|
|
822
|
-
},
|
|
823
|
-
uniforms: {
|
|
824
|
-
envMap: { value: null }
|
|
825
|
-
},
|
|
826
|
-
vertexShader: /* glsl */`
|
|
827
|
-
void main() {
|
|
828
|
-
gl_Position = vec4( position.xy, 0.0, 1.0 );
|
|
829
|
-
}
|
|
830
|
-
`,
|
|
831
|
-
fragmentShader: /* glsl */`
|
|
832
|
-
#include <common>
|
|
833
|
-
|
|
834
|
-
uniform samplerCube envMap;
|
|
835
|
-
|
|
836
|
-
void main() {
|
|
837
|
-
|
|
838
|
-
int coefIndex = int( gl_FragCoord.x );
|
|
839
|
-
|
|
840
|
-
vec3 accum0 = vec3( 0.0 );
|
|
841
|
-
vec3 accum1 = vec3( 0.0 );
|
|
842
|
-
vec3 accum2 = vec3( 0.0 );
|
|
843
|
-
vec3 accum3 = vec3( 0.0 );
|
|
844
|
-
vec3 accum4 = vec3( 0.0 );
|
|
845
|
-
vec3 accum5 = vec3( 0.0 );
|
|
846
|
-
vec3 accum6 = vec3( 0.0 );
|
|
847
|
-
vec3 accum7 = vec3( 0.0 );
|
|
848
|
-
vec3 accum8 = vec3( 0.0 );
|
|
849
|
-
float totalWeight = 0.0;
|
|
850
|
-
float pixelSize = 2.0 / float( CUBEMAP_SIZE );
|
|
851
|
-
|
|
852
|
-
for ( int face = 0; face < 6; face ++ ) {
|
|
853
|
-
|
|
854
|
-
for ( int iy = 0; iy < CUBEMAP_SIZE; iy ++ ) {
|
|
855
|
-
|
|
856
|
-
for ( int ix = 0; ix < CUBEMAP_SIZE; ix ++ ) {
|
|
857
|
-
|
|
858
|
-
// WebGL cubemaps have a left-handed orientation (flip = -1)
|
|
859
|
-
float col = ( float( ix ) + 0.5 ) * pixelSize - 1.0;
|
|
860
|
-
float row = 1.0 - ( float( iy ) + 0.5 ) * pixelSize;
|
|
861
|
-
|
|
862
|
-
vec3 coord;
|
|
863
|
-
|
|
864
|
-
if ( face == 0 ) coord = vec3( 1.0, row, -col );
|
|
865
|
-
else if ( face == 1 ) coord = vec3( -1.0, row, col );
|
|
866
|
-
else if ( face == 2 ) coord = vec3( col, 1.0, -row );
|
|
867
|
-
else if ( face == 3 ) coord = vec3( col, -1.0, row );
|
|
868
|
-
else if ( face == 4 ) coord = vec3( col, row, 1.0 );
|
|
869
|
-
else coord = vec3( -col, row, -1.0 );
|
|
870
|
-
|
|
871
|
-
float lengthSq = dot( coord, coord );
|
|
872
|
-
float weight = 4.0 / ( sqrt( lengthSq ) * lengthSq );
|
|
873
|
-
totalWeight += weight;
|
|
874
|
-
|
|
875
|
-
vec3 dir = normalize( coord );
|
|
876
|
-
vec3 cw = textureCube( envMap, coord ).rgb * weight;
|
|
877
|
-
|
|
878
|
-
// band 0
|
|
879
|
-
accum0 += cw * 0.282095;
|
|
880
|
-
|
|
881
|
-
// band 1
|
|
882
|
-
accum1 += cw * ( 0.488603 * dir.y );
|
|
883
|
-
accum2 += cw * ( 0.488603 * dir.z );
|
|
884
|
-
accum3 += cw * ( 0.488603 * dir.x );
|
|
885
|
-
|
|
886
|
-
// band 2
|
|
887
|
-
accum4 += cw * ( 1.092548 * ( dir.x * dir.y ) );
|
|
888
|
-
accum5 += cw * ( 1.092548 * ( dir.y * dir.z ) );
|
|
889
|
-
accum6 += cw * ( 0.315392 * ( 3.0 * dir.z * dir.z - 1.0 ) );
|
|
890
|
-
accum7 += cw * ( 1.092548 * ( dir.x * dir.z ) );
|
|
891
|
-
accum8 += cw * ( 0.546274 * ( dir.x * dir.x - dir.y * dir.y ) );
|
|
892
|
-
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
float norm = 4.0 * PI / totalWeight;
|
|
900
|
-
|
|
901
|
-
vec3 accum;
|
|
902
|
-
if ( coefIndex == 0 ) accum = accum0;
|
|
903
|
-
else if ( coefIndex == 1 ) accum = accum1;
|
|
904
|
-
else if ( coefIndex == 2 ) accum = accum2;
|
|
905
|
-
else if ( coefIndex == 3 ) accum = accum3;
|
|
906
|
-
else if ( coefIndex == 4 ) accum = accum4;
|
|
907
|
-
else if ( coefIndex == 5 ) accum = accum5;
|
|
908
|
-
else if ( coefIndex == 6 ) accum = accum6;
|
|
909
|
-
else if ( coefIndex == 7 ) accum = accum7;
|
|
910
|
-
else accum = accum8;
|
|
911
|
-
|
|
912
|
-
gl_FragColor = vec4( accum * norm, 1.0 );
|
|
913
|
-
|
|
914
|
-
}
|
|
915
|
-
`
|
|
916
|
-
} );
|
|
917
|
-
|
|
918
|
-
_lastCubemapSize = cubemapSize;
|
|
919
|
-
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
// Internal: Ensure GPU resources for repacking SH into the atlas 3D texture
|
|
925
|
-
function _ensureRepackResources() {
|
|
926
|
-
|
|
927
|
-
if ( _repackMaterials !== null ) return;
|
|
928
|
-
|
|
929
|
-
_ensureScene();
|
|
930
|
-
|
|
931
|
-
// Create 7 materials, one per output texture packing
|
|
932
|
-
// Texture 0: (c0.r, c0.g, c0.b, c1.r)
|
|
933
|
-
// Texture 1: (c1.g, c1.b, c2.r, c2.g)
|
|
934
|
-
// Texture 2: (c2.b, c3.r, c3.g, c3.b)
|
|
935
|
-
// Texture 3: (c4.r, c4.g, c4.b, c5.r)
|
|
936
|
-
// Texture 4: (c5.g, c5.b, c6.r, c6.g)
|
|
937
|
-
// Texture 5: (c6.b, c7.r, c7.g, c7.b)
|
|
938
|
-
// Texture 6: (c8.r, c8.g, c8.b, 0.0)
|
|
939
|
-
|
|
940
|
-
const repackVertexShader = /* glsl */`
|
|
941
|
-
void main() {
|
|
942
|
-
gl_Position = vec4( position.xy, 0.0, 1.0 );
|
|
943
823
|
}
|
|
944
|
-
`;
|
|
945
|
-
|
|
946
|
-
_repackMaterials = [];
|
|
947
|
-
|
|
948
|
-
for ( let t = 0; t < 7; t ++ ) {
|
|
949
|
-
|
|
950
|
-
_repackMaterials[ t ] = new ShaderMaterial( {
|
|
951
|
-
precision: 'highp',
|
|
952
|
-
defines: {
|
|
953
|
-
TEXTURE_INDEX: t
|
|
954
|
-
},
|
|
955
|
-
uniforms: {
|
|
956
|
-
batchTexture: { value: null },
|
|
957
|
-
resolution: { value: new Vector3() },
|
|
958
|
-
sliceZ: { value: 0 }
|
|
959
|
-
},
|
|
960
|
-
vertexShader: repackVertexShader,
|
|
961
|
-
fragmentShader: /* glsl */`
|
|
962
|
-
uniform sampler2D batchTexture;
|
|
963
|
-
uniform vec3 resolution;
|
|
964
|
-
uniform int sliceZ;
|
|
965
|
-
|
|
966
|
-
void main() {
|
|
967
|
-
|
|
968
|
-
int ix = int( gl_FragCoord.x );
|
|
969
|
-
int iy = int( gl_FragCoord.y );
|
|
970
|
-
int iz = sliceZ;
|
|
971
|
-
|
|
972
|
-
int probeIndex = ix + iy * int( resolution.x ) + iz * int( resolution.x ) * int( resolution.y );
|
|
973
|
-
|
|
974
|
-
// Read 9 SH coefficients from the batch texture row
|
|
975
|
-
vec4 c0 = texelFetch( batchTexture, ivec2( 0, probeIndex ), 0 );
|
|
976
|
-
vec4 c1 = texelFetch( batchTexture, ivec2( 1, probeIndex ), 0 );
|
|
977
|
-
vec4 c2 = texelFetch( batchTexture, ivec2( 2, probeIndex ), 0 );
|
|
978
|
-
vec4 c3 = texelFetch( batchTexture, ivec2( 3, probeIndex ), 0 );
|
|
979
|
-
vec4 c4 = texelFetch( batchTexture, ivec2( 4, probeIndex ), 0 );
|
|
980
|
-
vec4 c5 = texelFetch( batchTexture, ivec2( 5, probeIndex ), 0 );
|
|
981
|
-
vec4 c6 = texelFetch( batchTexture, ivec2( 6, probeIndex ), 0 );
|
|
982
|
-
vec4 c7 = texelFetch( batchTexture, ivec2( 7, probeIndex ), 0 );
|
|
983
|
-
vec4 c8 = texelFetch( batchTexture, ivec2( 8, probeIndex ), 0 );
|
|
984
|
-
|
|
985
|
-
// Pack into the output format for this texture index
|
|
986
|
-
#if TEXTURE_INDEX == 0
|
|
987
|
-
gl_FragColor = vec4( c0.rgb, c1.r );
|
|
988
|
-
#elif TEXTURE_INDEX == 1
|
|
989
|
-
gl_FragColor = vec4( c1.gb, c2.rg );
|
|
990
|
-
#elif TEXTURE_INDEX == 2
|
|
991
|
-
gl_FragColor = vec4( c2.b, c3.rgb );
|
|
992
|
-
#elif TEXTURE_INDEX == 3
|
|
993
|
-
gl_FragColor = vec4( c4.rgb, c5.r );
|
|
994
|
-
#elif TEXTURE_INDEX == 4
|
|
995
|
-
gl_FragColor = vec4( c5.gb, c6.rg );
|
|
996
|
-
#elif TEXTURE_INDEX == 5
|
|
997
|
-
gl_FragColor = vec4( c6.b, c7.rgb );
|
|
998
|
-
#else
|
|
999
|
-
gl_FragColor = vec4( c8.rgb, 0.0 );
|
|
1000
|
-
#endif
|
|
1001
|
-
|
|
1002
|
-
}
|
|
1003
|
-
`
|
|
1004
|
-
} );
|
|
1005
|
-
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
// Internal: Ensure cube render target and camera exist with the right parameters
|
|
1011
|
-
function _ensureBakeResources( options ) {
|
|
1012
|
-
|
|
1013
|
-
const {
|
|
1014
|
-
cubemapSize = 8,
|
|
1015
|
-
near = 0.1,
|
|
1016
|
-
far = 100
|
|
1017
|
-
} = options;
|
|
1018
|
-
|
|
1019
|
-
if ( _cubeRenderTarget === null || cubemapSize !== _cachedCubemapSize || near !== _cachedNear || far !== _cachedFar ) {
|
|
1020
|
-
|
|
1021
|
-
if ( _cubeRenderTarget !== null ) _cubeRenderTarget.dispose();
|
|
1022
|
-
|
|
1023
|
-
_cubeRenderTarget = new WebGLCubeRenderTarget( cubemapSize, { type: HalfFloatType } );
|
|
1024
|
-
_cubeCamera = new CubeCamera( near, far, _cubeRenderTarget );
|
|
1025
|
-
_cachedCubemapSize = cubemapSize;
|
|
1026
|
-
_cachedNear = near;
|
|
1027
|
-
_cachedFar = far;
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
_ensureGPUResources( cubemapSize );
|
|
1032
|
-
|
|
1033
|
-
return { cubeRenderTarget: _cubeRenderTarget, cubeCamera: _cubeCamera };
|
|
1034
|
-
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
// WITH_GENESYS
|
|
1038
|
-
function _ensureWebGPUBakeResources( options ) {
|
|
1039
|
-
|
|
1040
|
-
const {
|
|
1041
|
-
cubemapSize = 8,
|
|
1042
|
-
near = 0.1,
|
|
1043
|
-
far = 100
|
|
1044
|
-
} = options;
|
|
1045
|
-
|
|
1046
|
-
if ( _webgpuCubeRenderTarget === null || cubemapSize !== _webgpuCachedCubemapSize || near !== _webgpuCachedNear || far !== _webgpuCachedFar ) {
|
|
1047
|
-
|
|
1048
|
-
if ( _webgpuCubeRenderTarget !== null ) _webgpuCubeRenderTarget.dispose();
|
|
1049
|
-
|
|
1050
|
-
_webgpuCubeRenderTarget = new CubeRenderTarget( cubemapSize, { type: HalfFloatType } );
|
|
1051
|
-
_webgpuCubeCamera = new CubeCamera( near, far, _webgpuCubeRenderTarget );
|
|
1052
|
-
_webgpuCachedCubemapSize = cubemapSize;
|
|
1053
|
-
_webgpuCachedNear = near;
|
|
1054
|
-
_webgpuCachedFar = far;
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
return { cubeRenderTarget: _webgpuCubeRenderTarget, cubeCamera: _webgpuCubeCamera };
|
|
1059
|
-
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
function _ensureWebGPUComputeResources( cubemapSize, envMapTexture, atlasTexture ) {
|
|
1063
|
-
|
|
1064
|
-
if (
|
|
1065
|
-
_webgpuComputeNode !== null &&
|
|
1066
|
-
_webgpuComputeCubemapSize === cubemapSize &&
|
|
1067
|
-
_webgpuComputeAtlas === atlasTexture &&
|
|
1068
|
-
_webgpuComputeEnvMap === envMapTexture
|
|
1069
|
-
) {
|
|
1070
|
-
|
|
1071
|
-
return _webgpuComputeNode;
|
|
1072
|
-
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
_webgpuComputeCubemapSize = cubemapSize;
|
|
1076
|
-
_webgpuComputeAtlas = atlasTexture;
|
|
1077
|
-
_webgpuComputeEnvMap = envMapTexture;
|
|
1078
|
-
|
|
1079
|
-
const probeIx = uniform( 'uint' );
|
|
1080
|
-
const probeIy = uniform( 'uint' );
|
|
1081
|
-
const probeIz = uniform( 'uint' );
|
|
1082
|
-
const paddedSlices = uniform( 'uint' );
|
|
1083
|
-
|
|
1084
|
-
_webgpuProbeUniforms = { probeIx, probeIy, probeIz, paddedSlices };
|
|
1085
|
-
|
|
1086
|
-
const atlas = storageTexture( atlasTexture );
|
|
1087
|
-
|
|
1088
|
-
const projectProbe = Fn( () => {
|
|
1089
|
-
|
|
1090
|
-
const accum0 = vec3( 0 ).toVar();
|
|
1091
|
-
const accum1 = vec3( 0 ).toVar();
|
|
1092
|
-
const accum2 = vec3( 0 ).toVar();
|
|
1093
|
-
const accum3 = vec3( 0 ).toVar();
|
|
1094
|
-
const accum4 = vec3( 0 ).toVar();
|
|
1095
|
-
const accum5 = vec3( 0 ).toVar();
|
|
1096
|
-
const accum6 = vec3( 0 ).toVar();
|
|
1097
|
-
const accum7 = vec3( 0 ).toVar();
|
|
1098
|
-
const accum8 = vec3( 0 ).toVar();
|
|
1099
|
-
const totalWeight = float( 0 ).toVar();
|
|
1100
|
-
const pixelSize = float( 2 ).div( float( cubemapSize ) );
|
|
1101
|
-
|
|
1102
|
-
Loop(
|
|
1103
|
-
{ end: 6, name: 'face', type: 'int' },
|
|
1104
|
-
{ end: cubemapSize, name: 'iy', type: 'int' },
|
|
1105
|
-
{ end: cubemapSize, name: 'ix', type: 'int' },
|
|
1106
|
-
( { face, iy, ix } ) => {
|
|
1107
|
-
|
|
1108
|
-
const col = convert( ix, 'float' ).add( 0.5 ).mul( pixelSize ).sub( 1.0 );
|
|
1109
|
-
const row = float( 1 ).sub( convert( iy, 'float' ).add( 0.5 ).mul( pixelSize ) );
|
|
1110
|
-
|
|
1111
|
-
const dirX = select( face.equal( int( 0 ) ), float( 1 ), select( face.equal( int( 1 ) ), float( - 1 ), select( face.equal( int( 5 ) ), col.negate(), col ) ) );
|
|
1112
|
-
const dirY = select( face.equal( int( 2 ) ), float( 1 ), select( face.equal( int( 3 ) ), float( - 1 ), row ) );
|
|
1113
|
-
const dirZ = select( face.equal( int( 0 ) ), col.negate(), select( face.equal( int( 1 ) ), col, select( face.equal( int( 2 ) ), row.negate(), select( face.equal( int( 3 ) ), row, select( face.equal( int( 4 ) ), float( 1 ), float( - 1 ) ) ) ) ) );
|
|
1114
|
-
const coord = vec3( dirX, dirY, dirZ );
|
|
1115
|
-
|
|
1116
|
-
const lengthSq = coord.dot( coord );
|
|
1117
|
-
const weight = float( 4 ).div( lengthSq.sqrt().mul( lengthSq ) );
|
|
1118
|
-
totalWeight.addAssign( weight );
|
|
1119
|
-
|
|
1120
|
-
const dir = coord.normalize();
|
|
1121
|
-
// Pass explicit direction; omitting UV would default to reflectVector (needs camera).
|
|
1122
|
-
const cw = cubeTexture( envMapTexture, coord ).rgb.mul( weight );
|
|
1123
|
-
|
|
1124
|
-
accum0.addAssign( cw.mul( 0.282095 ) );
|
|
1125
|
-
accum1.addAssign( cw.mul( 0.488603 ).mul( dir.y ) );
|
|
1126
|
-
accum2.addAssign( cw.mul( 0.488603 ).mul( dir.z ) );
|
|
1127
|
-
accum3.addAssign( cw.mul( 0.488603 ).mul( dir.x ) );
|
|
1128
|
-
accum4.addAssign( cw.mul( 1.092548 ).mul( dir.x ).mul( dir.y ) );
|
|
1129
|
-
accum5.addAssign( cw.mul( 1.092548 ).mul( dir.y ).mul( dir.z ) );
|
|
1130
|
-
accum6.addAssign( cw.mul( 0.315392 ).mul( dir.z.mul( dir.z ).mul( 3 ).sub( 1 ) ) );
|
|
1131
|
-
accum7.addAssign( cw.mul( 1.092548 ).mul( dir.x ).mul( dir.z ) );
|
|
1132
|
-
accum8.addAssign( cw.mul( 0.546274 ).mul( dir.x.mul( dir.x ).sub( dir.y.mul( dir.y ) ) ) );
|
|
1133
|
-
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
);
|
|
1137
|
-
|
|
1138
|
-
const norm = float( 4 ).mul( PI ).div( totalWeight );
|
|
1139
|
-
const c0 = accum0.mul( norm );
|
|
1140
|
-
const c1 = accum1.mul( norm );
|
|
1141
|
-
const c2 = accum2.mul( norm );
|
|
1142
|
-
const c3 = accum3.mul( norm );
|
|
1143
|
-
const c4 = accum4.mul( norm );
|
|
1144
|
-
const c5 = accum5.mul( norm );
|
|
1145
|
-
const c6 = accum6.mul( norm );
|
|
1146
|
-
const c7 = accum7.mul( norm );
|
|
1147
|
-
const c8 = accum8.mul( norm );
|
|
1148
|
-
|
|
1149
|
-
Loop( { end: 7, name: 't', type: 'int' }, ( { t } ) => {
|
|
1150
|
-
|
|
1151
|
-
const baseSlice = paddedSlices.mul( t );
|
|
1152
|
-
const atlasZ = baseSlice.add( 1 ).add( probeIz );
|
|
1153
|
-
const trailingSlice = baseSlice.add( paddedSlices ).sub( 1 );
|
|
1154
|
-
const lastDataSlice = paddedSlices.sub( 3 );
|
|
1155
|
-
const storeProbeValue = ( value ) => {
|
|
1156
|
-
|
|
1157
|
-
textureStore( atlas, uvec3( probeIx, probeIy, atlasZ ), value ).toWriteOnly();
|
|
1158
|
-
|
|
1159
|
-
// Write padding during the compute pass; WebGPU validation rejects atlas-to-itself copies.
|
|
1160
|
-
If( probeIz.equal( uint( 0 ) ), () => {
|
|
1161
|
-
|
|
1162
|
-
textureStore( atlas, uvec3( probeIx, probeIy, baseSlice ), value ).toWriteOnly();
|
|
1163
|
-
|
|
1164
|
-
} );
|
|
1165
|
-
|
|
1166
|
-
If( probeIz.equal( lastDataSlice ), () => {
|
|
1167
|
-
|
|
1168
|
-
textureStore( atlas, uvec3( probeIx, probeIy, trailingSlice ), value ).toWriteOnly();
|
|
1169
|
-
|
|
1170
|
-
} );
|
|
1171
|
-
|
|
1172
|
-
};
|
|
1173
|
-
|
|
1174
|
-
If( t.equal( int( 0 ) ), () => {
|
|
1175
|
-
|
|
1176
|
-
storeProbeValue( vec4( c0.x, c0.y, c0.z, c1.x ) );
|
|
1177
|
-
|
|
1178
|
-
} ).ElseIf( t.equal( int( 1 ) ), () => {
|
|
1179
|
-
|
|
1180
|
-
storeProbeValue( vec4( c1.y, c1.z, c2.x, c2.y ) );
|
|
1181
|
-
|
|
1182
|
-
} ).ElseIf( t.equal( int( 2 ) ), () => {
|
|
1183
|
-
|
|
1184
|
-
storeProbeValue( vec4( c2.z, c3.x, c3.y, c3.z ) );
|
|
1185
|
-
|
|
1186
|
-
} ).ElseIf( t.equal( int( 3 ) ), () => {
|
|
1187
|
-
|
|
1188
|
-
storeProbeValue( vec4( c4.x, c4.y, c4.z, c5.x ) );
|
|
1189
|
-
|
|
1190
|
-
} ).ElseIf( t.equal( int( 4 ) ), () => {
|
|
1191
|
-
|
|
1192
|
-
storeProbeValue( vec4( c5.y, c5.z, c6.x, c6.y ) );
|
|
1193
824
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
storeProbeValue( vec4( c6.z, c7.x, c7.y, c7.z ) );
|
|
1197
|
-
|
|
1198
|
-
} ).Else( () => {
|
|
1199
|
-
|
|
1200
|
-
storeProbeValue( vec4( c8.x, c8.y, c8.z, float( 0 ) ) );
|
|
1201
|
-
|
|
1202
|
-
} );
|
|
1203
|
-
|
|
1204
|
-
} );
|
|
1205
|
-
|
|
1206
|
-
} );
|
|
1207
|
-
|
|
1208
|
-
_webgpuComputeNode = projectProbe().compute( 1 );
|
|
1209
|
-
|
|
1210
|
-
return _webgpuComputeNode;
|
|
1211
|
-
|
|
1212
|
-
}
|
|
1213
|
-
// !WITH_GENESYS
|
|
1214
|
-
|
|
1215
|
-
function _ensureBatchTarget( totalProbes ) {
|
|
1216
|
-
|
|
1217
|
-
if ( _batchTarget === null || _batchTargetProbes !== totalProbes ) {
|
|
1218
|
-
|
|
1219
|
-
if ( _batchTarget !== null ) _batchTarget.dispose();
|
|
1220
|
-
|
|
1221
|
-
_batchTarget = new WebGLRenderTarget( 9, totalProbes, {
|
|
1222
|
-
type: FloatType,
|
|
1223
|
-
minFilter: NearestFilter,
|
|
1224
|
-
magFilter: NearestFilter,
|
|
1225
|
-
depthBuffer: false
|
|
1226
|
-
} );
|
|
1227
|
-
|
|
1228
|
-
_batchTargetProbes = totalProbes;
|
|
825
|
+
super.dispose();
|
|
1229
826
|
|
|
1230
827
|
}
|
|
1231
828
|
|
|
1232
|
-
return _batchTarget;
|
|
1233
|
-
|
|
1234
829
|
}
|
|
1235
830
|
|
|
1236
831
|
export { LightProbeGrid };
|