@unikia/upe-renderer 0.186.110 → 0.187.11
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/README.md +5 -7
- package/UPSTREAM.md +4 -4
- package/build/three.core.js +853 -277
- package/build/three.module.js +1098 -1280
- package/build/three.tsl.js +41938 -686
- package/build/three.webgpu.js +10604 -49055
- package/build/three.webgpu.nodes.js +9249 -5788
- package/examples/jsm/Addons.js +2 -0
- package/examples/jsm/animation/CCDIKSolver.js +17 -5
- package/examples/jsm/controls/FirstPersonControls.js +1 -1
- package/examples/jsm/controls/OrbitControls.js +27 -14
- package/examples/jsm/csm/CSMShader.js +74 -3
- package/examples/jsm/curves/CurveExtras.js +4 -4
- package/examples/jsm/curves/NURBSCurve.js +14 -0
- package/examples/jsm/exporters/EXRExporter.js +673 -16
- package/examples/jsm/exporters/GLTFExporter.js +4 -4
- package/examples/jsm/exporters/KTX2Exporter.js +1 -1
- package/examples/jsm/exporters/OBJExporter.js +48 -5
- package/examples/jsm/exporters/PLYExporter.js +22 -11
- package/examples/jsm/generators/CityGenerator.js +3 -2
- package/examples/jsm/generators/city/SkyscraperGenerator.js +63 -21
- package/examples/jsm/gpgpu/BitonicSort.js +30 -23
- package/examples/jsm/helpers/VertexTangentsHelper.js +1 -1
- package/examples/jsm/inspector/Extension.js +1 -1
- package/examples/jsm/inspector/Inspector.js +6 -46
- package/examples/jsm/inspector/RendererInspector.js +43 -8
- package/examples/jsm/inspector/Storage.js +49 -0
- package/examples/jsm/inspector/extensions/color-grading/ColorGrading.js +32 -27
- package/examples/jsm/inspector/tabs/Parameters.js +5 -1
- package/examples/jsm/inspector/tabs/Performance.js +22 -7
- package/examples/jsm/inspector/tabs/Settings.js +1 -1
- package/examples/jsm/inspector/tabs/Timeline.js +83 -7
- package/examples/jsm/inspector/tabs/Viewer.js +25 -10
- package/examples/jsm/inspector/ui/Profiler.js +1 -1
- package/examples/jsm/inspector/ui/Style.js +21 -53
- package/examples/jsm/inspector/ui/Values.js +28 -3
- package/examples/jsm/libs/fflate.module.js +83 -56
- package/examples/jsm/libs/mikktspace.README.md +27 -0
- package/examples/jsm/libs/mikktspace.module.js +721 -109
- package/examples/jsm/lighting/ClusteredLighting.js +100 -2
- package/examples/jsm/lighting/LightMapper.js +295 -0
- package/examples/jsm/lighting/LightProbeGrid.js +242 -139
- package/examples/jsm/lighting/LightProbeGridWebGL.js +30 -14
- package/examples/jsm/lighting/vxgi/VXGIConeTracer.js +54 -5
- package/examples/jsm/lighting/vxgi/VXGIIrradiance.js +43 -0
- package/examples/jsm/lighting/vxgi/VXGINode.js +13 -56
- package/examples/jsm/lighting/vxgi/VXGISceneCollector.js +316 -1
- package/examples/jsm/lighting/vxgi/VXGIVolume.js +69 -59
- package/examples/jsm/lights/SunLight.js +9 -4
- package/examples/jsm/lights/SunLightNode.js +3 -3
- package/examples/jsm/lines/LineMaterial.js +26 -10
- package/examples/jsm/loaders/3DMLoader.js +10 -1
- package/examples/jsm/loaders/3MFLoader.js +5 -1
- package/examples/jsm/loaders/AMFLoader.js +2 -0
- package/examples/jsm/loaders/BVHLoader.js +2 -0
- package/examples/jsm/loaders/ColladaLoader.js +8 -0
- package/examples/jsm/loaders/DDSLoader.js +1 -1
- package/examples/jsm/loaders/DRACOLoader.js +5 -1
- package/examples/jsm/loaders/EXRLoader.js +120 -104
- package/examples/jsm/loaders/FBXLoader.js +4 -0
- package/examples/jsm/loaders/FontLoader.js +2 -0
- package/examples/jsm/loaders/GCodeLoader.js +5 -9
- package/examples/jsm/loaders/GLTFLoader.js +112 -31
- package/examples/jsm/loaders/GaussianSplatPLYLoader.js +2 -0
- package/examples/jsm/loaders/HDRCubeTextureLoader.js +3 -0
- package/examples/jsm/loaders/IESLoader.js +46 -12
- package/examples/jsm/loaders/JXLLoader.js +159 -0
- package/examples/jsm/loaders/KMZLoader.js +6 -0
- package/examples/jsm/loaders/KSPLATLoader.js +2 -0
- package/examples/jsm/loaders/KTX2Loader.js +49 -4
- package/examples/jsm/loaders/KTXLoader.js +5 -3
- package/examples/jsm/loaders/LDrawLoader.js +15 -22
- package/examples/jsm/loaders/LUT3dlLoader.js +5 -1
- package/examples/jsm/loaders/LUTCubeLoader.js +6 -2
- package/examples/jsm/loaders/LUTImageLoader.js +2 -0
- package/examples/jsm/loaders/LWOLoader.js +6 -0
- package/examples/jsm/loaders/MD2Loader.js +2 -0
- package/examples/jsm/loaders/MDDLoader.js +4 -0
- package/examples/jsm/loaders/MTLLoader.js +8 -0
- package/examples/jsm/loaders/MaterialXLoader.js +57 -5
- package/examples/jsm/loaders/NRRDLoader.js +4 -2
- package/examples/jsm/loaders/OBJLoader.js +10 -4
- package/examples/jsm/loaders/PCDLoader.js +6 -2
- package/examples/jsm/loaders/PDBLoader.js +5 -3
- package/examples/jsm/loaders/PLYLoader.js +39 -15
- package/examples/jsm/loaders/PVRLoader.js +2 -2
- package/examples/jsm/loaders/SPLATLoader.js +2 -0
- package/examples/jsm/loaders/SPZLoader.js +2 -0
- package/examples/jsm/loaders/STLLoader.js +3 -1
- package/examples/jsm/loaders/SVGLoader.js +27 -49
- package/examples/jsm/loaders/TDSLoader.js +4 -0
- package/examples/jsm/loaders/TGALoader.js +6 -5
- package/examples/jsm/loaders/TTFLoader.js +2 -0
- package/examples/jsm/loaders/USDLoader.js +14 -0
- package/examples/jsm/loaders/UltraHDRLoader.js +2 -0
- package/examples/jsm/loaders/VOXLoader.js +3 -0
- package/examples/jsm/loaders/VRMLLoader.js +4 -0
- package/examples/jsm/loaders/VTKLoader.js +2 -0
- package/examples/jsm/loaders/XYZLoader.js +2 -0
- package/examples/jsm/loaders/collada/ColladaComposer.js +15 -8
- package/examples/jsm/loaders/materialx/MaterialXDocument.js +610 -138
- package/examples/jsm/loaders/materialx/MaterialXInterfaceValidation.js +12 -95
- package/examples/jsm/loaders/materialx/MaterialXLog.js +4 -0
- package/examples/jsm/loaders/materialx/MaterialXNodeDefs.js +99 -0
- package/examples/jsm/loaders/materialx/MaterialXNodeInterfaceRegistry.js +760 -1
- package/examples/jsm/loaders/materialx/MaterialXNodeLibrary.js +222 -372
- package/examples/jsm/loaders/materialx/MaterialXSurfaceMappings.js +163 -259
- package/examples/jsm/loaders/materialx/MaterialXUtils.js +25 -0
- package/examples/jsm/loaders/materialx/compile/MaterialXCompileRegistry.js +161 -159
- package/examples/jsm/loaders/usd/USDAParser.js +56 -47
- package/examples/jsm/loaders/usd/USDComposer.js +25 -30
- package/examples/jsm/math/ColorConverter.js +7 -3
- package/examples/jsm/math/Lut.js +2 -2
- package/examples/jsm/math/OBB.js +3 -3
- package/examples/jsm/math/Octree.js +20 -17
- package/examples/jsm/objects/GaussianSplat.js +5 -4
- package/examples/jsm/objects/Reflector.js +5 -0
- package/examples/jsm/objects/SkyMesh.js +14 -7
- package/examples/jsm/objects/Water2Mesh.js +2 -2
- package/examples/jsm/physics/RapierPhysics.js +2 -2
- package/examples/jsm/pipelines/MeshletDrawingPipeline.js +5571 -0
- package/examples/jsm/pipelines/VisibilityBufferDrawingPipeline.js +954 -0
- package/examples/jsm/postprocessing/BokehPass.js +1 -1
- package/examples/jsm/postprocessing/GTAOPass.js +26 -18
- package/examples/jsm/renderers/SVGRenderer.js +3 -2
- package/examples/jsm/shaders/GTAOShader.js +7 -4
- package/examples/jsm/shaders/PoissonDenoiseShader.js +1 -10
- package/examples/jsm/tsl/WebGLNodesHandler.js +21 -9
- package/examples/jsm/tsl/display/AfterImageNode.js +3 -3
- package/examples/jsm/tsl/display/BilateralBlurNode.js +3 -3
- package/examples/jsm/tsl/display/BloomNode.js +3 -3
- package/examples/jsm/tsl/display/ChromaticAberrationNode.js +8 -19
- package/examples/jsm/tsl/display/DenoiseNode.js +5 -5
- package/examples/jsm/tsl/display/DepthOfFieldNode.js +3 -3
- package/examples/jsm/tsl/display/DotScreenNode.js +3 -3
- package/examples/jsm/tsl/display/FSR1Node.js +3 -3
- package/examples/jsm/tsl/display/FXAANode.js +3 -10
- package/examples/jsm/tsl/display/FilmNode.js +3 -3
- package/examples/jsm/tsl/display/GTAONode.js +33 -25
- package/examples/jsm/tsl/display/GaussianBlurNode.js +3 -3
- package/examples/jsm/tsl/display/GodraysNode.js +5 -19
- package/examples/jsm/tsl/display/ImportanceSampledEnvironment.js +8 -4
- package/examples/jsm/tsl/display/LensflareNode.js +3 -3
- package/examples/jsm/tsl/display/Lut3DNode.js +3 -3
- package/examples/jsm/tsl/display/OITPassNode.js +0 -11
- package/examples/jsm/tsl/display/OutlineNode.js +107 -5
- package/examples/jsm/tsl/display/PixelationPassNode.js +85 -193
- package/examples/jsm/tsl/display/RGBShiftNode.js +3 -3
- package/examples/jsm/tsl/display/RecurrentDenoiseNode.js +23 -126
- package/examples/jsm/tsl/display/SMAANode.js +3 -3
- package/examples/jsm/tsl/display/SSAONode.js +6 -20
- package/examples/jsm/tsl/display/SSGINode.js +36 -29
- package/examples/jsm/tsl/display/SSRNode.js +135 -63
- package/examples/jsm/tsl/display/SSSNode.js +6 -20
- package/examples/jsm/tsl/display/SharpenNode.js +3 -3
- package/examples/jsm/tsl/display/SobelOperatorNode.js +3 -3
- package/examples/jsm/tsl/display/TAAUNode.js +10 -42
- package/examples/jsm/tsl/display/TRAANode.js +11 -43
- package/examples/jsm/tsl/display/TemporalReprojectNode.js +42 -47
- package/examples/jsm/tsl/display/TransitionNode.js +3 -3
- package/examples/jsm/tsl/display/lensDirt.js +30 -0
- package/examples/jsm/tsl/lighting/ClusteredLightsNode.js +482 -121
- package/examples/jsm/tsl/lighting/DynamicLightsNode.js +41 -140
- package/examples/jsm/tsl/lighting/LightProbeGridNode.js +72 -25
- package/examples/jsm/tsl/lighting/data/AmbientLightDataNode.js +6 -0
- package/examples/jsm/tsl/lighting/data/DirectionalLightDataNode.js +6 -0
- package/examples/jsm/tsl/lighting/data/HemisphereLightDataNode.js +6 -0
- package/examples/jsm/tsl/lighting/data/PointLightDataNode.js +6 -0
- package/examples/jsm/tsl/lighting/data/SpotLightDataNode.js +6 -0
- package/examples/jsm/tsl/shadows/TileShadowNode.js +102 -14
- package/examples/jsm/tsl/utils/Raymarching.js +1 -1
- package/examples/jsm/tsl/utils/SoftParticles.js +5 -12
- package/examples/jsm/tsl/utils/SpecularHelpers.js +47 -70
- package/examples/jsm/tsl/utils/TAAUtils.js +6 -17
- package/examples/jsm/utils/BufferGeometryUtils.js +110 -88
- package/examples/jsm/utils/MeshletGeometryUtils.js +417 -0
- package/examples/jsm/utils/SceneOptimizer.js +2 -1
- package/examples/jsm/utils/SceneUtils.js +1 -1
- package/examples/jsm/utils/unwrapUVs.js +865 -0
- package/examples/jsm/webxr/XREstimatedLight.js +11 -4
- package/package.json +3 -3
- package/src/Three.TSL.js +2 -683
- package/src/Three.WebGPU.Nodes.js +2 -1
- package/src/Three.WebGPU.js +2 -1
- package/src/animation/AnimationAction.js +1 -1
- package/src/animation/AnimationUtils.js +1 -3
- package/src/animation/KeyframeTrack.js +19 -0
- package/src/cameras/ArrayCamera.js +12 -0
- package/src/cameras/CubeCamera.js +3 -3
- package/src/constants.js +1 -9
- package/src/core/BufferAttribute.js +57 -21
- package/src/core/BufferGeometry.js +5 -13
- package/src/core/Clock.js +1 -1
- package/src/core/InterleavedBuffer.js +28 -18
- package/src/core/InterleavedBufferAttribute.js +54 -20
- package/src/core/Object3D.js +19 -9
- package/src/core/Raycaster.js +2 -0
- package/src/core/RenderTarget.js +11 -5
- package/src/core/UniformsGroup.js +7 -3
- package/src/extras/PMREMGenerator.js +392 -685
- package/src/extras/core/Curve.js +4 -0
- package/src/extras/core/CurvePath.js +13 -0
- package/src/extras/core/ShapePath.js +1 -1
- package/src/geometries/EdgesGeometry.js +12 -10
- package/src/geometries/LatheGeometry.js +2 -0
- package/src/helpers/PolarGridHelper.js +1 -1
- package/src/lights/Light.js +11 -0
- package/src/lights/LightProbe.js +2 -0
- package/src/lights/LightShadow.js +2 -0
- package/src/loaders/AnimationLoader.js +2 -0
- package/src/loaders/AudioLoader.js +2 -0
- package/src/loaders/BufferGeometryLoader.js +2 -0
- package/src/loaders/CompressedTextureLoader.js +2 -0
- package/src/loaders/CubeTextureLoader.js +2 -0
- package/src/loaders/DataTextureLoader.js +2 -0
- package/src/loaders/FileLoader.js +2 -0
- package/src/loaders/ImageBitmapLoader.js +3 -1
- package/src/loaders/ImageLoader.js +1 -0
- package/src/loaders/Loader.js +47 -0
- package/src/loaders/MaterialLoader.js +2 -0
- package/src/loaders/ObjectLoader.js +27 -8
- package/src/loaders/TextureLoader.js +5 -3
- package/src/loaders/nodes/NodeLoader.js +2 -0
- package/src/materials/Material.js +21 -2
- package/src/materials/MeshDepthMaterial.js +1 -1
- package/src/materials/MeshDistanceMaterial.js +1 -1
- package/src/materials/MeshLambertMaterial.js +1 -1
- package/src/materials/MeshMatcapMaterial.js +1 -1
- package/src/materials/MeshNormalMaterial.js +1 -1
- package/src/materials/MeshPhongMaterial.js +1 -1
- package/src/materials/MeshPhysicalMaterial.js +90 -11
- package/src/materials/MeshStandardMaterial.js +1 -1
- package/src/materials/MeshToonMaterial.js +1 -1
- package/src/materials/nodes/Line2NodeMaterial.js +32 -10
- package/src/materials/nodes/MeshLambertNodeMaterial.js +13 -0
- package/src/materials/nodes/MeshPhongNodeMaterial.js +13 -0
- package/src/materials/nodes/MeshPhysicalNodeMaterial.js +40 -5
- package/src/materials/nodes/MeshToonNodeMaterial.js +13 -0
- package/src/materials/nodes/NodeMaterial.js +36 -16
- package/src/materials/nodes/NodeMaterialInstance.js +193 -0
- package/src/materials/nodes/NodeMaterials.js +1 -0
- package/src/materials/nodes/PointsNodeMaterial.js +1 -1
- package/src/materials/nodes/SpriteNodeMaterial.js +3 -3
- package/src/materials/nodes/manager/NodeMaterialObserver.js +191 -22
- package/src/math/Box3.js +2 -2
- package/src/math/Color.js +8 -8
- package/src/math/ColorManagement.js +2 -21
- package/src/math/FrustumArray.js +12 -0
- package/src/math/Interpolant.js +1 -1
- package/src/math/Line3.js +2 -4
- package/src/math/MathUtils.js +33 -46
- package/src/math/Matrix2.js +1 -1
- package/src/math/Matrix3.js +1 -1
- package/src/math/Matrix4.js +1 -1
- package/src/math/Triangle.js +2 -1
- package/src/math/Vector2.js +1 -1
- package/src/math/Vector3.js +1 -1
- package/src/math/Vector4.js +1 -1
- package/src/nodes/Nodes.js +1 -0
- package/src/nodes/TSL.js +2 -0
- package/src/nodes/accessors/Arrays.js +1 -1
- package/src/nodes/accessors/Batch.js +29 -23
- package/src/nodes/accessors/BufferAttributeNode.js +21 -1
- package/src/nodes/accessors/BuiltinNode.js +6 -0
- package/src/nodes/accessors/Camera.js +100 -93
- package/src/nodes/accessors/ClippingNode.js +17 -6
- package/src/nodes/accessors/CubeTextureNode.js +12 -24
- package/src/nodes/accessors/Instance.js +198 -160
- package/src/nodes/accessors/Lights.js +19 -6
- package/src/nodes/accessors/MaterialNode.js +33 -4
- package/src/nodes/accessors/Morph.js +81 -22
- package/src/nodes/accessors/Normal.js +0 -42
- package/src/nodes/accessors/Object3DNode.js +6 -0
- package/src/nodes/accessors/PointUVNode.js +6 -0
- package/src/nodes/accessors/ReferenceAttributeNode.js +279 -0
- package/src/nodes/accessors/ReferenceBaseNode.js +6 -0
- package/src/nodes/accessors/ReferenceNode.js +6 -0
- package/src/nodes/accessors/Skinning.js +57 -52
- package/src/nodes/accessors/StorageBufferNode.js +3 -12
- package/src/nodes/accessors/TextureBicubic.js +30 -27
- package/src/nodes/accessors/TextureNode.js +164 -78
- package/src/nodes/accessors/TextureSizeNode.js +6 -0
- package/src/nodes/accessors/UniformArrayNode.js +8 -15
- package/src/nodes/accessors/VelocityNode.js +13 -8
- package/src/nodes/code/CodeNode.js +6 -0
- package/src/nodes/code/ExpressionNode.js +6 -0
- package/src/nodes/code/FunctionCallNode.js +3 -3
- package/src/nodes/code/FunctionNode.js +15 -13
- package/src/nodes/core/ArrayNode.js +3 -3
- package/src/nodes/core/AssignNode.js +10 -9
- package/src/nodes/core/AttributeNode.js +39 -0
- package/src/nodes/core/BypassNode.js +6 -0
- package/src/nodes/core/ConstNode.js +31 -1
- package/src/nodes/core/ContextNode.js +11 -6
- package/src/nodes/core/IndexNode.js +6 -0
- package/src/nodes/core/InputNode.js +6 -0
- package/src/nodes/core/InspectorNode.js +17 -31
- package/src/nodes/core/IsolateNode.js +8 -0
- package/src/nodes/core/Node.js +367 -67
- package/src/nodes/core/NodeBuilder.js +664 -222
- package/src/nodes/core/NodeUtils.js +25 -0
- package/src/nodes/core/NodeVar.js +10 -1
- package/src/nodes/core/OutputStructNode.js +6 -0
- package/src/nodes/core/OverrideContextNode.js +38 -37
- package/src/nodes/core/PropertyNode.js +14 -0
- package/src/nodes/core/StackNode.js +33 -21
- package/src/nodes/core/StructNode.js +6 -0
- package/src/nodes/core/StructTypeNode.js +6 -0
- package/src/nodes/core/SubBuildNode.js +8 -0
- package/src/nodes/core/TempNode.js +10 -35
- package/src/nodes/core/UniformGroupNode.js +6 -0
- package/src/nodes/core/VarNode.js +43 -135
- package/src/nodes/core/VaryingNode.js +33 -2
- package/src/nodes/display/BlendModes.js +5 -40
- package/src/nodes/display/BumpMapNode.js +17 -7
- package/src/nodes/display/ColorAdjustment.js +22 -10
- package/src/nodes/display/ColorSpaceFunctions.js +2 -14
- package/src/nodes/display/ColorSpaceNode.js +3 -3
- package/src/nodes/display/FrontFacingNode.js +6 -0
- package/src/nodes/display/NormalMapNode.js +3 -3
- package/src/nodes/display/PassNode.js +75 -16
- package/src/nodes/display/RenderOutputNode.js +22 -5
- package/src/nodes/display/ScreenNode.js +6 -0
- package/src/nodes/display/ToneMappingFunctions.js +9 -51
- package/src/nodes/display/ToneMappingNode.js +3 -3
- package/src/nodes/display/ToonOutlinePassNode.js +66 -2
- package/src/nodes/display/ViewportDepthNode.js +34 -4
- package/src/nodes/functions/BSDF/BRDF_EON.js +65 -0
- package/src/nodes/functions/BSDF/BRDF_GGX.js +5 -3
- package/src/nodes/functions/BSDF/BRDF_Sheen.js +2 -16
- package/src/nodes/functions/BSDF/D_GGX.js +1 -8
- package/src/nodes/functions/BSDF/D_GGX_Anisotropic.js +7 -10
- package/src/nodes/functions/BSDF/LTC.js +20 -47
- package/src/nodes/functions/BSDF/Schlick_to_F0.js +1 -9
- package/src/nodes/functions/BSDF/V_GGX_SmithCorrelated.js +1 -9
- package/src/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js +10 -13
- package/src/nodes/functions/PhysicalLightingModel.js +84 -51
- package/src/nodes/functions/VolumetricLightingModel.js +1 -1
- package/src/nodes/functions/material/getAlphaHashThreshold.js +3 -9
- package/src/nodes/functions/material/getParallaxCorrectNormal.js +10 -11
- package/src/nodes/functions/material/getRoughness.js +3 -1
- package/src/nodes/geometry/RangeNode.js +52 -69
- package/src/nodes/gpgpu/AtomicFunctionNode.js +11 -6
- package/src/nodes/gpgpu/BarrierNode.js +6 -0
- package/src/nodes/gpgpu/ComputeBuiltinNode.js +6 -0
- package/src/nodes/gpgpu/ComputeNode.js +6 -0
- package/src/nodes/gpgpu/SubgroupFunctionNode.js +38 -29
- package/src/nodes/gpgpu/WorkgroupInfoNode.js +6 -0
- package/src/nodes/lighting/AnalyticLightNode.js +7 -14
- package/src/nodes/lighting/BasicEnvironmentNode.js +5 -1
- package/src/nodes/lighting/EnvironmentNode.js +58 -8
- package/src/nodes/lighting/IESSpotLightNode.js +19 -4
- package/src/nodes/lighting/LightProbeNode.js +2 -1
- package/src/nodes/lighting/LightUtils.js +2 -2
- package/src/nodes/lighting/LightingNode.js +6 -0
- package/src/nodes/lighting/LightsNode.js +26 -32
- package/src/nodes/lighting/PointShadowNode.js +92 -48
- package/src/nodes/lighting/ProjectorLightNode.js +1 -1
- package/src/nodes/lighting/RectAreaLightNode.js +13 -14
- package/src/nodes/lighting/ShadowBaseNode.js +9 -17
- package/src/nodes/lighting/ShadowFilterNode.js +26 -3
- package/src/nodes/lighting/ShadowNode.js +13 -11
- package/src/nodes/materialx/MaterialXColor.js +2 -14
- package/src/nodes/materialx/MaterialXColorTransform.js +1 -7
- package/src/nodes/materialx/MaterialXNodes.js +8 -11
- package/src/nodes/materialx/MaterialXNoise.js +195 -454
- package/src/nodes/math/BitcastNode.js +5 -5
- package/src/nodes/math/BitcountNode.js +18 -46
- package/src/nodes/math/ConditionalNode.js +92 -22
- package/src/nodes/math/Hash.js +1 -1
- package/src/nodes/math/MathNode.js +86 -64
- package/src/nodes/math/MathUtils.js +2 -2
- package/src/nodes/math/OperatorNode.js +42 -59
- package/src/nodes/math/PackFloatNode.js +9 -9
- package/src/nodes/math/Packed4x8IntegerNode.js +20 -52
- package/src/nodes/math/TriNoise3D.js +3 -23
- package/src/nodes/math/UnpackFloatNode.js +9 -9
- package/src/nodes/pmrem/PMREMNode.js +38 -75
- package/src/nodes/pmrem/PMREMUtils.js +108 -272
- package/src/nodes/procedural/Checker.js +1 -1
- package/src/nodes/tsl/TSLCore.js +199 -74
- package/src/nodes/utils/ArrayElementNode.js +19 -1
- package/src/nodes/utils/CubeMapNode.js +3 -3
- package/src/nodes/utils/DebugNode.js +2 -2
- package/src/nodes/utils/EventNode.js +6 -0
- package/src/nodes/utils/FlipNode.js +3 -3
- package/src/nodes/utils/FunctionOverloadingNode.js +7 -1
- package/src/nodes/utils/JoinNode.js +3 -3
- package/src/nodes/utils/LoopNode.js +14 -9
- package/src/nodes/utils/MemberNode.js +18 -0
- package/src/nodes/utils/PostProcessingUtils.js +20 -25
- package/src/nodes/utils/RTTNode.js +2 -0
- package/src/nodes/utils/ReflectorNode.js +24 -0
- package/src/nodes/utils/RotateNode.js +3 -3
- package/src/nodes/utils/SampleNode.js +6 -0
- package/src/nodes/utils/SetNode.js +3 -3
- package/src/nodes/utils/SplitNode.js +6 -0
- package/src/nodes/utils/UVUtils.js +2 -2
- package/src/objects/BatchedMesh.js +146 -15
- package/src/objects/InstancedMesh.js +12 -4
- package/src/objects/Line.js +20 -0
- package/src/objects/Mesh.js +8 -0
- package/src/objects/Points.js +20 -0
- package/src/objects/Skeleton.js +26 -0
- package/src/objects/SkinnedMesh.js +3 -3
- package/src/objects/Sprite.js +10 -0
- package/src/renderers/WebGLRenderer.js +104 -70
- package/src/renderers/common/Animation.js +5 -1
- package/src/renderers/common/Attributes.js +67 -57
- package/src/renderers/common/Backend.js +78 -3
- package/src/renderers/common/BindGroup.js +11 -0
- package/src/renderers/common/Binding.js +0 -11
- package/src/renderers/common/Bindings.js +116 -10
- package/src/renderers/common/Buffer.js +1 -1
- package/src/renderers/common/ClippingContext.js +12 -1
- package/src/renderers/common/ComputePipeline.js +17 -1
- package/src/renderers/common/DirectRenderPipeline.js +7 -3
- package/src/renderers/common/Geometries.js +170 -132
- package/src/renderers/common/Info.js +1 -1
- package/src/renderers/common/InspectorBase.js +5 -5
- package/src/renderers/common/Lighting.js +59 -0
- package/src/renderers/common/Pipelines.js +26 -12
- package/src/renderers/common/ProgrammableStage.js +1 -17
- package/src/renderers/common/RenderContext.js +21 -0
- package/src/renderers/common/RenderContexts.js +13 -4
- package/src/renderers/common/RenderObject.js +111 -35
- package/src/renderers/common/RenderObjects.js +37 -19
- package/src/renderers/common/Renderer.js +537 -295
- package/src/renderers/common/RendererUtils.js +15 -0
- package/src/renderers/common/StandardDrawingPipeline.js +343 -0
- package/src/renderers/common/Storage3DTexture.js +11 -0
- package/src/renderers/common/StorageArrayTexture.js +10 -0
- package/src/renderers/common/StorageTexture.js +0 -9
- package/src/renderers/common/Textures.js +144 -37
- package/src/renderers/common/UniformsGroup.js +19 -0
- package/src/renderers/common/XRManager.js +10 -91
- package/src/renderers/common/extras/PMREMGenerator.js +298 -576
- package/src/renderers/common/nodes/NodeBuilderState.js +7 -5
- package/src/renderers/common/nodes/NodeLibrary.js +11 -35
- package/src/renderers/common/nodes/NodeManager.js +80 -31
- package/src/renderers/common/nodes/NodeSampledTexture.js +14 -0
- package/src/renderers/common/nodes/NodeSampler.js +14 -0
- package/src/renderers/common/nodes/NodeStorageBuffer.js +1 -1
- package/src/renderers/common/nodes/NodeUniformBuffer.js +1 -14
- package/src/renderers/shaders/ShaderChunk/envmap_common_pars_fragment.glsl.js +13 -4
- package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +8 -8
- package/src/renderers/shaders/ShaderChunk/lightprobes_pars_fragment.glsl.js +23 -11
- package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +21 -2
- package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +1 -1
- package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +18 -2
- package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +104 -7
- package/src/renderers/shaders/ShaderChunk/morphcolor_vertex.glsl.js +11 -2
- package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +36 -20
- package/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js +5 -0
- package/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js +6 -0
- package/src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js +5 -0
- package/src/renderers/shaders/ShaderChunk.js +0 -2
- package/src/renderers/shaders/ShaderLib/backgroundCube.glsl.js +4 -18
- package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +0 -1
- package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +0 -1
- package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +8 -1
- package/src/renderers/shaders/ShaderLib.js +3 -0
- package/src/renderers/shaders/UniformsLib.js +4 -5
- package/src/renderers/webgl/WebGLBackground.js +3 -3
- package/src/renderers/webgl/WebGLBindingStates.js +4 -2
- package/src/renderers/webgl/WebGLCapabilities.js +7 -1
- package/src/renderers/webgl/WebGLEnvironments.js +2 -2
- package/src/renderers/webgl/WebGLGeometries.js +42 -14
- package/src/renderers/webgl/WebGLMaterials.js +15 -2
- package/src/renderers/webgl/WebGLOutput.js +37 -1
- package/src/renderers/webgl/WebGLProgram.js +13 -54
- package/src/renderers/webgl/WebGLPrograms.js +22 -8
- package/src/renderers/webgl/WebGLRenderStates.js +11 -8
- package/src/renderers/webgl/WebGLShadowMap.js +6 -4
- package/src/renderers/webgl/WebGLState.js +10 -6
- package/src/renderers/webgl/WebGLTextures.js +129 -77
- package/src/renderers/webgl/WebGLUniforms.js +44 -6
- package/src/renderers/webgl/WebGLUniformsGroups.js +75 -69
- package/src/renderers/webgl-fallback/WebGLBackend.js +206 -278
- package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +154 -20
- package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +45 -42
- package/src/renderers/webgl-fallback/utils/WebGLState.js +29 -4
- package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +129 -49
- package/src/renderers/webgl-fallback/utils/WebGLVertexArrayUtils.js +346 -0
- package/src/renderers/webgpu/WebGPUBackend.js +140 -82
- package/src/renderers/webgpu/WebGPURenderer.js +1 -1
- package/src/renderers/webgpu/nodes/BasicNodeLibrary.js +10 -10
- package/src/renderers/webgpu/nodes/StandardNodeLibrary.js +10 -10
- package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +135 -60
- package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +128 -55
- package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +1 -1
- package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +15 -12
- package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +55 -19
- package/src/renderers/webgpu/utils/WebGPUUtils.js +20 -3
- package/src/renderers/webxr/WebXRController.js +3 -3
- package/src/renderers/webxr/WebXRManager.js +5 -90
- package/src/scenes/Scene.js +4 -4
- package/src/textures/CompressedTexture.js +2 -2
- package/src/textures/DepthTexture.js +2 -2
- package/src/textures/FramebufferTexture.js +11 -0
- package/src/textures/Texture.js +29 -1
- package/src/textures/TextureSource.js +1 -1
- package/src/upe.js +1 -1
- package/src/utils.js +4 -4
- package/examples/jsm/libs/surfaceNet.js +0 -201
- package/src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl.js +0 -186
|
@@ -0,0 +1,954 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StorageBufferAttribute,
|
|
3
|
+
IndirectStorageBufferAttribute,
|
|
4
|
+
Mesh,
|
|
5
|
+
BoxGeometry,
|
|
6
|
+
BufferGeometry,
|
|
7
|
+
Float32BufferAttribute
|
|
8
|
+
} from 'three/webgpu';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
Fn, If, Loop, vec2, vec3, vec4, mat3, uint, float, int, min, max, floor, sqrt, select, struct, transformNormal,
|
|
12
|
+
storage, uniform, instanceIndex, vertexIndex, screenCoordinate, varyingProperty,
|
|
13
|
+
positionGeometry, cameraViewMatrix, cameraProjectionMatrix, normalize, context, overrideNodes,
|
|
14
|
+
positionLocal, positionWorld, positionWorldDirection, positionView, positionViewDirection,
|
|
15
|
+
normalLocal, normalViewGeometry, normalWorldGeometry, tangentViewFrame, bitangentViewFrame, modelWorldMatrix, modelViewMatrix, modelPosition, atomicMax, atomicAdd, atomicStore, atomicLoad
|
|
16
|
+
} from 'three/tsl';
|
|
17
|
+
|
|
18
|
+
import { MeshletDrawingPipeline, MeshletBatch, cacheAttributes, createDebugMaterial, createDrawMaterial, createOcclusion } from './MeshletDrawingPipeline.js';
|
|
19
|
+
import { MESHLET_SIZE } from '../utils/MeshletGeometryUtils.js';
|
|
20
|
+
|
|
21
|
+
// visibility buffer packing — the depth occupies the bits above each payload
|
|
22
|
+
|
|
23
|
+
const TRIANGLE_INDEX_BITS = 16;
|
|
24
|
+
const INSTANCE_INDEX_BITS = 17;
|
|
25
|
+
const TRIANGLE_INDEX_MASK = 2 ** TRIANGLE_INDEX_BITS - 1;
|
|
26
|
+
const INSTANCE_INDEX_MASK = 2 ** INSTANCE_INDEX_BITS - 1;
|
|
27
|
+
const DEPTH_TRI_MAX = 2 ** ( 32 - TRIANGLE_INDEX_BITS ) - 1;
|
|
28
|
+
const DEPTH_INST_MAX = 2 ** ( 32 - INSTANCE_INDEX_BITS ) - 1;
|
|
29
|
+
|
|
30
|
+
const MAX_TRIANGLES = TRIANGLE_INDEX_MASK + 1;
|
|
31
|
+
const MAX_INSTANCES = INSTANCE_INDEX_MASK + 1;
|
|
32
|
+
|
|
33
|
+
// the large triangles of one batch drawn by the hardware rasterizer per frame, limited by the vertices of the pulled geometry
|
|
34
|
+
|
|
35
|
+
const MAX_HW_TRIANGLES = 65536;
|
|
36
|
+
|
|
37
|
+
let _resolveGeometry = null;
|
|
38
|
+
let _fullscreenGeometry = null;
|
|
39
|
+
|
|
40
|
+
// the corners of a triangle deformed by the position node of the material, see deformTriangle()
|
|
41
|
+
|
|
42
|
+
const DeformedTriangle = /*@__PURE__*/ struct( { positions: 'mat3', normals: 'mat3' }, 'DeformedTriangle' );
|
|
43
|
+
|
|
44
|
+
const edgeFunction = /*@__PURE__*/ Fn( ( [ a, b, c ] ) => {
|
|
45
|
+
|
|
46
|
+
return c.y.sub( a.y ).mul( b.x.sub( a.x ) ).sub( c.x.sub( a.x ).mul( b.y.sub( a.y ) ) );
|
|
47
|
+
|
|
48
|
+
} );
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns the positions and the normals of the corners of a triangle deformed by the position node of the material, in
|
|
52
|
+
* the space of the object: the node is evaluated per corner with the position, the normal and the attributes of the
|
|
53
|
+
* vertex, and the position and the normal transformed by the instance matrix, like the regular instancing of node
|
|
54
|
+
* materials. The normal assigned to `normalLocal` by the position node is the normal of the corner.
|
|
55
|
+
*
|
|
56
|
+
* @private
|
|
57
|
+
* @param {Node<vec3>} positionNode - The position node of the material.
|
|
58
|
+
* @param {Object} vertex - The functions reading the position, the normal and the attributes of a vertex.
|
|
59
|
+
* @param {Array<Node<uint>>} corners - The addresses of the vertices of the corners.
|
|
60
|
+
* @param {Node<mat4>} instanceMatrix - The instance matrix, identity for objects which are not instanced meshes.
|
|
61
|
+
* @param {Node<uint>} instance - The instance index of the material.
|
|
62
|
+
* @return {Node} The deformed positions and normals, one column per corner, see DeformedTriangle.
|
|
63
|
+
*/
|
|
64
|
+
function deformTriangle( positionNode, { position, normal, vertexUv, hasAttribute, attribute }, corners, instanceMatrix, instance ) {
|
|
65
|
+
|
|
66
|
+
return Fn( () => {
|
|
67
|
+
|
|
68
|
+
const address = uint( 0 ).toVar();
|
|
69
|
+
const cornerNormal = vec3( 0 ).toVar();
|
|
70
|
+
const positions = [ vec3( 0 ).toVar(), vec3( 0 ).toVar(), vec3( 0 ).toVar() ];
|
|
71
|
+
const normals = [ vec3( 0 ).toVar(), vec3( 0 ).toVar(), vec3( 0 ).toVar() ];
|
|
72
|
+
|
|
73
|
+
const geometryPosition = position( address );
|
|
74
|
+
const geometryNormal = normal( address );
|
|
75
|
+
|
|
76
|
+
const getAttribute = cacheAttributes( ( name ) => {
|
|
77
|
+
|
|
78
|
+
if ( name === 'position' ) return geometryPosition;
|
|
79
|
+
if ( name === 'normal' ) return geometryNormal;
|
|
80
|
+
if ( name === 'uv' ) return vertexUv( address );
|
|
81
|
+
|
|
82
|
+
return hasAttribute( name ) ? attribute( name, address ) : null;
|
|
83
|
+
|
|
84
|
+
} );
|
|
85
|
+
|
|
86
|
+
const deformed = context( positionNode.overrideNodes( [
|
|
87
|
+
[ positionLocal, instanceMatrix.mul( vec4( geometryPosition, 1.0 ) ).xyz ],
|
|
88
|
+
[ normalLocal, cornerNormal ],
|
|
89
|
+
[ instanceIndex, instance ]
|
|
90
|
+
] ), { getAttribute } );
|
|
91
|
+
|
|
92
|
+
// the node is built once, in the loop over the corners
|
|
93
|
+
|
|
94
|
+
Loop( { start: 0, end: 3, type: 'int' }, ( { i } ) => {
|
|
95
|
+
|
|
96
|
+
address.assign( select( i.equal( 0 ), corners[ 0 ], select( i.equal( 1 ), corners[ 1 ], corners[ 2 ] ) ) );
|
|
97
|
+
cornerNormal.assign( transformNormal( geometryNormal, instanceMatrix ) );
|
|
98
|
+
|
|
99
|
+
const value = vec3( deformed ).toVar();
|
|
100
|
+
|
|
101
|
+
If( i.equal( 0 ), () => {
|
|
102
|
+
|
|
103
|
+
positions[ 0 ].assign( value );
|
|
104
|
+
normals[ 0 ].assign( cornerNormal );
|
|
105
|
+
|
|
106
|
+
} ).ElseIf( i.equal( 1 ), () => {
|
|
107
|
+
|
|
108
|
+
positions[ 1 ].assign( value );
|
|
109
|
+
normals[ 1 ].assign( cornerNormal );
|
|
110
|
+
|
|
111
|
+
} ).Else( () => {
|
|
112
|
+
|
|
113
|
+
positions[ 2 ].assign( value );
|
|
114
|
+
normals[ 2 ].assign( cornerNormal );
|
|
115
|
+
|
|
116
|
+
} );
|
|
117
|
+
|
|
118
|
+
} );
|
|
119
|
+
|
|
120
|
+
return DeformedTriangle( mat3( positions[ 0 ], positions[ 1 ], positions[ 2 ] ), mat3( normals[ 0 ], normals[ 1 ], normals[ 2 ] ) );
|
|
121
|
+
|
|
122
|
+
} )();
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Returns a context which feeds the surface of the merged object covering the current fragment into
|
|
128
|
+
* the material graph: position and normal in local, world and view space, the model matrices and the
|
|
129
|
+
* first uv channel. The nodes of the material evaluate the merged object instead of the drawing mesh.
|
|
130
|
+
* If a uv gradient is given, textures sampled with the first uv channel use it instead of the hardware
|
|
131
|
+
* derivatives, which are invalid if neighbor fragments belong to other triangles. The same applies to
|
|
132
|
+
* the tangent frame of normal maps without precomputed tangents. Other attributes of the geometry are
|
|
133
|
+
* provided by the given attribute function. The surface only exists in the fragment stage, so the nodes
|
|
134
|
+
* are overridden in the fragment stage and the varyings derived from them are evaluated there as well.
|
|
135
|
+
*
|
|
136
|
+
* @private
|
|
137
|
+
* @param {Object} surface - The reconstructed surface.
|
|
138
|
+
* @return {ContextNode} The context node.
|
|
139
|
+
*/
|
|
140
|
+
function createSurfaceContext( { localPosition, localNormal, worldPosition, worldNormal, uv, uvGradient = null, tangentFrame = null, matrixWorld, attribute } ) {
|
|
141
|
+
|
|
142
|
+
const viewPosition = cameraViewMatrix.mul( vec4( worldPosition, 1.0 ) ).xyz;
|
|
143
|
+
|
|
144
|
+
const overrides = [
|
|
145
|
+
[ positionLocal, localPosition ],
|
|
146
|
+
[ positionWorld, worldPosition ],
|
|
147
|
+
[ positionWorldDirection, normalize( matrixWorld.mul( vec4( localPosition, 0.0 ) ).xyz ) ],
|
|
148
|
+
[ positionView, viewPosition ],
|
|
149
|
+
[ positionViewDirection, viewPosition.negate().normalize() ],
|
|
150
|
+
[ normalLocal, normalize( localNormal ) ],
|
|
151
|
+
[ normalWorldGeometry, normalize( worldNormal ) ],
|
|
152
|
+
[ normalViewGeometry, cameraViewMatrix.mul( vec4( worldNormal, 0.0 ) ).xyz.normalize() ],
|
|
153
|
+
[ modelWorldMatrix, matrixWorld ],
|
|
154
|
+
[ modelViewMatrix, cameraViewMatrix.mul( matrixWorld ) ],
|
|
155
|
+
[ modelPosition, matrixWorld.mul( vec4( 0.0, 0.0, 0.0, 1.0 ) ).xyz ]
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
if ( tangentFrame !== null ) overrides.push( [ tangentViewFrame, tangentFrame[ 0 ] ], [ bitangentViewFrame, tangentFrame[ 1 ] ] );
|
|
159
|
+
|
|
160
|
+
return overrideNodes( overrides, context( {
|
|
161
|
+
getAttribute: cacheAttributes( ( name ) => name === 'uv' ? uv : attribute( name ) ),
|
|
162
|
+
getTextureGradient: uvGradient !== null ? () => uvGradient : null
|
|
163
|
+
} ), 'fragment' );
|
|
164
|
+
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Creates the visibility buffers of a view, shared by all batches of a render list, and the compute
|
|
169
|
+
* node clearing them. The instances of all batches share one index range, each batch owns a slice.
|
|
170
|
+
*
|
|
171
|
+
* @private
|
|
172
|
+
* @param {number} width - The width of the view in pixels.
|
|
173
|
+
* @param {number} height - The height of the view in pixels.
|
|
174
|
+
* @return {Object} The view.
|
|
175
|
+
*/
|
|
176
|
+
function createView( width, height ) {
|
|
177
|
+
|
|
178
|
+
const pixels = width * height;
|
|
179
|
+
|
|
180
|
+
// depth(16) | triangle(16) and depth(15) | instance(17)
|
|
181
|
+
|
|
182
|
+
const screenTriAttribute = new StorageBufferAttribute( new Uint32Array( pixels ), 1 );
|
|
183
|
+
const screenInstAttribute = new StorageBufferAttribute( new Uint32Array( pixels ), 1 );
|
|
184
|
+
|
|
185
|
+
const screenTriAtomic = storage( screenTriAttribute, 'uint', pixels ).toAtomic();
|
|
186
|
+
const screenInstAtomic = storage( screenInstAttribute, 'uint', pixels ).toAtomic();
|
|
187
|
+
|
|
188
|
+
const computeClear = Fn( () => {
|
|
189
|
+
|
|
190
|
+
atomicStore( screenTriAtomic.element( instanceIndex ), uint( 0 ) );
|
|
191
|
+
atomicStore( screenInstAtomic.element( instanceIndex ), uint( 0 ) );
|
|
192
|
+
|
|
193
|
+
} )().compute( pixels, [ 256 ] ).setName( 'VisibilityBufferDrawingPipeline Clear' );
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
width,
|
|
197
|
+
height,
|
|
198
|
+
screenTriAtomic,
|
|
199
|
+
screenTriRead: storage( screenTriAttribute, 'uint', pixels ).toReadOnly(),
|
|
200
|
+
screenInstAtomic,
|
|
201
|
+
screenInstRead: storage( screenInstAttribute, 'uint', pixels ).toReadOnly(),
|
|
202
|
+
computeClear,
|
|
203
|
+
dispose() {
|
|
204
|
+
|
|
205
|
+
computeClear.dispose();
|
|
206
|
+
screenTriAttribute.dispose();
|
|
207
|
+
screenInstAttribute.dispose();
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* A batch drawing the visible clusters into a visibility buffer: a compute shader rasterizes the small
|
|
217
|
+
* triangles in software and queues the large ones for the hardware rasterizer. A resolve draws the bounding
|
|
218
|
+
* box of each object and shades the fragments whose visible triangle belongs to the object.
|
|
219
|
+
*
|
|
220
|
+
* @private
|
|
221
|
+
* @augments MeshletBatch
|
|
222
|
+
*/
|
|
223
|
+
class VisibilityBufferBatch extends MeshletBatch {
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Creates the software rasterizer, the hardware path of the large triangles and the resolve.
|
|
227
|
+
*
|
|
228
|
+
* @param {Object} shared - The nodes and resources of the batch.
|
|
229
|
+
*/
|
|
230
|
+
setupDraw( shared ) {
|
|
231
|
+
|
|
232
|
+
const {
|
|
233
|
+
createAttribute, clusters, material, renderer, receiveShadow, debug,
|
|
234
|
+
position, normal, vertexUv, hasAttribute, attribute, indexBuffer, instanceWorld, instanceMvp, objectWorld, instanceLocal, instanceData,
|
|
235
|
+
workQueue, workQueueCountRead, maxWorkItems, projScreenMatrix, viewSize
|
|
236
|
+
} = shared;
|
|
237
|
+
|
|
238
|
+
// the position node of the material is evaluated per corner of the triangles by the software rasterizer and by the
|
|
239
|
+
// resolve. the world matrices of the culling approximate the deformation, the real ones are the matrices of the
|
|
240
|
+
// objects. the instance index of the material is the index of the instance in its instanced mesh
|
|
241
|
+
|
|
242
|
+
const deformed = this.deformed;
|
|
243
|
+
const vertex = { position, normal, vertexUv, hasAttribute, attribute };
|
|
244
|
+
const stride = this.instanceDataStride;
|
|
245
|
+
|
|
246
|
+
const deformCorners = ( corners, instId ) => deformTriangle( material.positionNode, vertex, corners, instanceLocal.element( instId ), uint( instanceData.element( instId.mul( stride ) ).x ) );
|
|
247
|
+
|
|
248
|
+
// the batches of the visibility buffer draw one geometry, the triangles of the visibility buffer are indexed
|
|
249
|
+
// from the first triangle of the geometry in the geometry pool
|
|
250
|
+
|
|
251
|
+
const triangleBase = this.triangleBase = uniform( this.pool.add( clusters ), 'uint' );
|
|
252
|
+
|
|
253
|
+
this.maxRasterSize = uniform( 8, 'int' );
|
|
254
|
+
|
|
255
|
+
// the slice of the instance index range of the view owned by this batch
|
|
256
|
+
|
|
257
|
+
this.instanceOffset = uniform( 0, 'uint' );
|
|
258
|
+
|
|
259
|
+
const { maxRasterSize, instanceOffset } = this;
|
|
260
|
+
|
|
261
|
+
// visibility buffers shared by all batches of the view
|
|
262
|
+
|
|
263
|
+
const { screenTriAtomic, screenTriRead, screenInstAtomic, screenInstRead } = this.view;
|
|
264
|
+
|
|
265
|
+
const dispatchAttribute = createAttribute( new Uint32Array( 3 ), 3, IndirectStorageBufferAttribute );
|
|
266
|
+
const dispatchBuffer = storage( dispatchAttribute, 'uint', 3 );
|
|
267
|
+
|
|
268
|
+
// the software rasterizer sends large triangles to the hardware queue, the counter followed by [ instance, triangle ] pairs
|
|
269
|
+
|
|
270
|
+
const hwQueueAttribute = createAttribute( new Uint32Array( 1 + MAX_HW_TRIANGLES * 2 ), 1 );
|
|
271
|
+
const hwQueueAtomic = storage( hwQueueAttribute, 'uint', 1 + MAX_HW_TRIANGLES * 2 ).toAtomic();
|
|
272
|
+
const hwQueueRead = storage( hwQueueAttribute, 'uint', 1 + MAX_HW_TRIANGLES * 2 ).toReadOnly();
|
|
273
|
+
|
|
274
|
+
const hwDrawAttribute = createAttribute( new Uint32Array( 4 ), 4, IndirectStorageBufferAttribute );
|
|
275
|
+
const hwDrawBuffer = storage( hwDrawAttribute, 'uint', 4 );
|
|
276
|
+
|
|
277
|
+
const computeHWReset = Fn( () => {
|
|
278
|
+
|
|
279
|
+
atomicStore( hwQueueAtomic.element( 0 ), uint( 0 ) );
|
|
280
|
+
|
|
281
|
+
} )().compute( 1 ).setName( 'VisibilityBufferDrawingPipeline Reset' );
|
|
282
|
+
|
|
283
|
+
// indirect dispatch arguments, split into 2D if exceeding 65535 workgroups
|
|
284
|
+
|
|
285
|
+
const computeDispatch = Fn( () => {
|
|
286
|
+
|
|
287
|
+
const workgroups = min( workQueueCountRead.element( 0 ), maxWorkItems );
|
|
288
|
+
const maxDimension = uint( 65535 );
|
|
289
|
+
|
|
290
|
+
dispatchBuffer.element( 0 ).assign( min( workgroups, maxDimension ) );
|
|
291
|
+
dispatchBuffer.element( 1 ).assign( workgroups.add( maxDimension ).sub( 1 ).div( maxDimension ) );
|
|
292
|
+
dispatchBuffer.element( 2 ).assign( 1 );
|
|
293
|
+
|
|
294
|
+
} )().compute( 1 ).setName( 'VisibilityBufferDrawingPipeline Dispatch' );
|
|
295
|
+
|
|
296
|
+
// software rasterizer — one thread per triangle of a cluster
|
|
297
|
+
|
|
298
|
+
const computeRasterize = Fn( () => {
|
|
299
|
+
|
|
300
|
+
const totalThreads = min( workQueueCountRead.element( 0 ), maxWorkItems ).mul( MESHLET_SIZE );
|
|
301
|
+
|
|
302
|
+
If( instanceIndex.lessThan( totalThreads ), () => {
|
|
303
|
+
|
|
304
|
+
const workItem = workQueue.element( instanceIndex.div( MESHLET_SIZE ) );
|
|
305
|
+
const instId = workItem.x;
|
|
306
|
+
const lodTriangleStart = workItem.y;
|
|
307
|
+
const lodNumTriangles = workItem.z;
|
|
308
|
+
const chunk = workItem.w;
|
|
309
|
+
|
|
310
|
+
const lodTriangle = chunk.mul( MESHLET_SIZE ).add( instanceIndex.mod( MESHLET_SIZE ) );
|
|
311
|
+
|
|
312
|
+
If( lodTriangle.lessThan( lodNumTriangles ), () => {
|
|
313
|
+
|
|
314
|
+
const megaTriangleIndex = lodTriangleStart.add( lodTriangle );
|
|
315
|
+
const indexOffset = megaTriangleIndex.mul( 3 );
|
|
316
|
+
|
|
317
|
+
const corners = [ indexBuffer.element( indexOffset ), indexBuffer.element( indexOffset.add( 1 ) ), indexBuffer.element( indexOffset.add( 2 ) ) ];
|
|
318
|
+
|
|
319
|
+
let p0, p1, p2;
|
|
320
|
+
|
|
321
|
+
if ( deformed === true ) {
|
|
322
|
+
|
|
323
|
+
const deformedPositions = deformCorners( corners, instId ).get( 'positions' );
|
|
324
|
+
const mvp = projScreenMatrix.mul( objectWorld.element( instId ) ).toVar();
|
|
325
|
+
|
|
326
|
+
p0 = mvp.mul( vec4( deformedPositions.element( 0 ), 1.0 ) );
|
|
327
|
+
p1 = mvp.mul( vec4( deformedPositions.element( 1 ), 1.0 ) );
|
|
328
|
+
p2 = mvp.mul( vec4( deformedPositions.element( 2 ), 1.0 ) );
|
|
329
|
+
|
|
330
|
+
} else {
|
|
331
|
+
|
|
332
|
+
const mvp = instanceMvp.element( instId );
|
|
333
|
+
|
|
334
|
+
p0 = mvp.mul( vec4( position( corners[ 0 ] ), 1.0 ) );
|
|
335
|
+
p1 = mvp.mul( vec4( position( corners[ 1 ] ), 1.0 ) );
|
|
336
|
+
p2 = mvp.mul( vec4( position( corners[ 2 ] ), 1.0 ) );
|
|
337
|
+
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const enqueueHardware = () => {
|
|
341
|
+
|
|
342
|
+
const hwCount = atomicAdd( hwQueueAtomic.element( 0 ), 1 );
|
|
343
|
+
|
|
344
|
+
If( hwCount.lessThan( MAX_HW_TRIANGLES ), () => {
|
|
345
|
+
|
|
346
|
+
const slot = hwCount.mul( 2 ).add( 1 );
|
|
347
|
+
|
|
348
|
+
atomicStore( hwQueueAtomic.element( slot ), instId );
|
|
349
|
+
atomicStore( hwQueueAtomic.element( slot.add( 1 ) ), megaTriangleIndex );
|
|
350
|
+
|
|
351
|
+
} );
|
|
352
|
+
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// triangles crossing the near plane need clipping, so they go to the hardware rasterizer
|
|
356
|
+
|
|
357
|
+
If( p0.w.greaterThan( 0.0 ).and( p1.w.greaterThan( 0.0 ) ).and( p2.w.greaterThan( 0.0 ) ), () => {
|
|
358
|
+
|
|
359
|
+
const ndc0 = p0.xyz.div( p0.w );
|
|
360
|
+
const ndc1 = p1.xyz.div( p1.w );
|
|
361
|
+
const ndc2 = p2.xyz.div( p2.w );
|
|
362
|
+
|
|
363
|
+
// back-face culling
|
|
364
|
+
|
|
365
|
+
If( edgeFunction( ndc0, ndc1, ndc2 ).greaterThan( 0.0 ), () => {
|
|
366
|
+
|
|
367
|
+
const ndcMinX = min( ndc0.x, min( ndc1.x, ndc2.x ) );
|
|
368
|
+
const ndcMaxX = max( ndc0.x, max( ndc1.x, ndc2.x ) );
|
|
369
|
+
const ndcMinY = min( ndc0.y, min( ndc1.y, ndc2.y ) );
|
|
370
|
+
const ndcMaxY = max( ndc0.y, max( ndc1.y, ndc2.y ) );
|
|
371
|
+
|
|
372
|
+
If( ndcMaxX.greaterThan( - 1.0 ).and( ndcMinX.lessThan( 1.0 ) ).and( ndcMaxY.greaterThan( - 1.0 ) ).and( ndcMinY.lessThan( 1.0 ) ), () => {
|
|
373
|
+
|
|
374
|
+
const w = viewSize.x;
|
|
375
|
+
const h = viewSize.y;
|
|
376
|
+
|
|
377
|
+
const s0 = ndc0.xy.add( 1.0 ).mul( 0.5 ).mul( vec2( w, h ) );
|
|
378
|
+
const s1 = ndc1.xy.add( 1.0 ).mul( 0.5 ).mul( vec2( w, h ) );
|
|
379
|
+
const s2 = ndc2.xy.add( 1.0 ).mul( 0.5 ).mul( vec2( w, h ) );
|
|
380
|
+
|
|
381
|
+
const startX = int( floor( max( 0.0, min( s0.x, min( s1.x, s2.x ) ) ) ) );
|
|
382
|
+
const endX = int( floor( min( w.sub( 1.0 ), max( s0.x, max( s1.x, s2.x ) ) ) ) );
|
|
383
|
+
const startY = int( floor( max( 0.0, min( s0.y, min( s1.y, s2.y ) ) ) ) );
|
|
384
|
+
const endY = int( floor( min( h.sub( 1.0 ), max( s0.y, max( s1.y, s2.y ) ) ) ) );
|
|
385
|
+
|
|
386
|
+
// only small triangles are rasterized in software, the others go to the hardware queue
|
|
387
|
+
|
|
388
|
+
If( startX.lessThanEqual( endX ).and( startY.lessThanEqual( endY ) ).and( endX.sub( startX ).lessThanEqual( maxRasterSize ) ).and( endY.sub( startY ).lessThanEqual( maxRasterSize ) ), () => {
|
|
389
|
+
|
|
390
|
+
const area = edgeFunction( s0, s1, s2 );
|
|
391
|
+
|
|
392
|
+
const stepX_w0 = s1.y.sub( s2.y );
|
|
393
|
+
const stepY_w0 = s2.x.sub( s1.x );
|
|
394
|
+
const stepX_w1 = s2.y.sub( s0.y );
|
|
395
|
+
const stepY_w1 = s0.x.sub( s2.x );
|
|
396
|
+
const stepX_w2 = s0.y.sub( s1.y );
|
|
397
|
+
const stepY_w2 = s1.x.sub( s0.x );
|
|
398
|
+
|
|
399
|
+
// top-left rule for watertight edges
|
|
400
|
+
|
|
401
|
+
const bias0 = stepX_w0.lessThan( 0.0 ).or( stepX_w0.equal( 0.0 ).and( stepY_w0.greaterThan( 0.0 ) ) ).select( 0.0, - 1e-5 );
|
|
402
|
+
const bias1 = stepX_w1.lessThan( 0.0 ).or( stepX_w1.equal( 0.0 ).and( stepY_w1.greaterThan( 0.0 ) ) ).select( 0.0, - 1e-5 );
|
|
403
|
+
const bias2 = stepX_w2.lessThan( 0.0 ).or( stepX_w2.equal( 0.0 ).and( stepY_w2.greaterThan( 0.0 ) ) ).select( 0.0, - 1e-5 );
|
|
404
|
+
|
|
405
|
+
const pStart = vec2( float( startX ).add( 0.5 ), float( startY ).add( 0.5 ) );
|
|
406
|
+
|
|
407
|
+
const row_w0 = edgeFunction( s1, s2, pStart ).add( bias0 ).toVar();
|
|
408
|
+
const row_w1 = edgeFunction( s2, s0, pStart ).add( bias1 ).toVar();
|
|
409
|
+
const row_w2 = edgeFunction( s0, s1, pStart ).add( bias2 ).toVar();
|
|
410
|
+
|
|
411
|
+
// incremental depth
|
|
412
|
+
|
|
413
|
+
const row_z = row_w0.div( area ).mul( ndc0.z ).add( row_w1.div( area ).mul( ndc1.z ) ).add( row_w2.div( area ).mul( ndc2.z ) ).toVar();
|
|
414
|
+
|
|
415
|
+
const stepX_z = stepX_w0.div( area ).mul( ndc0.z ).add( stepX_w1.div( area ).mul( ndc1.z ) ).add( stepX_w2.div( area ).mul( ndc2.z ) );
|
|
416
|
+
const stepY_z = stepY_w0.div( area ).mul( ndc0.z ).add( stepY_w1.div( area ).mul( ndc1.z ) ).add( stepY_w2.div( area ).mul( ndc2.z ) );
|
|
417
|
+
|
|
418
|
+
Loop( { name: 'y', type: 'int', start: startY, end: endY, condition: '<=' }, ( { y } ) => {
|
|
419
|
+
|
|
420
|
+
const w0 = row_w0.toVar();
|
|
421
|
+
const w1 = row_w1.toVar();
|
|
422
|
+
const w2 = row_w2.toVar();
|
|
423
|
+
const z = row_z.toVar();
|
|
424
|
+
|
|
425
|
+
Loop( { name: 'x', type: 'int', start: startX, end: endX, condition: '<=' }, ( { x } ) => {
|
|
426
|
+
|
|
427
|
+
If( w0.greaterThanEqual( 0.0 ).and( w1.greaterThanEqual( 0.0 ) ).and( w2.greaterThanEqual( 0.0 ) ).and( z.greaterThanEqual( 0.0 ) ).and( z.lessThanEqual( 1.0 ) ), () => {
|
|
428
|
+
|
|
429
|
+
// depth with a fourth-root distribution, packed above each payload
|
|
430
|
+
|
|
431
|
+
const zEncoded = sqrt( sqrt( float( 1.0 ).sub( z ) ) );
|
|
432
|
+
const depthTri = uint( zEncoded.mul( DEPTH_TRI_MAX ) );
|
|
433
|
+
const depthInst = uint( zEncoded.mul( DEPTH_INST_MAX ) );
|
|
434
|
+
|
|
435
|
+
const pixelIndex = uint( y ).mul( uint( w ) ).add( uint( x ) );
|
|
436
|
+
|
|
437
|
+
// the depth occupies the high bits, so atomicMax resolves the depth test and the payload together
|
|
438
|
+
|
|
439
|
+
If( depthTri.greaterThanEqual( atomicLoad( screenTriAtomic.element( pixelIndex ) ).shiftRight( TRIANGLE_INDEX_BITS ) ), () => {
|
|
440
|
+
|
|
441
|
+
atomicMax( screenTriAtomic.element( pixelIndex ), depthTri.shiftLeft( TRIANGLE_INDEX_BITS ).bitOr( megaTriangleIndex.sub( triangleBase ).bitAnd( TRIANGLE_INDEX_MASK ) ) );
|
|
442
|
+
atomicMax( screenInstAtomic.element( pixelIndex ), depthInst.shiftLeft( INSTANCE_INDEX_BITS ).bitOr( instanceOffset.add( instId ) ) );
|
|
443
|
+
|
|
444
|
+
} );
|
|
445
|
+
|
|
446
|
+
} );
|
|
447
|
+
|
|
448
|
+
w0.addAssign( stepX_w0 );
|
|
449
|
+
w1.addAssign( stepX_w1 );
|
|
450
|
+
w2.addAssign( stepX_w2 );
|
|
451
|
+
z.addAssign( stepX_z );
|
|
452
|
+
|
|
453
|
+
} );
|
|
454
|
+
|
|
455
|
+
row_w0.addAssign( stepY_w0 );
|
|
456
|
+
row_w1.addAssign( stepY_w1 );
|
|
457
|
+
row_w2.addAssign( stepY_w2 );
|
|
458
|
+
row_z.addAssign( stepY_z );
|
|
459
|
+
|
|
460
|
+
} );
|
|
461
|
+
|
|
462
|
+
} ).ElseIf( startX.lessThanEqual( endX ).and( startY.lessThanEqual( endY ) ), enqueueHardware );
|
|
463
|
+
|
|
464
|
+
} );
|
|
465
|
+
|
|
466
|
+
} );
|
|
467
|
+
|
|
468
|
+
} ).ElseIf( p0.w.greaterThan( 0.0 ).or( p1.w.greaterThan( 0.0 ) ).or( p2.w.greaterThan( 0.0 ) ), enqueueHardware );
|
|
469
|
+
|
|
470
|
+
} );
|
|
471
|
+
|
|
472
|
+
} );
|
|
473
|
+
|
|
474
|
+
} )().compute( dispatchAttribute ).setName( 'VisibilityBufferDrawingPipeline Rasterize' );
|
|
475
|
+
|
|
476
|
+
// indirect draw arguments of the hardware path
|
|
477
|
+
|
|
478
|
+
const computeHWArgs = Fn( () => {
|
|
479
|
+
|
|
480
|
+
hwDrawBuffer.element( 0 ).assign( min( atomicLoad( hwQueueAtomic.element( 0 ) ), uint( MAX_HW_TRIANGLES ) ).mul( 3 ) );
|
|
481
|
+
hwDrawBuffer.element( 1 ).assign( uint( 1 ) );
|
|
482
|
+
hwDrawBuffer.element( 2 ).assign( uint( 0 ) );
|
|
483
|
+
hwDrawBuffer.element( 3 ).assign( uint( 0 ) );
|
|
484
|
+
|
|
485
|
+
} )().compute( 1 ).setName( 'VisibilityBufferDrawingPipeline HW Args' );
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
this.computeNodes.push( computeHWReset, computeDispatch, computeRasterize, computeHWArgs );
|
|
489
|
+
|
|
490
|
+
// hardware path — the large triangles queued by the software rasterizer
|
|
491
|
+
|
|
492
|
+
const slot = vertexIndex.div( 3 ).mul( 2 ).add( 1 );
|
|
493
|
+
|
|
494
|
+
this.hwMesh = this.createPulledMesh( hwDrawAttribute, {
|
|
495
|
+
instance: hwQueueRead.element( slot ),
|
|
496
|
+
triangle: hwQueueRead.element( slot.add( 1 ) ),
|
|
497
|
+
corner: vertexIndex.mod( 3 )
|
|
498
|
+
}, shared );
|
|
499
|
+
|
|
500
|
+
// resolve — shades the visibility buffer through the material graph
|
|
501
|
+
|
|
502
|
+
// the resolve draws the bounding box of each object, so every fragment is only shaded by the box of
|
|
503
|
+
// the object visible in it — a fullscreen resolve would run the material for the whole screen per batch.
|
|
504
|
+
// the back faces cover the object even if the camera is inside its box. the winding of the box is
|
|
505
|
+
// reversed instead of using BackSide, which would negate the normals of the material.
|
|
506
|
+
|
|
507
|
+
if ( _resolveGeometry === null ) {
|
|
508
|
+
|
|
509
|
+
_resolveGeometry = new BoxGeometry();
|
|
510
|
+
|
|
511
|
+
const index = _resolveGeometry.index;
|
|
512
|
+
|
|
513
|
+
for ( let i = 0; i < index.count; i += 3 ) {
|
|
514
|
+
|
|
515
|
+
const b = index.getX( i + 1 );
|
|
516
|
+
|
|
517
|
+
index.setX( i + 1, index.getX( i + 2 ) );
|
|
518
|
+
index.setX( i + 2, b );
|
|
519
|
+
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const vResolveInstance = varyingProperty( 'uint', 'vVisibilityBufferInstance' );
|
|
525
|
+
|
|
526
|
+
const boxMin = uniform( clusters.boundingBox.min.clone() );
|
|
527
|
+
const boxSize = uniform( clusters.boundingBox.max.clone().sub( clusters.boundingBox.min ) );
|
|
528
|
+
|
|
529
|
+
const resolveVertex = Fn( () => {
|
|
530
|
+
|
|
531
|
+
vResolveInstance.assign( instanceIndex );
|
|
532
|
+
|
|
533
|
+
if ( deformed === true ) {
|
|
534
|
+
|
|
535
|
+
// the box of the deformed positions: the world matrix of the culling approximates the deformation, the box
|
|
536
|
+
// grows by the margin of the deformation. deformations which can't be bounded are resolved fullscreen
|
|
537
|
+
|
|
538
|
+
const bounds = this.culling.instanceBounds.element( this.rangeNodes.dataOffset.add( instanceIndex ) );
|
|
539
|
+
const margin = bounds.x.div( bounds.w.abs() );
|
|
540
|
+
const boxPosition = positionGeometry.add( 0.5 ).mul( boxSize.add( margin.mul( 2 ) ) ).add( boxMin.sub( margin ) );
|
|
541
|
+
const clipPosition = cameraProjectionMatrix.mul( cameraViewMatrix ).mul( instanceWorld.element( instanceIndex ) ).mul( vec4( boxPosition, 1.0 ) );
|
|
542
|
+
|
|
543
|
+
return select( this.unbounded.greaterThan( 0 ), vec4( 0 ), clipPosition );
|
|
544
|
+
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const boxPosition = positionGeometry.add( 0.5 ).mul( boxSize ).add( boxMin );
|
|
548
|
+
|
|
549
|
+
return cameraProjectionMatrix.mul( cameraViewMatrix ).mul( instanceWorld.element( instanceIndex ) ).mul( vec4( boxPosition, 1.0 ) );
|
|
550
|
+
|
|
551
|
+
} )();
|
|
552
|
+
|
|
553
|
+
// the rasterizer addresses the screen bottom-up, screenCoordinate is top-down
|
|
554
|
+
|
|
555
|
+
const flippedY = viewSize.y.sub( screenCoordinate.y );
|
|
556
|
+
const pixelIndex = uint( flippedY ).mul( uint( viewSize.x ) ).add( uint( screenCoordinate.x ) );
|
|
557
|
+
|
|
558
|
+
const packedTri = screenTriRead.element( pixelIndex );
|
|
559
|
+
const megaTriangleIndex = packedTri.bitAnd( TRIANGLE_INDEX_MASK ).add( triangleBase );
|
|
560
|
+
// the fragment is shaded if the object visible in it is the object of the box
|
|
561
|
+
|
|
562
|
+
const globalInstance = screenInstRead.element( pixelIndex ).bitAnd( INSTANCE_INDEX_MASK );
|
|
563
|
+
const ownedByBox = globalInstance.equal( instanceOffset.add( vResolveInstance ) );
|
|
564
|
+
const instId = globalInstance.sub( instanceOffset );
|
|
565
|
+
|
|
566
|
+
// the fullscreen resolve shades the fragments of all objects of the batch
|
|
567
|
+
|
|
568
|
+
this.resolveCount = uniform( 0, 'uint' );
|
|
569
|
+
|
|
570
|
+
const ownedByBatch = instId.lessThan( this.resolveCount );
|
|
571
|
+
|
|
572
|
+
const i0 = indexBuffer.element( megaTriangleIndex.mul( 3 ) );
|
|
573
|
+
const i1 = indexBuffer.element( megaTriangleIndex.mul( 3 ).add( 1 ) );
|
|
574
|
+
const i2 = indexBuffer.element( megaTriangleIndex.mul( 3 ).add( 2 ) );
|
|
575
|
+
|
|
576
|
+
let matrixWorld, l0, l1, l2, n0, n1, n2;
|
|
577
|
+
|
|
578
|
+
if ( deformed === true ) {
|
|
579
|
+
|
|
580
|
+
const deformedTriangle = deformCorners( [ i0, i1, i2 ], instId );
|
|
581
|
+
const deformedPositions = deformedTriangle.get( 'positions' );
|
|
582
|
+
const deformedNormals = deformedTriangle.get( 'normals' );
|
|
583
|
+
|
|
584
|
+
matrixWorld = objectWorld.element( instId );
|
|
585
|
+
|
|
586
|
+
l0 = deformedPositions.element( 0 );
|
|
587
|
+
l1 = deformedPositions.element( 1 );
|
|
588
|
+
l2 = deformedPositions.element( 2 );
|
|
589
|
+
|
|
590
|
+
n0 = deformedNormals.element( 0 );
|
|
591
|
+
n1 = deformedNormals.element( 1 );
|
|
592
|
+
n2 = deformedNormals.element( 2 );
|
|
593
|
+
|
|
594
|
+
} else {
|
|
595
|
+
|
|
596
|
+
matrixWorld = instanceWorld.element( instId );
|
|
597
|
+
|
|
598
|
+
l0 = position( i0 );
|
|
599
|
+
l1 = position( i1 );
|
|
600
|
+
l2 = position( i2 );
|
|
601
|
+
|
|
602
|
+
n0 = normal( i0 );
|
|
603
|
+
n1 = normal( i1 );
|
|
604
|
+
n2 = normal( i2 );
|
|
605
|
+
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const p0 = projScreenMatrix.mul( matrixWorld ).mul( vec4( l0, 1.0 ) );
|
|
609
|
+
const p1 = projScreenMatrix.mul( matrixWorld ).mul( vec4( l1, 1.0 ) );
|
|
610
|
+
const p2 = projScreenMatrix.mul( matrixWorld ).mul( vec4( l2, 1.0 ) );
|
|
611
|
+
|
|
612
|
+
const screenScale = vec2( viewSize.x, viewSize.y );
|
|
613
|
+
const s0 = p0.xy.div( p0.w ).add( 1.0 ).mul( 0.5 ).mul( screenScale );
|
|
614
|
+
const s1 = p1.xy.div( p1.w ).add( 1.0 ).mul( 0.5 ).mul( screenScale );
|
|
615
|
+
const s2 = p2.xy.div( p2.w ).add( 1.0 ).mul( 0.5 ).mul( screenScale );
|
|
616
|
+
|
|
617
|
+
const p = vec2( screenCoordinate.x, flippedY );
|
|
618
|
+
|
|
619
|
+
// perspective correct barycentrics from the edge functions weighted by the inverse clip w
|
|
620
|
+
|
|
621
|
+
const e0 = edgeFunction( s1, s2, p );
|
|
622
|
+
const e1 = edgeFunction( s2, s0, p );
|
|
623
|
+
const e2 = edgeFunction( s0, s1, p );
|
|
624
|
+
|
|
625
|
+
const q0 = float( 1.0 ).div( p0.w );
|
|
626
|
+
const q1 = float( 1.0 ).div( p1.w );
|
|
627
|
+
const q2 = float( 1.0 ).div( p2.w );
|
|
628
|
+
|
|
629
|
+
const sum = e0.mul( q0 ).add( e1.mul( q1 ) ).add( e2.mul( q2 ) );
|
|
630
|
+
const safeSum = sum.equal( 0.0 ).select( 1.0, sum );
|
|
631
|
+
|
|
632
|
+
const interpolate = ( a0, a1, a2 ) => a0.mul( e0.mul( q0 ) ).add( a1.mul( e1.mul( q1 ) ) ).add( a2.mul( e2.mul( q2 ) ) ).div( safeSum );
|
|
633
|
+
|
|
634
|
+
// analytic screen-space derivatives, neighbor fragments can belong to other triangles —
|
|
635
|
+
// the derivatives of the edge functions along the screen x and y axes, with the same
|
|
636
|
+
// orientation as the hardware derivatives
|
|
637
|
+
|
|
638
|
+
const dx = ( a0, a1, a2, value ) => derivative( a0, a1, a2, value, s2.y.sub( s1.y ), s0.y.sub( s2.y ), s1.y.sub( s0.y ) );
|
|
639
|
+
const dy = ( a0, a1, a2, value ) => derivative( a0, a1, a2, value, s1.x.sub( s2.x ), s2.x.sub( s0.x ), s0.x.sub( s1.x ) );
|
|
640
|
+
|
|
641
|
+
const derivative = ( a0, a1, a2, value, d0, d1, d2 ) => d0.mul( q0 ).mul( a0.sub( value ) ).add( d1.mul( q1 ).mul( a1.sub( value ) ) ).add( d2.mul( q2 ).mul( a2.sub( value ) ) ).div( safeSum );
|
|
642
|
+
|
|
643
|
+
const uv0 = vertexUv( i0 );
|
|
644
|
+
const uv1 = vertexUv( i1 );
|
|
645
|
+
const uv2 = vertexUv( i2 );
|
|
646
|
+
|
|
647
|
+
const uv = interpolate( uv0, uv1, uv2 );
|
|
648
|
+
const uvDx = dx( uv0, uv1, uv2, uv );
|
|
649
|
+
const uvDy = dy( uv0, uv1, uv2, uv );
|
|
650
|
+
|
|
651
|
+
const localPosition = interpolate( l0, l1, l2 );
|
|
652
|
+
const localNormal = interpolate( n0, n1, n2 );
|
|
653
|
+
const worldPosition = matrixWorld.mul( vec4( localPosition, 1.0 ) ).xyz;
|
|
654
|
+
const worldNormal = matrixWorld.mul( vec4( localNormal, 0.0 ) ).xyz;
|
|
655
|
+
|
|
656
|
+
// tangent frame of normal maps from the analytic derivatives, see TangentUtils
|
|
657
|
+
|
|
658
|
+
const modelView = cameraViewMatrix.mul( matrixWorld );
|
|
659
|
+
|
|
660
|
+
const v0 = modelView.mul( vec4( l0, 1.0 ) ).xyz;
|
|
661
|
+
const v1 = modelView.mul( vec4( l1, 1.0 ) ).xyz;
|
|
662
|
+
const v2 = modelView.mul( vec4( l2, 1.0 ) ).xyz;
|
|
663
|
+
|
|
664
|
+
const viewPosition = interpolate( v0, v1, v2 );
|
|
665
|
+
const viewNormal = cameraViewMatrix.mul( vec4( worldNormal, 0.0 ) ).xyz.normalize();
|
|
666
|
+
|
|
667
|
+
const q1perp = dy( v0, v1, v2, viewPosition ).cross( viewNormal );
|
|
668
|
+
const q0perp = viewNormal.cross( dx( v0, v1, v2, viewPosition ) );
|
|
669
|
+
|
|
670
|
+
const tangent = q1perp.mul( uvDx.x ).add( q0perp.mul( uvDy.x ) );
|
|
671
|
+
const bitangent = q1perp.mul( uvDx.y ).add( q0perp.mul( uvDy.y ) );
|
|
672
|
+
|
|
673
|
+
const det = tangent.dot( tangent ).max( bitangent.dot( bitangent ) );
|
|
674
|
+
const frameScale = det.equal( 0.0 ).select( 0.0, det.inverseSqrt() );
|
|
675
|
+
|
|
676
|
+
// depth from the high bits with the fourth-root distribution reversed, zero means not covered
|
|
677
|
+
|
|
678
|
+
const depthTri = packedTri.shiftRight( TRIANGLE_INDEX_BITS );
|
|
679
|
+
const depthEncoded = float( depthTri ).div( DEPTH_TRI_MAX );
|
|
680
|
+
const depthSquared = depthEncoded.mul( depthEncoded );
|
|
681
|
+
|
|
682
|
+
const createResolveMaterial = ( vertexNode, owned ) => {
|
|
683
|
+
|
|
684
|
+
let resolveMaterial;
|
|
685
|
+
|
|
686
|
+
if ( debug === true ) {
|
|
687
|
+
|
|
688
|
+
resolveMaterial = createDebugMaterial( megaTriangleIndex.div( MESHLET_SIZE ), instId );
|
|
689
|
+
|
|
690
|
+
} else {
|
|
691
|
+
|
|
692
|
+
resolveMaterial = createDrawMaterial( material, renderer );
|
|
693
|
+
resolveMaterial.positionNode = null;
|
|
694
|
+
resolveMaterial.receivedShadowPositionNode = worldPosition;
|
|
695
|
+
resolveMaterial.contextNode = createSurfaceContext( {
|
|
696
|
+
localPosition,
|
|
697
|
+
localNormal,
|
|
698
|
+
worldPosition,
|
|
699
|
+
worldNormal,
|
|
700
|
+
uv,
|
|
701
|
+
uvGradient: [ uvDx, uvDy ],
|
|
702
|
+
tangentFrame: [ tangent.mul( frameScale ), bitangent.mul( frameScale ) ],
|
|
703
|
+
matrixWorld,
|
|
704
|
+
attribute: ( name ) => {
|
|
705
|
+
|
|
706
|
+
return hasAttribute( name ) ? interpolate( attribute( name, i0 ), attribute( name, i1 ), attribute( name, i2 ) ) : null;
|
|
707
|
+
|
|
708
|
+
}
|
|
709
|
+
} );
|
|
710
|
+
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
resolveMaterial.vertexNode = vertexNode;
|
|
714
|
+
resolveMaterial.depthNode = float( 1.0 ).sub( depthSquared.mul( depthSquared ) );
|
|
715
|
+
resolveMaterial.maskNode = depthTri.notEqual( uint( 0 ) ).and( owned );
|
|
716
|
+
|
|
717
|
+
return resolveMaterial;
|
|
718
|
+
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
this.resolveMesh = new Mesh( _resolveGeometry, createResolveMaterial( resolveVertex, ownedByBox ) );
|
|
722
|
+
this.resolveMesh.frustumCulled = false;
|
|
723
|
+
this.resolveMesh.receiveShadow = receiveShadow;
|
|
724
|
+
|
|
725
|
+
this.meshes.push( this.resolveMesh, this.hwMesh );
|
|
726
|
+
|
|
727
|
+
// deformations which can't be bounded are resolved by one fullscreen triangle instead of the boxes
|
|
728
|
+
|
|
729
|
+
if ( deformed === true ) {
|
|
730
|
+
|
|
731
|
+
if ( _fullscreenGeometry === null ) {
|
|
732
|
+
|
|
733
|
+
_fullscreenGeometry = new BufferGeometry();
|
|
734
|
+
_fullscreenGeometry.setAttribute( 'position', new Float32BufferAttribute( [ - 1, - 1, 0, 3, - 1, 0, - 1, 3, 0 ], 3 ) );
|
|
735
|
+
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const fullscreenVertex = select( this.unbounded.greaterThan( 0 ), vec4( positionGeometry.xy, 0.0, 1.0 ), vec4( 0 ) );
|
|
739
|
+
|
|
740
|
+
this.fullscreenMesh = new Mesh( _fullscreenGeometry, createResolveMaterial( fullscreenVertex, ownedByBatch ) );
|
|
741
|
+
this.fullscreenMesh.frustumCulled = false;
|
|
742
|
+
this.fullscreenMesh.receiveShadow = receiveShadow;
|
|
743
|
+
|
|
744
|
+
this.meshes.push( this.fullscreenMesh );
|
|
745
|
+
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
update( ...parameters ) {
|
|
751
|
+
|
|
752
|
+
super.update( ...parameters );
|
|
753
|
+
|
|
754
|
+
// Compaction can move this geometry without rebuilding its batch.
|
|
755
|
+
|
|
756
|
+
this.triangleBase.value = this.pool.add( this.clusters );
|
|
757
|
+
|
|
758
|
+
const pipeline = parameters[ 1 ];
|
|
759
|
+
|
|
760
|
+
this.maxRasterSize.value = pipeline.maxRasterSize;
|
|
761
|
+
this.resolveCount.value = this.count;
|
|
762
|
+
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* A meshlet drawing pipeline with a hybrid rasterizer. Like {@link MeshletDrawingPipeline}, compute shaders select the
|
|
769
|
+
* level of detail and cull objects and clusters, but the visible clusters are rasterized into a visibility
|
|
770
|
+
* buffer: small triangles in software by a compute shader, large triangles by the hardware rasterizer. A
|
|
771
|
+
* resolve pass shades the visibility buffer with the material of the meshes: its node graph is evaluated on
|
|
772
|
+
* the reconstructed surface (position, normal, model matrices and the attributes of the geometry) with
|
|
773
|
+
* analytic derivatives, so custom nodes, lights, shadows and the environment work as usual and the meshes
|
|
774
|
+
* depth test against other objects.
|
|
775
|
+
*
|
|
776
|
+
* The visibility buffer stores the triangle in 16 bits, so only the levels of detail whose triangles fit
|
|
777
|
+
* into this range are used. Geometries whose most detailed level doesn't fit are drawn by the hardware
|
|
778
|
+
* pipeline of {@link MeshletDrawingPipeline}. The resolve only writes the color, so render calls with MRT, like the
|
|
779
|
+
* velocity of TRAA, draw all clusters with the hardware pipeline. The position node of the material is evaluated
|
|
780
|
+
* per corner of the triangles by the software rasterizer and by the resolve.
|
|
781
|
+
*
|
|
782
|
+
* ```js
|
|
783
|
+
* renderer.drawingPipeline = new VisibilityBufferDrawingPipeline();
|
|
784
|
+
* ```
|
|
785
|
+
*
|
|
786
|
+
* This class is experimental and its interface might change.
|
|
787
|
+
*
|
|
788
|
+
* @augments MeshletDrawingPipeline
|
|
789
|
+
*/
|
|
790
|
+
class VisibilityBufferDrawingPipeline extends MeshletDrawingPipeline {
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Constructs a new visibility buffer drawing pipeline.
|
|
794
|
+
*
|
|
795
|
+
* @param {Object} [parameters] - The configuration parameter.
|
|
796
|
+
* @param {number} [parameters.lodThreshold=1] - The projected error in pixels below which a simpler level of detail is selected.
|
|
797
|
+
* @param {number} [parameters.shadowLodThreshold=1] - The projected error in shadow map texels below which a simpler level of detail is selected for shadow casters.
|
|
798
|
+
* @param {number} [parameters.maxRasterSize=8] - The maximum screen-space size in pixels of triangles rasterized in software.
|
|
799
|
+
* @param {boolean} [parameters.debug=false] - Whether the clusters should be shown with a flat color each instead of the material.
|
|
800
|
+
* @param {boolean} [parameters.occlusionCulling=true] - Whether the clusters hidden by other clusters should be culled.
|
|
801
|
+
*/
|
|
802
|
+
constructor( { lodThreshold, shadowLodThreshold, maxRasterSize = 8, debug, occlusionCulling } = {} ) {
|
|
803
|
+
|
|
804
|
+
super( { lodThreshold, shadowLodThreshold, debug, occlusionCulling } );
|
|
805
|
+
|
|
806
|
+
this._hardware = false;
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* The maximum screen-space size in pixels of triangles rasterized in software.
|
|
810
|
+
* Larger triangles are drawn by the hardware rasterizer. The software rasterizer
|
|
811
|
+
* loops over the pixels of a triangle in one thread, so it only pays off for small
|
|
812
|
+
* triangles.
|
|
813
|
+
*
|
|
814
|
+
* @type {number}
|
|
815
|
+
* @default 8
|
|
816
|
+
*/
|
|
817
|
+
this.maxRasterSize = maxRasterSize;
|
|
818
|
+
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* The maximum number of objects per render list, limited by the instance index of the visibility buffer.
|
|
823
|
+
*
|
|
824
|
+
* @type {number}
|
|
825
|
+
* @readonly
|
|
826
|
+
*/
|
|
827
|
+
get maxInstances() {
|
|
828
|
+
|
|
829
|
+
return MAX_INSTANCES;
|
|
830
|
+
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
updateView( record, width, height ) {
|
|
834
|
+
|
|
835
|
+
// shadow passes are drawn by the hardware rasterizer of the base pipeline
|
|
836
|
+
|
|
837
|
+
if ( this._shadowPass === true ) return null;
|
|
838
|
+
|
|
839
|
+
// the resolve only writes the color and the software rasterizer doesn't apply the deformation of the render call:
|
|
840
|
+
// render calls with MRT or deformed positions draw all clusters with the hardware rasterizer
|
|
841
|
+
|
|
842
|
+
const hardware = this.renderer.getMRT() !== null || this._boundsNode !== null;
|
|
843
|
+
|
|
844
|
+
if ( record.view !== null && record.view.hardware !== hardware ) {
|
|
845
|
+
|
|
846
|
+
record.view.dispose();
|
|
847
|
+
record.view = null;
|
|
848
|
+
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
this._hardware = hardware;
|
|
852
|
+
|
|
853
|
+
return super.updateView( record, width, height );
|
|
854
|
+
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
_isSupportedMaterial( material ) {
|
|
858
|
+
|
|
859
|
+
// the software rasterizer doesn't discard fragments
|
|
860
|
+
|
|
861
|
+
// the resolve doesn't write the MRT outputs of the material
|
|
862
|
+
|
|
863
|
+
if ( material.isNodeMaterial === true && ( ( material.maskNode !== null && material.maskNode !== undefined ) || ( material.mrtNode !== null && material.mrtNode !== undefined ) ) ) return false;
|
|
864
|
+
|
|
865
|
+
return super._isSupportedMaterial( material );
|
|
866
|
+
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
_canMergeLevels() {
|
|
870
|
+
|
|
871
|
+
// the resolve shades a batch with one material, the levels of LOD objects are drawn as separate objects
|
|
872
|
+
|
|
873
|
+
return false;
|
|
874
|
+
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
_usesDepthPrepass() {
|
|
878
|
+
|
|
879
|
+
// the resolve shades every pixel once, the large triangles of the hardware path are drawn directly
|
|
880
|
+
|
|
881
|
+
return false;
|
|
882
|
+
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
createView( width, height, occlusion ) {
|
|
886
|
+
|
|
887
|
+
if ( this._hardware === true ) {
|
|
888
|
+
|
|
889
|
+
const view = super.createView( width, height, occlusion );
|
|
890
|
+
|
|
891
|
+
if ( view !== null ) view.hardware = true;
|
|
892
|
+
|
|
893
|
+
return view;
|
|
894
|
+
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
const view = createView( width, height );
|
|
898
|
+
view.hardware = false;
|
|
899
|
+
const disposeBuffers = view.dispose;
|
|
900
|
+
|
|
901
|
+
view.occlusion = occlusion === true ? createOcclusion( width, height ) : null;
|
|
902
|
+
view.dispose = () => {
|
|
903
|
+
|
|
904
|
+
disposeBuffers();
|
|
905
|
+
|
|
906
|
+
if ( view.occlusion !== null ) view.occlusion.dispose();
|
|
907
|
+
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
return view;
|
|
911
|
+
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* The batches of the software rasterizer index the triangles of one geometry, each geometry has its own batches.
|
|
916
|
+
*
|
|
917
|
+
* @param {Object} clusters - The cluster data of the geometry.
|
|
918
|
+
* @return {Object} The key.
|
|
919
|
+
*/
|
|
920
|
+
_getBatchKey( clusters ) {
|
|
921
|
+
|
|
922
|
+
return clusters;
|
|
923
|
+
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
createBatch( entry, capacity, view, culling ) {
|
|
927
|
+
|
|
928
|
+
// the levels of detail whose triangles fit into the triangle index of the visibility buffer,
|
|
929
|
+
// the levels are ordered from the most detailed one
|
|
930
|
+
|
|
931
|
+
// the instances of instanced meshes are drawn as objects, their world matrices are computed on the GPU. the resolve
|
|
932
|
+
// doesn't read the instanced attributes of the geometry and the instance colors, these instanced meshes are drawn by the hardware rasterizer
|
|
933
|
+
|
|
934
|
+
// the software rasterizer doesn't evaluate the alpha of alpha-tested materials
|
|
935
|
+
|
|
936
|
+
if ( this._shadowPass === true || ( entry.instanced === true && ( entry.clusters.instancedAttributes.length > 0 || entry.instanceColor === true ) ) || entry.material.alphaTest > 0 || view === null || view.hardware === true ) return super.createBatch( entry, capacity, view, culling );
|
|
937
|
+
|
|
938
|
+
const lodTriangleEnds = entry.clusters.lodTriangleEnds;
|
|
939
|
+
|
|
940
|
+
let lodCount = 0;
|
|
941
|
+
|
|
942
|
+
while ( lodCount < lodTriangleEnds.length && lodTriangleEnds[ lodCount ] <= MAX_TRIANGLES ) lodCount ++;
|
|
943
|
+
|
|
944
|
+
if ( lodCount === 0 ) return super.createBatch( entry, capacity, view, culling );
|
|
945
|
+
|
|
946
|
+
const source = entry.source !== null ? entry.source.batch : null;
|
|
947
|
+
|
|
948
|
+
return new VisibilityBufferBatch( entry.clusters, entry.material, entry.receiveShadow, capacity, this.renderer, culling, { debug: this.debug, lodCount, view, instanced: entry.instanced, source, queueBudget: entry.queueBudget, maxChunks: entry.maxChunks, pool: this._geometryPool } );
|
|
949
|
+
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
export { VisibilityBufferDrawingPipeline };
|