@aura3d/engine 3.0.0 → 3.0.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/README.md +24 -5
- package/dist/animation/AnimationMixer.d.ts +4 -1
- package/dist/animation/AnimationMixer.d.ts.map +1 -1
- package/dist/animation/AnimationMixer.js +36 -29
- package/dist/animation/AnimationMixer.js.map +1 -1
- package/dist/animation/FootIk.d.ts +9 -0
- package/dist/animation/FootIk.d.ts.map +1 -1
- package/dist/animation/FootIk.js +22 -8
- package/dist/animation/FootIk.js.map +1 -1
- package/dist/animation/HumanoidRetargeting.d.ts +6 -2
- package/dist/animation/HumanoidRetargeting.d.ts.map +1 -1
- package/dist/animation/HumanoidRetargeting.js +18 -8
- package/dist/animation/HumanoidRetargeting.js.map +1 -1
- package/dist/animation/LocomotionEvidence.d.ts +34 -0
- package/dist/animation/LocomotionEvidence.d.ts.map +1 -0
- package/dist/animation/LocomotionEvidence.js +48 -0
- package/dist/animation/LocomotionEvidence.js.map +1 -0
- package/dist/animation/RootMotion.d.ts +13 -4
- package/dist/animation/RootMotion.d.ts.map +1 -1
- package/dist/animation/RootMotion.js +21 -1
- package/dist/animation/RootMotion.js.map +1 -1
- package/dist/animation/index.d.ts +1 -0
- package/dist/animation/index.d.ts.map +1 -1
- package/dist/animation/index.js +1 -0
- package/dist/animation/index.js.map +1 -1
- package/dist/assets/GLTFAnimationRuntime.d.ts +84 -4
- package/dist/assets/GLTFAnimationRuntime.d.ts.map +1 -1
- package/dist/assets/GLTFAnimationRuntime.js +308 -23
- package/dist/assets/GLTFAnimationRuntime.js.map +1 -1
- package/dist/assets/GLTFCompressionDecoders.d.ts +1 -0
- package/dist/assets/GLTFCompressionDecoders.d.ts.map +1 -1
- package/dist/assets/GLTFCompressionDecoders.js +20 -5
- package/dist/assets/GLTFCompressionDecoders.js.map +1 -1
- package/dist/assets/GLTFLoader.d.ts.map +1 -1
- package/dist/assets/GLTFLoader.js +21 -7
- package/dist/assets/GLTFLoader.js.map +1 -1
- package/dist/assets/KTX2BasisTextureTranscoder.d.ts.map +1 -1
- package/dist/assets/KTX2BasisTextureTranscoder.js +8 -0
- package/dist/assets/KTX2BasisTextureTranscoder.js.map +1 -1
- package/dist/controls/MapControls.d.ts +1 -1
- package/dist/controls/MapControls.d.ts.map +1 -1
- package/dist/controls/MapControls.js +3 -3
- package/dist/controls/MapControls.js.map +1 -1
- package/dist/controls/OrbitControls.d.ts +17 -3
- package/dist/controls/OrbitControls.d.ts.map +1 -1
- package/dist/controls/OrbitControls.js +24 -7
- package/dist/controls/OrbitControls.js.map +1 -1
- package/dist/controls/TrackballControls.d.ts.map +1 -1
- package/dist/controls/TrackballControls.js +2 -0
- package/dist/controls/TrackballControls.js.map +1 -1
- package/dist/create-aura3d/index.js +1 -1
- package/dist/engine/agent-api/AnimationController.d.ts +5 -1
- package/dist/engine/agent-api/AnimationController.d.ts.map +1 -1
- package/dist/engine/agent-api/AnimationController.js +5 -0
- package/dist/engine/agent-api/AnimationController.js.map +1 -1
- package/dist/engine/agent-api/CameraProjection.d.ts +2 -0
- package/dist/engine/agent-api/CameraProjection.d.ts.map +1 -0
- package/dist/engine/agent-api/CameraProjection.js +2 -0
- package/dist/engine/agent-api/CameraProjection.js.map +1 -0
- package/dist/engine/agent-api/DeferredFrameResources.d.ts +2 -0
- package/dist/engine/agent-api/DeferredFrameResources.d.ts.map +1 -0
- package/dist/engine/agent-api/DeferredFrameResources.js +2 -0
- package/dist/engine/agent-api/DeferredFrameResources.js.map +1 -0
- package/dist/engine/agent-api/FootPlanting.d.ts +6 -0
- package/dist/engine/agent-api/FootPlanting.d.ts.map +1 -1
- package/dist/engine/agent-api/FootPlanting.js +2 -1
- package/dist/engine/agent-api/FootPlanting.js.map +1 -1
- package/dist/engine/agent-api/GameCameraRigs.d.ts.map +1 -1
- package/dist/engine/agent-api/GameCameraRigs.js +7 -2
- package/dist/engine/agent-api/GameCameraRigs.js.map +1 -1
- package/dist/engine/agent-api/LabelTelemetry.d.ts +8 -2
- package/dist/engine/agent-api/LabelTelemetry.d.ts.map +1 -1
- package/dist/engine/agent-api/LabelTelemetry.js +18 -4
- package/dist/engine/agent-api/LabelTelemetry.js.map +1 -1
- package/dist/engine/agent-api/ModelInstanceMatrices.d.ts +2 -0
- package/dist/engine/agent-api/ModelInstanceMatrices.d.ts.map +1 -0
- package/dist/engine/agent-api/ModelInstanceMatrices.js +2 -0
- package/dist/engine/agent-api/ModelInstanceMatrices.js.map +1 -0
- package/dist/engine/agent-api/NavigationCrowds.d.ts +28 -0
- package/dist/engine/agent-api/NavigationCrowds.d.ts.map +1 -1
- package/dist/engine/agent-api/NavigationCrowds.js +73 -1
- package/dist/engine/agent-api/NavigationCrowds.js.map +1 -1
- package/dist/engine/agent-api/PngTexturePixels.d.ts +9 -0
- package/dist/engine/agent-api/PngTexturePixels.d.ts.map +1 -0
- package/dist/engine/agent-api/PngTexturePixels.js +53 -0
- package/dist/engine/agent-api/PngTexturePixels.js.map +1 -0
- package/dist/engine/agent-api/RootDiagnosticSnapshot.d.ts +2 -0
- package/dist/engine/agent-api/RootDiagnosticSnapshot.d.ts.map +1 -0
- package/dist/engine/agent-api/RootDiagnosticSnapshot.js +2 -0
- package/dist/engine/agent-api/RootDiagnosticSnapshot.js.map +1 -0
- package/dist/engine/agent-api/RootFrameClock.d.ts +2 -0
- package/dist/engine/agent-api/RootFrameClock.d.ts.map +1 -0
- package/dist/engine/agent-api/RootFrameClock.js +2 -0
- package/dist/engine/agent-api/RootFrameClock.js.map +1 -0
- package/dist/engine/agent-api/RootPerformanceQuality.d.ts +2 -0
- package/dist/engine/agent-api/RootPerformanceQuality.d.ts.map +1 -0
- package/dist/engine/agent-api/RootPerformanceQuality.js +2 -0
- package/dist/engine/agent-api/RootPerformanceQuality.js.map +1 -0
- package/dist/engine/agent-api/RootRuntimeSupport.d.ts +61 -0
- package/dist/engine/agent-api/RootRuntimeSupport.d.ts.map +1 -0
- package/dist/engine/agent-api/RootRuntimeSupport.js +127 -0
- package/dist/engine/agent-api/RootRuntimeSupport.js.map +1 -0
- package/dist/engine/agent-api/RuntimeNodeHandle.d.ts +22 -0
- package/dist/engine/agent-api/RuntimeNodeHandle.d.ts.map +1 -1
- package/dist/engine/agent-api/RuntimeNodeHandle.js.map +1 -1
- package/dist/engine/agent-api/WorldLabelRenderer.d.ts +13 -2
- package/dist/engine/agent-api/WorldLabelRenderer.d.ts.map +1 -1
- package/dist/engine/agent-api/WorldLabelRenderer.js +58 -26
- package/dist/engine/agent-api/WorldLabelRenderer.js.map +1 -1
- package/dist/engine/agent-api/index.d.ts +103 -8
- package/dist/engine/agent-api/index.d.ts.map +1 -1
- package/dist/engine/agent-api/index.js +750 -242
- package/dist/engine/agent-api/index.js.map +1 -1
- package/dist/engine/agent-api/product-viewer-runtime.d.ts.map +1 -1
- package/dist/engine/production-runtime/RootGpuParticleWorkload.d.ts +34 -0
- package/dist/engine/production-runtime/RootGpuParticleWorkload.d.ts.map +1 -0
- package/dist/engine/production-runtime/RootGpuParticleWorkload.js +117 -0
- package/dist/engine/production-runtime/RootGpuParticleWorkload.js.map +1 -0
- package/dist/engine/production-runtime/RootRenderSourceBridge.d.ts +2 -0
- package/dist/engine/production-runtime/RootRenderSourceBridge.d.ts.map +1 -0
- package/dist/engine/production-runtime/RootRenderSourceBridge.js +2 -0
- package/dist/engine/production-runtime/RootRenderSourceBridge.js.map +1 -0
- package/dist/engine/production-runtime/TypedGLBActor.d.ts +6 -0
- package/dist/engine/production-runtime/TypedGLBActor.d.ts.map +1 -1
- package/dist/engine/production-runtime/TypedGLBActor.js +13 -0
- package/dist/engine/production-runtime/TypedGLBActor.js.map +1 -1
- package/dist/engine/production-runtime/index.d.ts +2 -0
- package/dist/engine/production-runtime/index.d.ts.map +1 -1
- package/dist/engine/production-runtime/index.js +2 -0
- package/dist/engine/production-runtime/index.js.map +1 -1
- package/dist/input/Haptics.d.ts +1 -1
- package/dist/input/Haptics.js +1 -1
- package/dist/input/InputSystem.d.ts.map +1 -1
- package/dist/input/InputSystem.js +1 -0
- package/dist/input/InputSystem.js.map +1 -1
- package/dist/input/PointerDevice.d.ts +1 -0
- package/dist/input/PointerDevice.d.ts.map +1 -1
- package/dist/input/PointerDevice.js +1 -1
- package/dist/input/PointerDevice.js.map +1 -1
- package/dist/input/controls/OrbitControls.d.ts +44 -1
- package/dist/input/controls/OrbitControls.d.ts.map +1 -1
- package/dist/input/controls/OrbitControls.js +151 -12
- package/dist/input/controls/OrbitControls.js.map +1 -1
- package/dist/lean/base.d.ts +1 -1
- package/dist/lean/base.d.ts.map +1 -1
- package/dist/lean/base.js +1 -1
- package/dist/lean/base.js.map +1 -1
- package/dist/lean/index.js +1 -1
- package/dist/lean/index.js.map +1 -1
- package/dist/navigation-recast/index.d.ts +116 -0
- package/dist/navigation-recast/index.d.ts.map +1 -0
- package/dist/navigation-recast/index.js +247 -0
- package/dist/navigation-recast/index.js.map +1 -0
- package/dist/physics-rapier/HeightfieldLayout.d.ts +12 -0
- package/dist/physics-rapier/HeightfieldLayout.d.ts.map +1 -0
- package/dist/physics-rapier/HeightfieldLayout.js +19 -0
- package/dist/physics-rapier/HeightfieldLayout.js.map +1 -0
- package/dist/physics-rapier/index.d.ts.map +1 -1
- package/dist/physics-rapier/index.js +2 -1
- package/dist/physics-rapier/index.js.map +1 -1
- package/dist/rendering/CascadedShadowMaps.d.ts.map +1 -1
- package/dist/rendering/CascadedShadowMaps.js +3 -1
- package/dist/rendering/CascadedShadowMaps.js.map +1 -1
- package/dist/rendering/ExtensionScalarAtlas.d.ts +18 -0
- package/dist/rendering/ExtensionScalarAtlas.d.ts.map +1 -0
- package/dist/rendering/ExtensionScalarAtlas.js +107 -0
- package/dist/rendering/ExtensionScalarAtlas.js.map +1 -0
- package/dist/rendering/LeanWebGL2Device.d.ts +265 -0
- package/dist/rendering/LeanWebGL2Device.d.ts.map +1 -0
- package/dist/rendering/LeanWebGL2Device.js +4001 -0
- package/dist/rendering/LeanWebGL2Device.js.map +1 -0
- package/dist/rendering/MaterialBinding.js +1 -1
- package/dist/rendering/MaterialBinding.js.map +1 -1
- package/dist/rendering/PlanarReflection.d.ts +2 -2
- package/dist/rendering/PlanarReflection.js +3 -3
- package/dist/rendering/PlanarReflection.js.map +1 -1
- package/dist/rendering/PostProcessPass.d.ts +19 -0
- package/dist/rendering/PostProcessPass.d.ts.map +1 -1
- package/dist/rendering/PostProcessPass.js +64 -32
- package/dist/rendering/PostProcessPass.js.map +1 -1
- package/dist/rendering/ProjectionMath.d.ts +3 -0
- package/dist/rendering/ProjectionMath.d.ts.map +1 -0
- package/dist/rendering/ProjectionMath.js +26 -0
- package/dist/rendering/ProjectionMath.js.map +1 -0
- package/dist/rendering/ReflectionSurfaces.d.ts +4 -1
- package/dist/rendering/ReflectionSurfaces.d.ts.map +1 -1
- package/dist/rendering/ReflectionSurfaces.js +10 -1
- package/dist/rendering/ReflectionSurfaces.js.map +1 -1
- package/dist/rendering/RenderDevice.d.ts +5 -0
- package/dist/rendering/RenderDevice.d.ts.map +1 -1
- package/dist/rendering/RenderDevice.js.map +1 -1
- package/dist/rendering/Renderer.d.ts +9 -0
- package/dist/rendering/Renderer.d.ts.map +1 -1
- package/dist/rendering/Renderer.js +94 -8
- package/dist/rendering/Renderer.js.map +1 -1
- package/dist/rendering/RendererPostprocessPlan.d.ts +16 -3
- package/dist/rendering/RendererPostprocessPlan.d.ts.map +1 -1
- package/dist/rendering/RendererPostprocessPlan.js +16 -2
- package/dist/rendering/RendererPostprocessPlan.js.map +1 -1
- package/dist/rendering/ScreenSpaceReflectionPass.d.ts +43 -0
- package/dist/rendering/ScreenSpaceReflectionPass.d.ts.map +1 -0
- package/dist/rendering/ScreenSpaceReflectionPass.js +58 -0
- package/dist/rendering/ScreenSpaceReflectionPass.js.map +1 -0
- package/dist/rendering/ShaderLibrary.d.ts.map +1 -1
- package/dist/rendering/ShaderLibrary.js +168 -197
- package/dist/rendering/ShaderLibrary.js.map +1 -1
- package/dist/rendering/ShaderLibraryCore.d.ts +3 -0
- package/dist/rendering/ShaderLibraryCore.d.ts.map +1 -1
- package/dist/rendering/ShaderLibraryCore.js +3 -0
- package/dist/rendering/ShaderLibraryCore.js.map +1 -1
- package/dist/rendering/TemporalHistory.d.ts +37 -0
- package/dist/rendering/TemporalHistory.d.ts.map +1 -0
- package/dist/rendering/TemporalHistory.js +135 -0
- package/dist/rendering/TemporalHistory.js.map +1 -0
- package/dist/rendering/TemporalMath.d.ts +3 -0
- package/dist/rendering/TemporalMath.d.ts.map +1 -0
- package/dist/rendering/TemporalMath.js +9 -0
- package/dist/rendering/TemporalMath.js.map +1 -0
- package/dist/rendering/TexturedPBRMaterial.d.ts +3 -0
- package/dist/rendering/TexturedPBRMaterial.d.ts.map +1 -1
- package/dist/rendering/TexturedPBRMaterial.js +65 -3
- package/dist/rendering/TexturedPBRMaterial.js.map +1 -1
- package/dist/rendering/WebGL2Device.d.ts +15 -0
- package/dist/rendering/WebGL2Device.d.ts.map +1 -1
- package/dist/rendering/WebGL2Device.js +328 -90
- package/dist/rendering/WebGL2Device.js.map +1 -1
- package/dist/rendering/WebGPUDevice.d.ts +16 -5
- package/dist/rendering/WebGPUDevice.d.ts.map +1 -1
- package/dist/rendering/WebGPUDevice.js +357 -58
- package/dist/rendering/WebGPUDevice.js.map +1 -1
- package/dist/rendering/WebGPUExtensionAtlas.d.ts +6 -0
- package/dist/rendering/WebGPUExtensionAtlas.d.ts.map +1 -0
- package/dist/rendering/WebGPUExtensionAtlas.js +225 -0
- package/dist/rendering/WebGPUExtensionAtlas.js.map +1 -0
- package/dist/rendering/effects/GPUParticleBackend.d.ts +4 -2
- package/dist/rendering/effects/GPUParticleBackend.d.ts.map +1 -1
- package/dist/rendering/effects/GPUParticleBackend.js +20 -2
- package/dist/rendering/effects/GPUParticleBackend.js.map +1 -1
- package/dist/rendering/effects/ResidentGPUParticleRenderer.d.ts +158 -0
- package/dist/rendering/effects/ResidentGPUParticleRenderer.d.ts.map +1 -0
- package/dist/rendering/effects/ResidentGPUParticleRenderer.js +576 -0
- package/dist/rendering/effects/ResidentGPUParticleRenderer.js.map +1 -0
- package/dist/rendering/extension-scalar-atlas.d.ts +3 -0
- package/dist/rendering/extension-scalar-atlas.d.ts.map +1 -0
- package/dist/rendering/extension-scalar-atlas.js +2 -0
- package/dist/rendering/extension-scalar-atlas.js.map +1 -0
- package/dist/rendering/index.d.ts +1 -0
- package/dist/rendering/index.d.ts.map +1 -1
- package/dist/rendering/index.js +1 -0
- package/dist/rendering/index.js.map +1 -1
- package/dist/rendering/lean/LeanProductionRenderer.d.ts.map +1 -1
- package/dist/rendering/lean/LeanProductionRenderer.js +2 -2
- package/dist/rendering/lean/LeanProductionRenderer.js.map +1 -1
- package/dist/rendering/lean-core-runtime.d.ts +13 -0
- package/dist/rendering/lean-core-runtime.d.ts.map +1 -0
- package/dist/rendering/lean-core-runtime.js +10 -0
- package/dist/rendering/lean-core-runtime.js.map +1 -0
- package/dist/rendering/postprocess/NativeBloomPyramid.d.ts +17 -1
- package/dist/rendering/postprocess/NativeBloomPyramid.d.ts.map +1 -1
- package/dist/rendering/postprocess/NativeBloomPyramid.js +31 -1
- package/dist/rendering/postprocess/NativeBloomPyramid.js.map +1 -1
- package/dist/rendering/production-runtime/ProductionRendererTypes.d.ts +1 -0
- package/dist/rendering/production-runtime/ProductionRendererTypes.d.ts.map +1 -1
- package/dist/rendering/production-runtime/ProductionRendererTypes.js.map +1 -1
- package/dist/rendering/production-runtime/ProductionRuntimeRenderer.d.ts +3 -0
- package/dist/rendering/production-runtime/ProductionRuntimeRenderer.d.ts.map +1 -1
- package/dist/rendering/production-runtime/ProductionRuntimeRenderer.js +8 -1
- package/dist/rendering/production-runtime/ProductionRuntimeRenderer.js.map +1 -1
- package/dist/rendering/production-runtime/ProductionWebGL2Renderer.d.ts +4 -0
- package/dist/rendering/production-runtime/ProductionWebGL2Renderer.d.ts.map +1 -1
- package/dist/rendering/production-runtime/ProductionWebGL2Renderer.js +15 -0
- package/dist/rendering/production-runtime/ProductionWebGL2Renderer.js.map +1 -1
- package/dist/rendering/production-runtime/ProductionWebGPURenderer.d.ts +7 -1
- package/dist/rendering/production-runtime/ProductionWebGPURenderer.d.ts.map +1 -1
- package/dist/rendering/production-runtime/ProductionWebGPURenderer.js +28 -2
- package/dist/rendering/production-runtime/ProductionWebGPURenderer.js.map +1 -1
- package/dist/rendering/production-runtime/framegraph/FrameGraph.d.ts +4 -2
- package/dist/rendering/production-runtime/framegraph/FrameGraph.d.ts.map +1 -1
- package/dist/rendering/production-runtime/framegraph/FrameGraph.js +62 -4
- package/dist/rendering/production-runtime/framegraph/FrameGraph.js.map +1 -1
- package/dist/rendering/production-runtime/framegraph/NativeFrameGraphBindings.d.ts +32 -0
- package/dist/rendering/production-runtime/framegraph/NativeFrameGraphBindings.d.ts.map +1 -0
- package/dist/rendering/production-runtime/framegraph/NativeFrameGraphBindings.js +111 -0
- package/dist/rendering/production-runtime/framegraph/NativeFrameGraphBindings.js.map +1 -0
- package/dist/rendering/production-runtime/framegraph/RenderPass.d.ts +23 -0
- package/dist/rendering/production-runtime/framegraph/RenderPass.d.ts.map +1 -1
- package/dist/rendering/production-runtime/framegraph/RenderPass.js +87 -1
- package/dist/rendering/production-runtime/framegraph/RenderPass.js.map +1 -1
- package/dist/rendering/production-runtime/index.d.ts +2 -0
- package/dist/rendering/production-runtime/index.d.ts.map +1 -1
- package/dist/rendering/production-runtime/index.js +1 -0
- package/dist/rendering/production-runtime/index.js.map +1 -1
- package/dist/rendering/production-runtime/passes/DepthPrepass.d.ts +4 -12
- package/dist/rendering/production-runtime/passes/DepthPrepass.d.ts.map +1 -1
- package/dist/rendering/production-runtime/passes/DepthPrepass.js +3 -11
- package/dist/rendering/production-runtime/passes/DepthPrepass.js.map +1 -1
- package/dist/rendering/production-runtime/passes/FramegraphTopology.js +1 -1
- package/dist/rendering/production-runtime/passes/FramegraphTopology.js.map +1 -1
- package/dist/rendering/production-runtime/passes/OpaquePass.d.ts +3 -8
- package/dist/rendering/production-runtime/passes/OpaquePass.d.ts.map +1 -1
- package/dist/rendering/production-runtime/passes/OpaquePass.js +3 -1
- package/dist/rendering/production-runtime/passes/OpaquePass.js.map +1 -1
- package/dist/rendering/production-runtime/passes/ShadowPass.d.ts +3 -8
- package/dist/rendering/production-runtime/passes/ShadowPass.d.ts.map +1 -1
- package/dist/rendering/production-runtime/passes/ShadowPass.js +2 -0
- package/dist/rendering/production-runtime/passes/ShadowPass.js.map +1 -1
- package/dist/rendering/production-runtime/passes/SkyboxPass.d.ts +3 -7
- package/dist/rendering/production-runtime/passes/SkyboxPass.d.ts.map +1 -1
- package/dist/rendering/production-runtime/passes/SkyboxPass.js +2 -0
- package/dist/rendering/production-runtime/passes/SkyboxPass.js.map +1 -1
- package/dist/rendering/production-runtime/passes/ToneMappingPass.d.ts +7 -10
- package/dist/rendering/production-runtime/passes/ToneMappingPass.d.ts.map +1 -1
- package/dist/rendering/production-runtime/passes/ToneMappingPass.js +9 -0
- package/dist/rendering/production-runtime/passes/ToneMappingPass.js.map +1 -1
- package/dist/rendering/production-runtime/passes/TransparentPass.d.ts +4 -9
- package/dist/rendering/production-runtime/passes/TransparentPass.d.ts.map +1 -1
- package/dist/rendering/production-runtime/passes/TransparentPass.js +6 -1
- package/dist/rendering/production-runtime/passes/TransparentPass.js.map +1 -1
- package/dist/rendering/reflection-surfaces.d.ts +5 -0
- package/dist/rendering/reflection-surfaces.d.ts.map +1 -0
- package/dist/rendering/reflection-surfaces.js +3 -0
- package/dist/rendering/reflection-surfaces.js.map +1 -0
- package/dist/rendering/webgpu/WebGPUPostShaders.d.ts +2 -3
- package/dist/rendering/webgpu/WebGPUPostShaders.d.ts.map +1 -1
- package/dist/rendering/webgpu/WebGPUPostShaders.js +2 -3
- package/dist/rendering/webgpu/WebGPUPostShaders.js.map +1 -1
- package/dist/rendering/webgpu/WebGPUTemporal.d.ts +17 -0
- package/dist/rendering/webgpu/WebGPUTemporal.d.ts.map +1 -0
- package/dist/rendering/webgpu/WebGPUTemporal.js +64 -0
- package/dist/rendering/webgpu/WebGPUTemporal.js.map +1 -0
- package/dist/rendering/webgpu.d.ts +6 -0
- package/dist/rendering/webgpu.d.ts.map +1 -1
- package/dist/rendering/webgpu.js +4 -0
- package/dist/rendering/webgpu.js.map +1 -1
- package/package.json +37 -24
- package/templates/cinematic-scene/package.json +2 -2
- package/templates/cinematic-scene/src/main.ts +14 -2
- package/templates/mini-game/package.json +2 -2
- package/templates/product-viewer/package.json +2 -2
- package/templates/production-asset-inspector/package.json +1 -1
- package/templates/production-material-studio/package.json +1 -1
- package/templates/production-product-configurator/package.json +1 -1
- package/templates/production-product-viewer/package.json +1 -1
- package/templates/cinematic-scene/node_modules/.vite/deps/_metadata.json +0 -8
- package/templates/cinematic-scene/node_modules/.vite/deps/package.json +0 -3
- package/templates/cinematic-scene/test-results/.last-run.json +0 -6
- package/templates/cinematic-scene/test-results/route-health-Aura3D-cinematic-scene-reaches-ready-state/error-context.md +0 -64
- package/templates/product-viewer/node_modules/.vite/deps/_metadata.json +0 -8
- package/templates/product-viewer/node_modules/.vite/deps/package.json +0 -3
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { WEBGPU_EXTENSION_ATLAS_WGSL, webgpuExtensionAtlasUniforms } from "./WebGPUExtensionAtlas.js";
|
|
1
2
|
import { RenderDeviceError, viewBytes, resolveGpuTargetOwner, spreadGpuTargetInventory } from "./RenderDevice.js";
|
|
2
3
|
import { MAX_WEBGPU_SKINNING_JOINTS } from "./WebGPUSkinningLimits.js";
|
|
4
|
+
import { normalizeWebGPUTemporalOptions, WEBGPU_TAA_FRAGMENT, WEBGPU_TAA_OUTPUT_FRAGMENT } from "./webgpu/WebGPUTemporal.js";
|
|
3
5
|
import { defaultWebGPUBloomWeights, normalizeWebGPUColorGradeOptions, normalizeWebGPUBloomOptions, webgpuBlurFragment, webgpuBloomCompositeFragment, webgpuBrightExtractFragment, webgpuColorGradeFragment, webgpuFxaaFragment, WEBGPU_POST_VERTEX_WGSL } from "./webgpu/WebGPUPostShaders.js";
|
|
4
6
|
import { DEFAULT_DEPTH_SHADER_MARKER } from "./ShaderLibraryCore.js";
|
|
5
7
|
import { reflectShaderSources } from "./ShaderReflection.js";
|
|
@@ -24,6 +26,26 @@ const TEXTURE_USAGE = {
|
|
|
24
26
|
TEXTURE_BINDING: 0x0004
|
|
25
27
|
};
|
|
26
28
|
const DEPTH_TEXTURE_FORMAT = "depth24plus";
|
|
29
|
+
const WEBGPU_NATIVE_COPY_FRAGMENT = `
|
|
30
|
+
@group(0) @binding(0) var<uniform> params: vec4<f32>;
|
|
31
|
+
@group(0) @binding(1) var linearSampler: sampler;
|
|
32
|
+
@group(0) @binding(2) var source: texture_2d<f32>;
|
|
33
|
+
@fragment fn fs_copy(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
|
34
|
+
return textureSample(source, linearSampler, clamp(uv, params.xy * 0.5, vec2<f32>(1.0) - params.xy * 0.5));
|
|
35
|
+
}`;
|
|
36
|
+
const WEBGPU_NATIVE_TONE_FRAGMENT = `
|
|
37
|
+
@group(0) @binding(0) var<uniform> params: vec4<f32>;
|
|
38
|
+
@group(0) @binding(1) var linearSampler: sampler;
|
|
39
|
+
@group(0) @binding(2) var source: texture_2d<f32>;
|
|
40
|
+
@fragment fn fs_tone(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
|
41
|
+
let sample = textureSample(source, linearSampler, uv);
|
|
42
|
+
var c = max(sample.rgb * params.x / params.w, vec3<f32>(0.0));
|
|
43
|
+
if (params.y > 2.5) { let toe=max(c-vec3<f32>(0.004),vec3<f32>(0.0)); c=min((toe*(6.2*toe+vec3<f32>(0.5)))/(toe*(6.2*toe+vec3<f32>(1.7))+vec3<f32>(0.06)),c*1.08); }
|
|
44
|
+
else if (params.y > 1.5) { c = clamp((c * (2.51 * c + vec3<f32>(0.03))) / (c * (2.43 * c + vec3<f32>(0.59)) + vec3<f32>(0.14)), vec3<f32>(0.0), vec3<f32>(1.0)); }
|
|
45
|
+
else if (params.y > 0.5) { c = c / (vec3<f32>(1.0) + c); }
|
|
46
|
+
if (params.z > 0.5) { c = select(1.055 * pow(c, vec3<f32>(1.0 / 2.4)) - vec3<f32>(0.055), c * 12.92, c <= vec3<f32>(0.0031308)); }
|
|
47
|
+
return vec4<f32>(c, sample.a);
|
|
48
|
+
}`;
|
|
27
49
|
class WebGPURenderBuffer {
|
|
28
50
|
id;
|
|
29
51
|
usage;
|
|
@@ -58,9 +80,13 @@ class WebGPUShaderProgram {
|
|
|
58
80
|
entryPoints;
|
|
59
81
|
nativeUniformLayout;
|
|
60
82
|
portableBindings;
|
|
83
|
+
nativeColorDefaultVertex;
|
|
84
|
+
nativeAtlasVertex;
|
|
61
85
|
disposed = false;
|
|
62
86
|
renderPipelines = new Map();
|
|
63
|
-
|
|
87
|
+
nativeColorDefaultModule;
|
|
88
|
+
atlasVertexModules = new Map();
|
|
89
|
+
constructor(id, label, marker, reflection, modules, entryPoints, nativeUniformLayout, portableBindings, nativeColorDefaultVertex, nativeAtlasVertex) {
|
|
64
90
|
this.id = id;
|
|
65
91
|
this.label = label;
|
|
66
92
|
this.marker = marker;
|
|
@@ -69,6 +95,8 @@ class WebGPUShaderProgram {
|
|
|
69
95
|
this.entryPoints = entryPoints;
|
|
70
96
|
this.nativeUniformLayout = nativeUniformLayout;
|
|
71
97
|
this.portableBindings = portableBindings;
|
|
98
|
+
this.nativeColorDefaultVertex = nativeColorDefaultVertex;
|
|
99
|
+
this.nativeAtlasVertex = nativeAtlasVertex;
|
|
72
100
|
}
|
|
73
101
|
dispose() {
|
|
74
102
|
this.disposed = true;
|
|
@@ -162,6 +190,8 @@ export class WebGPUDevice {
|
|
|
162
190
|
nativeBloomPasses = 0;
|
|
163
191
|
nativeColorGradePasses = 0;
|
|
164
192
|
nativeFxaaPasses = 0;
|
|
193
|
+
nativeTaaPasses = 0;
|
|
194
|
+
nativeTemporalBindings = 0;
|
|
165
195
|
webgpuPostPipelines = new Map();
|
|
166
196
|
webgpuPostLinearSampler = null;
|
|
167
197
|
lastWebGPUBloom = null;
|
|
@@ -312,7 +342,7 @@ export class WebGPUDevice {
|
|
|
312
342
|
this.device.createShaderModule({ label: `${sources.label}-fragment`, code: nativeSources.fragment })
|
|
313
343
|
]
|
|
314
344
|
: [];
|
|
315
|
-
const shader = new WebGPUShaderProgram(this.nextId++, sources.label, sources.marker, reflectShaderSources(sources), modules, nativeSources.entryPoints, nativeSources.uniformLayout, nativeSources.portableBindings ?? []);
|
|
345
|
+
const shader = new WebGPUShaderProgram(this.nextId++, sources.label, sources.marker, reflectShaderSources(sources), modules, nativeSources.entryPoints, nativeSources.uniformLayout, nativeSources.portableBindings ?? [], nativeSources.colorDefaultVertex, nativeSources.atlasVertex);
|
|
316
346
|
this.shaders.add(shader);
|
|
317
347
|
return shader;
|
|
318
348
|
}
|
|
@@ -787,6 +817,13 @@ export class WebGPUDevice {
|
|
|
787
817
|
this.rasterizeDraw(command, vertexBuffer);
|
|
788
818
|
this.drawCalls += 1;
|
|
789
819
|
}
|
|
820
|
+
async waitForSubmittedWork() {
|
|
821
|
+
this.assertAlive();
|
|
822
|
+
if (!this.device.queue.onSubmittedWorkDone) {
|
|
823
|
+
throw new RenderDeviceError("Native GPU queue completion is unavailable", "GPU_COMPLETION_UNAVAILABLE");
|
|
824
|
+
}
|
|
825
|
+
await this.device.queue.onSubmittedWorkDone();
|
|
826
|
+
}
|
|
790
827
|
endFrame() {
|
|
791
828
|
this.assertFrame();
|
|
792
829
|
this.frameActive = false;
|
|
@@ -821,6 +858,8 @@ export class WebGPUDevice {
|
|
|
821
858
|
["nativeBloomPasses", this.nativeBloomPasses],
|
|
822
859
|
["nativeColorGradePasses", this.nativeColorGradePasses],
|
|
823
860
|
["nativeFxaaPasses", this.nativeFxaaPasses],
|
|
861
|
+
["nativeTaaPasses", this.nativeTaaPasses],
|
|
862
|
+
["nativeTemporalBindings", this.nativeTemporalBindings],
|
|
824
863
|
["canvasSubmissions", this.canvasSubmissions]
|
|
825
864
|
]);
|
|
826
865
|
}
|
|
@@ -879,7 +918,7 @@ export class WebGPUDevice {
|
|
|
879
918
|
*
|
|
880
919
|
* Renders bright-extract -> separable-blur mip pyramid -> composite over
|
|
881
920
|
* the source, all as real WGSL fullscreen passes on this device. Returns a
|
|
882
|
-
* fresh
|
|
921
|
+
* fresh rgba16f target owned by the caller (dispose it); every intermediate
|
|
883
922
|
* is disposed before return. Throws fail-closed when the native device
|
|
884
923
|
* cannot run fullscreen passes.
|
|
885
924
|
*/
|
|
@@ -893,7 +932,10 @@ export class WebGPUDevice {
|
|
|
893
932
|
}
|
|
894
933
|
const width = src.width;
|
|
895
934
|
const height = src.height;
|
|
896
|
-
|
|
935
|
+
// Preserve HDR source energy even at performance quality. Bloom adds to
|
|
936
|
+
// scene radiance before tone mapping, so its composite is always floating point.
|
|
937
|
+
const halfFloat = normalized.halfFloat || src.colorTexture.format === "rgba16f" || src.colorTexture.format === "rgba32f";
|
|
938
|
+
const mipFormat = halfFloat ? "rgba16f" : "rgba8";
|
|
897
939
|
const owned = [];
|
|
898
940
|
const track = (target) => {
|
|
899
941
|
owned.push(target);
|
|
@@ -943,7 +985,7 @@ export class WebGPUDevice {
|
|
|
943
985
|
level = mipTarget;
|
|
944
986
|
}
|
|
945
987
|
const weights = defaultWebGPUBloomWeights(normalized.mipCount);
|
|
946
|
-
const composite = track(this.createRenderTarget({ width, height, format: "
|
|
988
|
+
const composite = track(this.createRenderTarget({ width, height, format: "rgba16f", label: "a3d-webgpu-bloom-composite" }));
|
|
947
989
|
const mipViews = mips.map((mipTarget) => {
|
|
948
990
|
const view = this.requireRenderTarget(mipTarget).nativeView;
|
|
949
991
|
if (!view)
|
|
@@ -958,13 +1000,13 @@ export class WebGPUDevice {
|
|
|
958
1000
|
views: [srcView, ...mipViews],
|
|
959
1001
|
target: composite
|
|
960
1002
|
});
|
|
961
|
-
const bytesPerPixel =
|
|
1003
|
+
const bytesPerPixel = halfFloat ? 8 : 4;
|
|
962
1004
|
const targetBytes = width * height * bytesPerPixel
|
|
963
|
-
+ mips.reduce((total, mipTarget) => total + mipTarget.width * mipTarget.height * bytesPerPixel, 0)
|
|
964
|
-
+ width * height *
|
|
1005
|
+
+ mips.reduce((total, mipTarget) => total + mipTarget.width * mipTarget.height * bytesPerPixel * 2, 0)
|
|
1006
|
+
+ width * height * 8;
|
|
965
1007
|
this.lastWebGPUBloom = {
|
|
966
1008
|
mipCount: normalized.mipCount,
|
|
967
|
-
halfFloat
|
|
1009
|
+
halfFloat,
|
|
968
1010
|
targetBytes,
|
|
969
1011
|
compositeGain: normalized.strength,
|
|
970
1012
|
passes: 1 + normalized.mipCount * 2 + 1,
|
|
@@ -1033,9 +1075,8 @@ export class WebGPUDevice {
|
|
|
1033
1075
|
/**
|
|
1034
1076
|
* muse3jsparity-PRD J2 — native WebGPU FXAA.
|
|
1035
1077
|
* Compact FXAA 3.11 console core (luma neighborhood, one perpendicular
|
|
1036
|
-
* blend tap pair; flat neighborhoods pass through untouched).
|
|
1037
|
-
*
|
|
1038
|
-
* WebGPU path (same withheld doctrine as the root A3 nodes).
|
|
1078
|
+
* blend tap pair; flat neighborhoods pass through untouched). Temporal
|
|
1079
|
+
* antialiasing has a separate GPU history contract in executeWebGPUTaa.
|
|
1039
1080
|
*/
|
|
1040
1081
|
executeWebGPUFxaa(source) {
|
|
1041
1082
|
this.reclaimWebGPUPostUniformBuffers();
|
|
@@ -1062,16 +1103,108 @@ export class WebGPUDevice {
|
|
|
1062
1103
|
throw error;
|
|
1063
1104
|
}
|
|
1064
1105
|
}
|
|
1106
|
+
/** Native target-to-target chain. Unsupported passes fail before any submission. */
|
|
1107
|
+
presentLdrPostprocess(source, options) {
|
|
1108
|
+
this.assertAlive();
|
|
1109
|
+
const supported = new Set(["bloom", "tone-mapping", "color-grade", "fxaa", "taa"]);
|
|
1110
|
+
for (const pass of options.passes) {
|
|
1111
|
+
if (!supported.has(pass.name))
|
|
1112
|
+
throw new RenderDeviceError(`Native WebGPU postprocess does not support ${pass.name}`, "WEBGPU_POSTPROCESS_UNSUPPORTED", { pass: pass.name });
|
|
1113
|
+
}
|
|
1114
|
+
const owned = [];
|
|
1115
|
+
let current = source;
|
|
1116
|
+
const track = (target) => { owned.push(target); current = target; };
|
|
1117
|
+
try {
|
|
1118
|
+
for (const pass of options.passes) {
|
|
1119
|
+
if (pass.name === "bloom")
|
|
1120
|
+
track(this.executeWebGPUBloom(current, pass.options));
|
|
1121
|
+
else if (pass.name === "color-grade")
|
|
1122
|
+
track(this.executeWebGPUColorGrade(current, pass.options));
|
|
1123
|
+
else if (pass.name === "fxaa")
|
|
1124
|
+
track(this.executeWebGPUFxaa(current));
|
|
1125
|
+
else if (pass.name === "taa") {
|
|
1126
|
+
const temporal = pass.options.temporal;
|
|
1127
|
+
if (!temporal)
|
|
1128
|
+
throw new RenderDeviceError("Native WebGPU TAA requires GPU temporal bindings", "TEMPORAL_NATIVE_REQUIRED");
|
|
1129
|
+
track(this.executeWebGPUTaa(current, { ...temporal, ...(typeof pass.options.blend === "number" ? { blend: pass.options.blend } : {}) }));
|
|
1130
|
+
}
|
|
1131
|
+
else if (pass.name === "tone-mapping") {
|
|
1132
|
+
const tone = { ...options.toneMappingDefaults, ...pass.options };
|
|
1133
|
+
const operator = tone.operator ?? "reinhard";
|
|
1134
|
+
const operatorId = operator === "linear" || operator === "none" ? 0 : operator === "reinhard" ? 1 : operator === "aces" || operator === "aces-filmic" ? 2 : operator === "filmic" ? 3 : -1;
|
|
1135
|
+
if (operatorId < 0)
|
|
1136
|
+
throw new RenderDeviceError(`Unsupported native WebGPU tone operator ${String(operator)}`, "WEBGPU_POSTPROCESS_UNSUPPORTED");
|
|
1137
|
+
const exposure = typeof tone.exposure === "number" ? tone.exposure : 1;
|
|
1138
|
+
const whitePoint = typeof tone.whitePoint === "number" ? tone.whitePoint : 1;
|
|
1139
|
+
if (!Number.isFinite(whitePoint) || whitePoint <= 0)
|
|
1140
|
+
throw new RenderDeviceError("Invalid tone white point", "WEBGPU_POSTPROCESS_UNSUPPORTED");
|
|
1141
|
+
if (!Number.isFinite(exposure) || exposure < 0)
|
|
1142
|
+
throw new RenderDeviceError("Invalid tone exposure", "WEBGPU_POSTPROCESS_UNSUPPORTED");
|
|
1143
|
+
const target = this.createRenderTarget({ width: source.width, height: source.height, format: "rgba8", label: "a3d-webgpu-tone" });
|
|
1144
|
+
owned.push(target);
|
|
1145
|
+
this.runWebGPUFullscreenPass({ label: "webgpu-tone", fragment: WEBGPU_NATIVE_TONE_FRAGMENT, entryPoint: "fs_tone",
|
|
1146
|
+
uniforms: new Float32Array([exposure, operatorId, tone.outputColorSpace === "srgb" ? 1 : 0, whitePoint]),
|
|
1147
|
+
views: [this.requireRenderTarget(current).nativeView], target });
|
|
1148
|
+
current = target;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
const target = options.outputTarget ?? null;
|
|
1152
|
+
if (target === current)
|
|
1153
|
+
throw new RenderDeviceError("Native WebGPU presentation source/output alias", "INVALID_RESOURCE");
|
|
1154
|
+
this.runWebGPUFullscreenPass({ label: "webgpu-post-present", fragment: WEBGPU_NATIVE_COPY_FRAGMENT, entryPoint: "fs_copy",
|
|
1155
|
+
uniforms: new Float32Array([1 / source.width, 1 / source.height, 0, 0]),
|
|
1156
|
+
views: [this.requireRenderTarget(current).nativeView], target });
|
|
1157
|
+
if (!target) {
|
|
1158
|
+
this.activeRenderTarget = null;
|
|
1159
|
+
this.canvasSubmissions += 1;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
finally {
|
|
1163
|
+
for (const target of owned)
|
|
1164
|
+
target.dispose();
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
/** Resolve GPU velocity/history into caller-owned historyOutput, returning scene-alpha color. */
|
|
1168
|
+
executeWebGPUTaa(source, options) {
|
|
1169
|
+
this.assertAlive();
|
|
1170
|
+
const [blend, depthThreshold] = normalizeWebGPUTemporalOptions(options);
|
|
1171
|
+
const targets = [source, options.velocity, options.history, options.historyOutput];
|
|
1172
|
+
if (new Set(targets).size !== targets.length)
|
|
1173
|
+
throw new RenderDeviceError("TAA targets must not alias", "NATIVE_POST_UNSUPPORTED");
|
|
1174
|
+
const native = targets.map((target) => this.requireRenderTarget(target));
|
|
1175
|
+
if (native.some((target) => target.width !== source.width || target.height !== source.height || !target.nativeView)) {
|
|
1176
|
+
throw new RenderDeviceError("TAA requires same-size native source, velocity and history targets", "NATIVE_POST_UNSUPPORTED");
|
|
1177
|
+
}
|
|
1178
|
+
if (targets.slice(1).some((target) => target.colorTexture.format !== "rgba16f")) {
|
|
1179
|
+
throw new RenderDeviceError("TAA velocity/history targets require rgba16f", "NATIVE_POST_UNSUPPORTED");
|
|
1180
|
+
}
|
|
1181
|
+
const out = this.createRenderTarget({ width: source.width, height: source.height, format: "rgba16f", label: "a3d-webgpu-taa-color" });
|
|
1182
|
+
try {
|
|
1183
|
+
this.runWebGPUFullscreenPass({ label: "webgpu-taa", fragment: WEBGPU_TAA_FRAGMENT, entryPoint: "fs_taa",
|
|
1184
|
+
uniforms: new Float32Array([1 / source.width, 1 / source.height, blend, options.historyValid ? 1 : 0, depthThreshold, 0, 0, 0]),
|
|
1185
|
+
views: native.slice(0, 3).map((target) => target.nativeView), target: options.historyOutput });
|
|
1186
|
+
this.runWebGPUFullscreenPass({ label: "webgpu-taa-output", fragment: WEBGPU_TAA_OUTPUT_FRAGMENT, entryPoint: "fs_taa_output",
|
|
1187
|
+
uniforms: new Float32Array([1 / source.width, 1 / source.height, 0, 0]),
|
|
1188
|
+
views: [native[3].nativeView, native[0].nativeView], target: out });
|
|
1189
|
+
this.nativeTaaPasses += 2;
|
|
1190
|
+
this.nativeTemporalBindings += 3;
|
|
1191
|
+
return out;
|
|
1192
|
+
}
|
|
1193
|
+
catch (error) {
|
|
1194
|
+
out.dispose();
|
|
1195
|
+
throw error;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1065
1198
|
runWebGPUFullscreenPass(args) {
|
|
1066
1199
|
// No assertFrame here on purpose: these are target-to-target passes with
|
|
1067
1200
|
// their own encoders, so they run both inside a Renderer frame (scene ->
|
|
1068
1201
|
// post chaining) and after it closed (proof harnesses that render, then
|
|
1069
1202
|
// post, then read back).
|
|
1070
1203
|
this.assertAlive();
|
|
1071
|
-
const target = this.requireRenderTarget(args.target);
|
|
1072
|
-
const targetView = target.nativeView;
|
|
1204
|
+
const target = args.target ? this.requireRenderTarget(args.target) : null;
|
|
1205
|
+
const targetView = target ? target.nativeView : this.canvasContext?.getCurrentTexture().createView();
|
|
1073
1206
|
if (!targetView) {
|
|
1074
|
-
throw new RenderDeviceError("WebGPU post target has no native view", "NATIVE_POST_UNSUPPORTED", { label: target
|
|
1207
|
+
throw new RenderDeviceError("WebGPU post target has no native view", "NATIVE_POST_UNSUPPORTED", { label: target?.label ?? "canvas" });
|
|
1075
1208
|
}
|
|
1076
1209
|
if (!this.device.createShaderModule || !this.device.createRenderPipeline || !this.device.createCommandEncoder
|
|
1077
1210
|
|| !this.device.createSampler || !this.device.createBuffer || !this.device.createBindGroup) {
|
|
@@ -1084,8 +1217,10 @@ export class WebGPUDevice {
|
|
|
1084
1217
|
// the submit) so per-pass validation failures land here labeled.
|
|
1085
1218
|
scopeDevice.pushErrorScope?.("validation");
|
|
1086
1219
|
}
|
|
1087
|
-
const format = webgpuTextureFormat(target.colorTexture.format);
|
|
1088
|
-
|
|
1220
|
+
const format = target ? webgpuTextureFormat(target.colorTexture.format) : this.presentationFormat;
|
|
1221
|
+
// Bloom quality changes the fragment binding layout (one texture per mip).
|
|
1222
|
+
// A label/format-only key can reuse the wrong native pipeline after a quality change.
|
|
1223
|
+
const cacheKey = `${args.label}:${args.entryPoint}:${format}:${args.fragment}`;
|
|
1089
1224
|
let pipeline = this.webgpuPostPipelines.get(cacheKey);
|
|
1090
1225
|
if (!pipeline) {
|
|
1091
1226
|
const vertexModule = this.device.createShaderModule({ label: `${args.label}-vs`, code: WEBGPU_POST_VERTEX_WGSL });
|
|
@@ -1141,7 +1276,8 @@ export class WebGPUDevice {
|
|
|
1141
1276
|
submitted = true;
|
|
1142
1277
|
// The pass owns every pixel (fullscreen triangle), so a later
|
|
1143
1278
|
// readPixelsAsync must NOT flush a stale pending clear over it.
|
|
1144
|
-
target
|
|
1279
|
+
if (target)
|
|
1280
|
+
target.nativeNeedsClear = false;
|
|
1145
1281
|
this.nativeRenderPasses += 1;
|
|
1146
1282
|
// Retired, not destroyed: the submit only enqueues; the pass reads
|
|
1147
1283
|
// these uniforms when the GPU gets to it.
|
|
@@ -1202,6 +1338,8 @@ export class WebGPUDevice {
|
|
|
1202
1338
|
throw new RenderDeviceError("No active frame", "NO_ACTIVE_FRAME");
|
|
1203
1339
|
}
|
|
1204
1340
|
}
|
|
1341
|
+
temporalLossListeners = new Set();
|
|
1342
|
+
onDeviceLost(listener) { this.temporalLossListeners.add(listener); return () => this.temporalLossListeners.delete(listener); }
|
|
1205
1343
|
observeDeviceLost() {
|
|
1206
1344
|
const lost = this.device.lost;
|
|
1207
1345
|
if (!lost || typeof lost.then !== "function")
|
|
@@ -1210,12 +1348,24 @@ export class WebGPUDevice {
|
|
|
1210
1348
|
if (this.disposed)
|
|
1211
1349
|
return;
|
|
1212
1350
|
this.contextLost = true;
|
|
1351
|
+
for (const listener of this.temporalLossListeners) {
|
|
1352
|
+
try {
|
|
1353
|
+
listener();
|
|
1354
|
+
}
|
|
1355
|
+
catch { /* Continue notifying owners. */ }
|
|
1356
|
+
}
|
|
1213
1357
|
const detail = [info.reason, info.message].filter(Boolean).join(": ");
|
|
1214
1358
|
this.lastError = detail ? `WebGPU device lost: ${detail}` : "WebGPU device lost";
|
|
1215
1359
|
}).catch((error) => {
|
|
1216
1360
|
if (this.disposed)
|
|
1217
1361
|
return;
|
|
1218
1362
|
this.contextLost = true;
|
|
1363
|
+
for (const listener of this.temporalLossListeners) {
|
|
1364
|
+
try {
|
|
1365
|
+
listener();
|
|
1366
|
+
}
|
|
1367
|
+
catch { /* Continue notifying owners. */ }
|
|
1368
|
+
}
|
|
1219
1369
|
this.lastError = `WebGPU device lost promise rejected: ${error instanceof Error ? error.message : String(error)}`;
|
|
1220
1370
|
});
|
|
1221
1371
|
}
|
|
@@ -1289,9 +1439,9 @@ export class WebGPUDevice {
|
|
|
1289
1439
|
const worldA = transformPosition(localA, modelMatrix);
|
|
1290
1440
|
const worldB = transformPosition(localB, modelMatrix);
|
|
1291
1441
|
const worldC = transformPosition(localC, modelMatrix);
|
|
1292
|
-
const colorA = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexA);
|
|
1293
|
-
const colorB = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexB);
|
|
1294
|
-
const colorC = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexC);
|
|
1442
|
+
const colorA = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexA, colorAttribute?.components);
|
|
1443
|
+
const colorB = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexB, colorAttribute?.components);
|
|
1444
|
+
const colorC = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexC, colorAttribute?.components);
|
|
1295
1445
|
const uvA = readVertexUv(vertexBuffer.bytes, command.vertexFormat.stride, uvAttribute?.offset, indexA);
|
|
1296
1446
|
const uvB = readVertexUv(vertexBuffer.bytes, command.vertexFormat.stride, uvAttribute?.offset, indexB);
|
|
1297
1447
|
const uvC = readVertexUv(vertexBuffer.bytes, command.vertexFormat.stride, uvAttribute?.offset, indexC);
|
|
@@ -1304,15 +1454,15 @@ export class WebGPUDevice {
|
|
|
1304
1454
|
const indexB = indices[offset + 1];
|
|
1305
1455
|
const a = transformPosition(readLocal(indexA), matrix);
|
|
1306
1456
|
const b = transformPosition(readLocal(indexB), matrix);
|
|
1307
|
-
const colorA = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexA);
|
|
1308
|
-
const colorB = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexB);
|
|
1457
|
+
const colorA = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexA, colorAttribute?.components);
|
|
1458
|
+
const colorB = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, indexB, colorAttribute?.components);
|
|
1309
1459
|
rasterizeLine(this.activeRenderTarget, a, b, color, colorA, colorB, depthTest, depthWrite);
|
|
1310
1460
|
}
|
|
1311
1461
|
}
|
|
1312
1462
|
else {
|
|
1313
1463
|
for (const index of indices) {
|
|
1314
1464
|
const point = transformPosition(readLocal(index), matrix);
|
|
1315
|
-
const vertexColor = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, index);
|
|
1465
|
+
const vertexColor = readVertexColor(vertexBuffer.bytes, command.vertexFormat.stride, colorAttribute?.offset, index, colorAttribute?.components);
|
|
1316
1466
|
rasterizePoint(this.activeRenderTarget, point, multiplyColor(color, vertexColor), depthTest, depthWrite);
|
|
1317
1467
|
}
|
|
1318
1468
|
}
|
|
@@ -1326,7 +1476,27 @@ export class WebGPUDevice {
|
|
|
1326
1476
|
if (!hasNativeRenderPipeline(this.device))
|
|
1327
1477
|
return;
|
|
1328
1478
|
const shader = this.requireShader(command.shader);
|
|
1329
|
-
|
|
1479
|
+
// GL supplies an opaque white default for an absent vertex color. Native
|
|
1480
|
+
// WGSL inputs must instead match the actual vertex buffer layout.
|
|
1481
|
+
const useDefaultColor = shader.nativeColorDefaultVertex && !command.vertexFormat?.attributes.some(attribute => attribute.semantic === "color");
|
|
1482
|
+
if (useDefaultColor && !shader.nativeColorDefaultModule) {
|
|
1483
|
+
shader.nativeColorDefaultModule = this.device.createShaderModule?.({ label: `${shader.label}-vertex-default-color`, code: shader.nativeColorDefaultVertex });
|
|
1484
|
+
}
|
|
1485
|
+
let vertexModule = useDefaultColor ? shader.nativeColorDefaultModule : shader.modules[0];
|
|
1486
|
+
if (shader.nativeAtlasVertex) {
|
|
1487
|
+
const hasColor = command.vertexFormat?.attributes.some(attribute => attribute.shaderLocation === 4) ?? false;
|
|
1488
|
+
const hasUv1 = command.vertexFormat?.attributes.some(attribute => attribute.shaderLocation === 7) ?? false;
|
|
1489
|
+
const key = `${hasColor}:${hasUv1}`;
|
|
1490
|
+
if (!shader.atlasVertexModules.has(key)) {
|
|
1491
|
+
let source = shader.nativeAtlasVertex;
|
|
1492
|
+
if (!hasColor)
|
|
1493
|
+
source = source.replace(", @location(4) color: vec4<f32>", "").replace("output.color = color;", "output.color = vec4<f32>(1.0);");
|
|
1494
|
+
if (!hasUv1)
|
|
1495
|
+
source = source.replace(", @location(7) uv1: vec2<f32>", "").replace("output.uv1 = uv1;", "output.uv1 = vec2<f32>(0.0);");
|
|
1496
|
+
shader.atlasVertexModules.set(key, this.device.createShaderModule?.({ label: `${shader.label}-atlas-vertex-${key}`, code: source }));
|
|
1497
|
+
}
|
|
1498
|
+
vertexModule = shader.atlasVertexModules.get(key);
|
|
1499
|
+
}
|
|
1330
1500
|
const fragmentModule = shader.modules[1] ?? vertexModule;
|
|
1331
1501
|
if (!vertexModule || !fragmentModule)
|
|
1332
1502
|
return;
|
|
@@ -1386,12 +1556,19 @@ export class WebGPUDevice {
|
|
|
1386
1556
|
const uniformBuffer = usesNativeDrawUniforms(shader.nativeUniformLayout) ? this.createNativeDrawUniformBuffer(command) : null;
|
|
1387
1557
|
const sampledTexture = shader.nativeUniformLayout === "generated-texture" ? this.createNativeSampledTextureBinding(uniformBaseColorTextureBinding(command.uniforms)) : null;
|
|
1388
1558
|
const materialTextures = usesNativePbrTextureBindings(shader.nativeUniformLayout) ? this.createNativePbrTextureBindings(command) : null;
|
|
1559
|
+
const atlasResources = shader.nativeUniformLayout === "generated-atlas-pbr" ? this.createNativeAtlasBindings(command) : null;
|
|
1560
|
+
if (shader.nativeUniformLayout === "generated-atlas-pbr" && !atlasResources) {
|
|
1561
|
+
uniformBuffer?.destroy();
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1389
1564
|
if (shader.nativeUniformLayout === "generated-texture" && !sampledTexture) {
|
|
1390
1565
|
uniformBuffer?.destroy();
|
|
1566
|
+
atlasResources?.buffer.destroy();
|
|
1391
1567
|
return;
|
|
1392
1568
|
}
|
|
1393
1569
|
if (usesNativePbrTextureBindings(shader.nativeUniformLayout) && !materialTextures) {
|
|
1394
1570
|
uniformBuffer?.destroy();
|
|
1571
|
+
atlasResources?.buffer.destroy();
|
|
1395
1572
|
return;
|
|
1396
1573
|
}
|
|
1397
1574
|
if (shader.nativeUniformLayout === "portable" && !portableResources)
|
|
@@ -1402,6 +1579,7 @@ export class WebGPUDevice {
|
|
|
1402
1579
|
layout: pipeline.getBindGroupLayout(0),
|
|
1403
1580
|
entries: portableResources?.entries ?? [
|
|
1404
1581
|
{ binding: 0, resource: { buffer: uniformBuffer } },
|
|
1582
|
+
...(atlasResources?.entries ?? []),
|
|
1405
1583
|
...(sampledTexture ? [
|
|
1406
1584
|
{ binding: 1, resource: sampledTexture.sampler },
|
|
1407
1585
|
{ binding: 2, resource: sampledTexture.view }
|
|
@@ -1458,6 +1636,7 @@ export class WebGPUDevice {
|
|
|
1458
1636
|
if (!pass.setIndexBuffer || !pass.drawIndexed) {
|
|
1459
1637
|
pass.end();
|
|
1460
1638
|
uniformBuffer?.destroy();
|
|
1639
|
+
atlasResources?.buffer.destroy();
|
|
1461
1640
|
portableResources?.buffer.destroy();
|
|
1462
1641
|
this.lastError = "Native WebGPU indexed draw skipped because the render-pass encoder does not expose indexed draw APIs.";
|
|
1463
1642
|
return;
|
|
@@ -1474,6 +1653,7 @@ export class WebGPUDevice {
|
|
|
1474
1653
|
if (this.activeRenderTarget)
|
|
1475
1654
|
this.activeRenderTarget.nativeNeedsClear = false;
|
|
1476
1655
|
uniformBuffer?.destroy();
|
|
1656
|
+
atlasResources?.buffer.destroy();
|
|
1477
1657
|
portableResources?.buffer.destroy();
|
|
1478
1658
|
this.nativeSubmissions += 1;
|
|
1479
1659
|
if (sampledTexture)
|
|
@@ -1488,7 +1668,7 @@ export class WebGPUDevice {
|
|
|
1488
1668
|
this.nativePassthroughSubmissions += 1;
|
|
1489
1669
|
this.nativeTextureBindings += portableResources?.actualTextureCount ?? 0;
|
|
1490
1670
|
}
|
|
1491
|
-
if (shader.nativeUniformLayout === "generated-pbr" || shader.nativeUniformLayout === "generated-textured-pbr" || shader.nativeUniformLayout === "generated-instanced-pbr")
|
|
1671
|
+
if (shader.nativeUniformLayout === "generated-pbr" || shader.nativeUniformLayout === "generated-atlas-pbr" || shader.nativeUniformLayout === "generated-textured-pbr" || shader.nativeUniformLayout === "generated-instanced-pbr")
|
|
1492
1672
|
this.nativePbrSubmissions += 1;
|
|
1493
1673
|
if (shader.nativeUniformLayout === "generated-instanced-pbr")
|
|
1494
1674
|
this.nativeInstancedSubmissions += 1;
|
|
@@ -1496,6 +1676,7 @@ export class WebGPUDevice {
|
|
|
1496
1676
|
this.nativeSkinnedSubmissions += 1;
|
|
1497
1677
|
if (shader.nativeUniformLayout === "generated-morph-unlit")
|
|
1498
1678
|
this.nativeMorphSubmissions += 1;
|
|
1679
|
+
this.nativeTextureBindings += atlasResources?.actualTextureCount ?? 0;
|
|
1499
1680
|
if (materialTextures?.actualBaseColor)
|
|
1500
1681
|
this.nativeTextureBindings += 1;
|
|
1501
1682
|
if (materialTextures?.actualNormal)
|
|
@@ -1799,6 +1980,36 @@ export class WebGPUDevice {
|
|
|
1799
1980
|
this.device.queue.writeBuffer(buffer, 0, data);
|
|
1800
1981
|
return buffer;
|
|
1801
1982
|
}
|
|
1983
|
+
createNativeAtlasBindings(command) {
|
|
1984
|
+
const definitions = [
|
|
1985
|
+
["u_extensionScalarAtlas", 20, 0, "linear"],
|
|
1986
|
+
["u_clearcoatNormalTexture", 22, 21, "linear"],
|
|
1987
|
+
["u_sheenColorTexture", 24, 23, "srgb"],
|
|
1988
|
+
["u_anisotropyTexture", 26, 25, "linear"],
|
|
1989
|
+
["u_emissiveTexture", 28, 27, "srgb"]
|
|
1990
|
+
];
|
|
1991
|
+
const entries = [];
|
|
1992
|
+
let actualTextureCount = 0;
|
|
1993
|
+
for (const [name, textureIndex, samplerIndex, colorSpace] of definitions) {
|
|
1994
|
+
const actualTexture = this.createNativeSampledTextureBinding(uniformTextureBinding(command.uniforms, name));
|
|
1995
|
+
if (textureIndex === 20 && !actualTexture)
|
|
1996
|
+
throw new RenderDeviceError("Native extension atlas requires a resolved scalar atlas texture", "TEXTURE_BINDING_MISSING");
|
|
1997
|
+
const texture = actualTexture
|
|
1998
|
+
?? this.createNativeFallbackSampledTextureBinding(`atlas-${name}`, name.includes("Normal") ? [128, 128, 255, 255] : [255, 255, 255, 255], colorSpace);
|
|
1999
|
+
if (!texture)
|
|
2000
|
+
return null;
|
|
2001
|
+
if (texture.actual)
|
|
2002
|
+
actualTextureCount += 1;
|
|
2003
|
+
entries.push({ binding: textureIndex, resource: texture.view });
|
|
2004
|
+
if (samplerIndex)
|
|
2005
|
+
entries.push({ binding: samplerIndex, resource: texture.sampler });
|
|
2006
|
+
}
|
|
2007
|
+
const data = webgpuExtensionAtlasUniforms(command.uniforms);
|
|
2008
|
+
const buffer = this.device.createBuffer({ label: "extension-atlas-uniforms", size: data.byteLength, usage: BUFFER_USAGE.UNIFORM | BUFFER_USAGE.COPY_DST });
|
|
2009
|
+
this.device.queue.writeBuffer(buffer, 0, data);
|
|
2010
|
+
entries.push({ binding: 19, resource: { buffer } });
|
|
2011
|
+
return { buffer, entries, actualTextureCount };
|
|
2012
|
+
}
|
|
1802
2013
|
createNativePortableBindings(command, bindings) {
|
|
1803
2014
|
if (!this.device.createBindGroup)
|
|
1804
2015
|
return null;
|
|
@@ -2105,6 +2316,7 @@ function usesNativeDrawUniforms(layout) {
|
|
|
2105
2316
|
}
|
|
2106
2317
|
function usesNativePbrTextureBindings(layout) {
|
|
2107
2318
|
return layout === "generated-pbr" ||
|
|
2319
|
+
layout === "generated-atlas-pbr" ||
|
|
2108
2320
|
layout === "generated-textured-pbr" ||
|
|
2109
2321
|
layout === "generated-instanced-pbr";
|
|
2110
2322
|
}
|
|
@@ -2360,7 +2572,7 @@ function jointPaletteFor(uniforms) {
|
|
|
2360
2572
|
const count = Math.min(MAX_WEBGPU_SKINNING_JOINTS, Math.floor(length / 16));
|
|
2361
2573
|
return count > 0 ? uniformMat4Array(value, count) : [];
|
|
2362
2574
|
}
|
|
2363
|
-
function readVertexColor(bytes, stride, offset, vertexIndex) {
|
|
2575
|
+
function readVertexColor(bytes, stride, offset, vertexIndex, components = 4) {
|
|
2364
2576
|
if (offset === undefined)
|
|
2365
2577
|
return [1, 1, 1, 1];
|
|
2366
2578
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
@@ -2369,7 +2581,7 @@ function readVertexColor(bytes, stride, offset, vertexIndex) {
|
|
|
2369
2581
|
view.getFloat32(base, true),
|
|
2370
2582
|
view.getFloat32(base + 4, true),
|
|
2371
2583
|
view.getFloat32(base + 8, true),
|
|
2372
|
-
view.getFloat32(base + 12, true)
|
|
2584
|
+
components >= 4 ? view.getFloat32(base + 12, true) : 1
|
|
2373
2585
|
];
|
|
2374
2586
|
}
|
|
2375
2587
|
function readVertexUv(bytes, stride, offset, vertexIndex) {
|
|
@@ -2554,7 +2766,9 @@ function createNativeShaderSources(sources) {
|
|
|
2554
2766
|
return { ...nativeInstancedPbrShader(vertexEntry, fragmentEntry, sources.marker), entryPoints: [vertexEntry, fragmentEntry], uniformLayout: "generated-instanced-pbr" };
|
|
2555
2767
|
}
|
|
2556
2768
|
if (sources.marker.includes("pbr-textured")) {
|
|
2557
|
-
|
|
2769
|
+
const atlas = /uniform\s+sampler2D\s+u_extensionScalarAtlas/.test(sources.fragment);
|
|
2770
|
+
const native = nativeTexturedPbrShader(vertexEntry, fragmentEntry, sources.marker, nativeShaderUsesTangent(sources.vertex), atlas);
|
|
2771
|
+
return { ...native, ...(atlas ? { atlasVertex: native.vertex } : {}), entryPoints: [vertexEntry, fragmentEntry], uniformLayout: atlas ? "generated-atlas-pbr" : "generated-textured-pbr" };
|
|
2558
2772
|
}
|
|
2559
2773
|
if (sources.marker.includes("pbr-direct")) {
|
|
2560
2774
|
return sources.fragment.includes("u_baseColorTexture")
|
|
@@ -2568,20 +2782,89 @@ function createNativeShaderSources(sources) {
|
|
|
2568
2782
|
return { ...nativeMorphUnlitShader(vertexEntry, fragmentEntry, sources.marker), entryPoints: [vertexEntry, fragmentEntry], uniformLayout: "generated-morph-unlit" };
|
|
2569
2783
|
}
|
|
2570
2784
|
if (/sampler2D/.test(sources.fragment) && /layout\s*\(\s*location\s*=\s*2\s*\)\s*in\s+vec2/.test(sources.vertex)) {
|
|
2785
|
+
const colorInput = /layout\s*\(\s*location\s*=\s*(\d+)\s*\)\s*in\s+(?:lowp\s+|mediump\s+|highp\s+)?vec([34])\s+(?:a_color|color)\s*;/.exec(sources.vertex);
|
|
2786
|
+
const colorParameter = colorInput ? `, @location(${colorInput[1]}) vertexColor: vec${colorInput[2]}<f32>` : "";
|
|
2787
|
+
const drawUniforms = `struct DrawUniforms {
|
|
2788
|
+
modelViewProjection: mat4x4<f32>,
|
|
2789
|
+
color: vec4<f32>,
|
|
2790
|
+
};
|
|
2791
|
+
@group(0) @binding(0) var<uniform> u_draw: DrawUniforms;`;
|
|
2792
|
+
const vertexOutput = `struct VertexOutput {
|
|
2793
|
+
@builtin(position) position: vec4<f32>,
|
|
2794
|
+
@location(0) uv: vec2<f32>,
|
|
2795
|
+
${colorInput ? "@location(1) color: vec4<f32>," : ""}
|
|
2796
|
+
};`;
|
|
2797
|
+
const vertex = `// ${sources.marker}
|
|
2798
|
+
${drawUniforms}
|
|
2799
|
+
${vertexOutput}
|
|
2800
|
+
@vertex
|
|
2801
|
+
fn ${vertexEntry}(@location(0) position: vec3<f32>, @location(2) uv: vec2<f32>${colorParameter}) -> VertexOutput {
|
|
2802
|
+
var output: VertexOutput;
|
|
2803
|
+
let clipPosition = u_draw.modelViewProjection * vec4<f32>(position, 1.0);
|
|
2804
|
+
output.position = vec4<f32>(clipPosition.x, clipPosition.y, clipPosition.z * 0.5 + clipPosition.w * 0.5, clipPosition.w);
|
|
2805
|
+
output.uv = uv;
|
|
2806
|
+
${colorInput ? `output.color = ${colorInput[2] === "3" ? "vec4<f32>(vertexColor, 1.0)" : "vertexColor"};` : ""}
|
|
2807
|
+
return output;
|
|
2808
|
+
}
|
|
2809
|
+
`;
|
|
2571
2810
|
return {
|
|
2572
|
-
vertex
|
|
2573
|
-
|
|
2574
|
-
fragment: `// ${sources.marker}
|
|
2811
|
+
vertex,
|
|
2812
|
+
colorDefaultVertex: colorInput ? vertex.replace(colorParameter, "").replace(/output\.color = [^;]+;/, "output.color = vec4<f32>(1.0);") : undefined,
|
|
2813
|
+
fragment: `// ${sources.marker}
|
|
2814
|
+
${drawUniforms}
|
|
2815
|
+
${vertexOutput}
|
|
2816
|
+
@group(0) @binding(1) var u_textureSampler: sampler;
|
|
2817
|
+
@group(0) @binding(2) var u_texture: texture_2d<f32>;
|
|
2818
|
+
@fragment
|
|
2819
|
+
fn ${fragmentEntry}(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
2820
|
+
return u_draw.color * textureSample(u_texture, u_textureSampler, input.uv)${colorInput ? " * input.color" : ""};
|
|
2821
|
+
}
|
|
2822
|
+
`,
|
|
2575
2823
|
entryPoints: [vertexEntry, fragmentEntry],
|
|
2576
2824
|
uniformLayout: "generated-texture"
|
|
2577
2825
|
};
|
|
2578
2826
|
}
|
|
2827
|
+
// Basic GLSL programs (including unlit primitives and particle sprites)
|
|
2828
|
+
// declare their color input explicitly. Preserve that location and component
|
|
2829
|
+
// count; RGB inputs use opaque alpha, while RGBA alpha modulates the material.
|
|
2830
|
+
// Depth programs intentionally do not consume material/vertex color.
|
|
2831
|
+
const colorInput = sources.marker.includes(DEFAULT_DEPTH_SHADER_MARKER) ? null
|
|
2832
|
+
: /layout\s*\(\s*location\s*=\s*(\d+)\s*\)\s*in\s+(?:lowp\s+|mediump\s+|highp\s+)?vec([34])\s+(?:a_color|color)\s*;/.exec(sources.vertex);
|
|
2833
|
+
const colorParameter = colorInput ? `, @location(${colorInput[1]}) vertexColor: vec${colorInput[2]}<f32>` : "";
|
|
2834
|
+
const vertexOutput = `struct VertexOutput {
|
|
2835
|
+
@builtin(position) position: vec4<f32>,
|
|
2836
|
+
${colorInput ? "@location(0) color: vec4<f32>," : ""}
|
|
2837
|
+
};`;
|
|
2838
|
+
const drawUniforms = `struct DrawUniforms {
|
|
2839
|
+
modelViewProjection: mat4x4<f32>,
|
|
2840
|
+
color: vec4<f32>,
|
|
2841
|
+
};
|
|
2842
|
+
@group(0) @binding(0) var<uniform> u_draw: DrawUniforms;`;
|
|
2843
|
+
const vertex = `// ${sources.marker}
|
|
2844
|
+
${drawUniforms}
|
|
2845
|
+
${vertexOutput}
|
|
2846
|
+
@vertex
|
|
2847
|
+
fn ${vertexEntry}(@location(0) position: vec3<f32>${colorParameter}) -> VertexOutput {
|
|
2848
|
+
var output: VertexOutput;
|
|
2849
|
+
let clipPosition = u_draw.modelViewProjection * vec4<f32>(position, 1.0);
|
|
2850
|
+
output.position = vec4<f32>(clipPosition.x, clipPosition.y, clipPosition.z * 0.5 + clipPosition.w * 0.5, clipPosition.w);
|
|
2851
|
+
${colorInput ? `output.color = ${colorInput[2] === "3" ? "vec4<f32>(vertexColor, 1.0)" : "vertexColor"};` : ""}
|
|
2852
|
+
return output;
|
|
2853
|
+
}
|
|
2854
|
+
`;
|
|
2579
2855
|
return {
|
|
2580
|
-
vertex
|
|
2581
|
-
|
|
2856
|
+
vertex,
|
|
2857
|
+
colorDefaultVertex: colorInput ? vertex.replace(colorParameter, "").replace(/output\.color = [^;]+;/, "output.color = vec4<f32>(1.0);") : undefined,
|
|
2582
2858
|
fragment: sources.marker.includes(DEFAULT_DEPTH_SHADER_MARKER)
|
|
2583
2859
|
? nativeDepthFragment(sources.marker, fragmentEntry)
|
|
2584
|
-
: `// ${sources.marker}
|
|
2860
|
+
: `// ${sources.marker}
|
|
2861
|
+
${drawUniforms}
|
|
2862
|
+
${vertexOutput}
|
|
2863
|
+
@fragment
|
|
2864
|
+
fn ${fragmentEntry}(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
2865
|
+
return u_draw.color${colorInput ? " * input.color" : ""};
|
|
2866
|
+
}
|
|
2867
|
+
`,
|
|
2585
2868
|
entryPoints: [vertexEntry, fragmentEntry],
|
|
2586
2869
|
uniformLayout: "generated-basic"
|
|
2587
2870
|
};
|
|
@@ -2725,7 +3008,7 @@ fn a3dWebGPUClipPosition(clipPosition: vec4<f32>) -> vec4<f32> {
|
|
|
2725
3008
|
function nativeShaderUsesTangent(vertexSource) {
|
|
2726
3009
|
return /\ba_tangent\b/.test(vertexSource) || /layout\s*\(\s*location\s*=\s*3\s*\)\s*in\s+vec4/.test(vertexSource);
|
|
2727
3010
|
}
|
|
2728
|
-
function nativePbrFragmentPrelude(marker) {
|
|
3011
|
+
function nativePbrFragmentPrelude(marker, atlas = false) {
|
|
2729
3012
|
return `// ${marker}
|
|
2730
3013
|
${nativeUniformStruct()}
|
|
2731
3014
|
@group(0) @binding(1) var u_baseSampler: sampler;
|
|
@@ -2747,12 +3030,15 @@ ${nativeUniformStruct()}
|
|
|
2747
3030
|
@group(0) @binding(17) var u_spotShadowSampler: sampler;
|
|
2748
3031
|
@group(0) @binding(18) var u_spotShadowTexture: texture_2d<f32>;
|
|
2749
3032
|
|
|
3033
|
+
${atlas ? WEBGPU_EXTENSION_ATLAS_WGSL : ""}
|
|
3034
|
+
|
|
2750
3035
|
struct VertexOutput {
|
|
2751
3036
|
@builtin(position) position: vec4<f32>,
|
|
2752
3037
|
@location(0) normal: vec3<f32>,
|
|
2753
3038
|
@location(1) uv: vec2<f32>,
|
|
2754
3039
|
@location(2) worldPosition: vec3<f32>,
|
|
2755
3040
|
@location(3) tangent: vec4<f32>,
|
|
3041
|
+
${atlas ? "@location(4) uv1: vec2<f32>, @location(5) color: vec4<f32>," : ""}
|
|
2756
3042
|
};
|
|
2757
3043
|
|
|
2758
3044
|
fn fresnelSchlick(cosTheta: f32, f0: vec3<f32>) -> vec3<f32> {
|
|
@@ -2765,14 +3051,16 @@ fn fresnelSchlickRoughness(cosTheta: f32, f0: vec3<f32>, roughness: f32) -> vec3
|
|
|
2765
3051
|
}
|
|
2766
3052
|
|
|
2767
3053
|
fn ggxDistribution(nDotH: f32, roughness: f32) -> f32 {
|
|
2768
|
-
let a = max(roughness * roughness, 0.045);
|
|
3054
|
+
let a = ${atlas ? "max(roughness, 0.045) * max(roughness, 0.045)" : "max(roughness * roughness, 0.045)"};
|
|
2769
3055
|
let a2 = a * a;
|
|
2770
|
-
|
|
2771
|
-
|
|
3056
|
+
// At roughness .045 the true denominator before squaring is ~4.1e-6.
|
|
3057
|
+
// A .001/.00001 floor destroys the normalized low-roughness GGX lobe.
|
|
3058
|
+
let denom = max((nDotH * nDotH) * (a2 - 1.0) + 1.0, ${atlas ? "0.00000001" : "0.001"});
|
|
3059
|
+
return a2 / max(3.14159265 * denom * denom, ${atlas ? "0.0000000000000001" : "0.001"});
|
|
2772
3060
|
}
|
|
2773
3061
|
|
|
2774
3062
|
fn ggxVisibilitySmithCorrelated(nDotV: f32, nDotL: f32, roughness: f32) -> f32 {
|
|
2775
|
-
let a = max(roughness * roughness, 0.045);
|
|
3063
|
+
let a = ${atlas ? "max(roughness, 0.045) * max(roughness, 0.045)" : "max(roughness * roughness, 0.045)"};
|
|
2776
3064
|
let a2 = a * a;
|
|
2777
3065
|
let lambdaV = nDotL * sqrt(max((nDotV - a2 * nDotV) * nDotV + a2, 0.00001));
|
|
2778
3066
|
let lambdaL = nDotV * sqrt(max((nDotL - a2 * nDotL) * nDotL + a2, 0.00001));
|
|
@@ -2898,18 +3186,18 @@ fn a3dNativeShadowFactor(worldPosition: vec3<f32>, normal: vec3<f32>, lightDirec
|
|
|
2898
3186
|
return mix(1.0, 1.0 - occlusion, clamp(strength, 0.0, 1.0));
|
|
2899
3187
|
}
|
|
2900
3188
|
|
|
2901
|
-
fn shadePbr(normalInput: vec3<f32>, tangentFrame: vec4<f32>, uv: vec2<f32>, worldPosition: vec3<f32>, fragmentPosition: vec2<f32>) -> vec4<f32> {
|
|
3189
|
+
fn shadePbr(normalInput: vec3<f32>, tangentFrame: vec4<f32>, uv: vec2<f32>, worldPosition: vec3<f32>, fragmentPosition: vec2<f32>${atlas ? ", uv1: vec2<f32>, vertexColor: vec4<f32>" : ""}) -> vec4<f32> {
|
|
2902
3190
|
var normal = normalize(normalInput);
|
|
2903
3191
|
if (u_draw.morph0.x > 0.5) {
|
|
2904
|
-
normal = perturbNormal(normal, tangentFrame, textureSample(u_normalTexture, u_normalSampler, uv).rgb, u_draw.morph0.y);
|
|
3192
|
+
normal = perturbNormal(normal, tangentFrame, textureSample(u_normalTexture, u_normalSampler, ${atlas ? "atlasUv(1u, uv, uv1)" : "uv"}).rgb, u_draw.morph0.y);
|
|
2905
3193
|
}
|
|
2906
3194
|
let viewDirection = normalize(u_draw.camera.xyz - worldPosition);
|
|
2907
3195
|
let lightDirection = normalize(vec3<f32>(0.36, 0.52, 0.78));
|
|
2908
3196
|
let halfVector = normalize(lightDirection + viewDirection);
|
|
2909
|
-
var baseColor = u_draw.color.rgb;
|
|
2910
|
-
var materialAlpha = u_draw.color.a;
|
|
3197
|
+
var baseColor = u_draw.color.rgb${atlas ? " * vertexColor.rgb" : ""};
|
|
3198
|
+
var materialAlpha = u_draw.color.a${atlas ? " * vertexColor.a" : ""};
|
|
2911
3199
|
if (u_draw.flags.x > 0.5) {
|
|
2912
|
-
let baseSample = textureSample(u_baseTexture, u_baseSampler, uv);
|
|
3200
|
+
let baseSample = textureSample(u_baseTexture, u_baseSampler, ${atlas ? "atlasUv(0u, uv, uv1)" : "uv"});
|
|
2913
3201
|
baseColor = baseColor * baseSample.rgb;
|
|
2914
3202
|
materialAlpha = materialAlpha * baseSample.a;
|
|
2915
3203
|
}
|
|
@@ -2918,16 +3206,14 @@ fn shadePbr(normalInput: vec3<f32>, tangentFrame: vec4<f32>, uv: vec2<f32>, worl
|
|
|
2918
3206
|
let productBodyGate = productPropBodyGate(sourceProductBaseColor, u_draw.materialFlags.z) * (1.0 - productOrangeGate * 0.92);
|
|
2919
3207
|
let productSurfaceGate = clamp(productBodyGate + productOrangeGate * 0.72, 0.0, 1.0);
|
|
2920
3208
|
baseColor = productPropAlbedo(sourceProductBaseColor, u_draw.materialFlags.z);
|
|
2921
|
-
if (materialAlpha < u_draw.material.x) {
|
|
2922
|
-
discard;
|
|
2923
|
-
}
|
|
3209
|
+
${atlas ? "" : "if (materialAlpha < u_draw.material.x) { discard; }"}
|
|
2924
3210
|
let transmission = clamp(max(u_draw.material.y, u_draw.material.z), 0.0, 1.0);
|
|
2925
|
-
let metallicRoughnessSample = textureSample(u_metallicRoughnessTexture, u_metallicRoughnessSampler, uv);
|
|
3211
|
+
let metallicRoughnessSample = textureSample(u_metallicRoughnessTexture, u_metallicRoughnessSampler, ${atlas ? "atlasUv(2u, uv, uv1)" : "uv"});
|
|
2926
3212
|
let metallicRoughnessEnabled = step(0.5, u_draw.materialFlags.x);
|
|
2927
3213
|
let occlusionEnabled = step(0.5, u_draw.materialFlags.y);
|
|
2928
3214
|
let sampledMetallic = clamp(u_draw.params.x * metallicRoughnessSample.b, 0.0, 1.0);
|
|
2929
3215
|
let sampledRoughness = clamp(u_draw.params.y * metallicRoughnessSample.g, 0.045, 1.0);
|
|
2930
|
-
let sampledOcclusion = mix(1.0, textureSample(u_occlusionTexture, u_occlusionSampler, uv).r, clamp(u_draw.morph0.z, 0.0, 1.0));
|
|
3216
|
+
let sampledOcclusion = mix(1.0, textureSample(u_occlusionTexture, u_occlusionSampler, ${atlas ? "atlasUv(3u, uv, uv1)" : "uv"}).r, clamp(u_draw.morph0.z, 0.0, 1.0));
|
|
2931
3217
|
let metallic = mix(clamp(u_draw.params.x, 0.0, 1.0), sampledMetallic, metallicRoughnessEnabled);
|
|
2932
3218
|
let roughness = mix(clamp(u_draw.params.y, 0.045, 1.0), sampledRoughness, metallicRoughnessEnabled);
|
|
2933
3219
|
let occlusion = mix(1.0, sampledOcclusion, occlusionEnabled);
|
|
@@ -2937,16 +3223,23 @@ fn shadePbr(normalInput: vec3<f32>, tangentFrame: vec4<f32>, uv: vec2<f32>, worl
|
|
|
2937
3223
|
let nDotV = max(dot(normal, viewDirection), 0.001);
|
|
2938
3224
|
let nDotH = max(dot(normal, halfVector), 0.001);
|
|
2939
3225
|
let vDotH = max(dot(viewDirection, halfVector), 0.001);
|
|
2940
|
-
let
|
|
3226
|
+
let dielectricF0 = ${atlas ? "vec3<f32>(pow((u_atlas.substrate.x-1.0)/(u_atlas.substrate.x+1.0),2.0)) * clamp(u_atlas.specularColor.rgb,vec3<f32>(0.0),vec3<f32>(1.0)) * clamp(u_atlas.substrate.y,0.0,1.0)" : "vec3<f32>(0.04, 0.04, 0.04)"};
|
|
3227
|
+
let f0 = mix(dielectricF0, baseColor, metallic);
|
|
2941
3228
|
let fresnel = fresnelSchlick(vDotH, f0);
|
|
2942
3229
|
let distribution = ggxDistribution(nDotH, roughness);
|
|
2943
3230
|
let visibility = ggxVisibilitySmithCorrelated(nDotV, nDotL, roughness);
|
|
2944
3231
|
let lDotH = max(dot(lightDirection, halfVector), 0.0);
|
|
2945
|
-
|
|
3232
|
+
${atlas ? `// The film replaces the substrate Fresnel in the dielectric energy split.
|
|
3233
|
+
// Retaining the old kd while adding film specular creates or loses energy.
|
|
3234
|
+
let filmFresnel = atlasIridescenceFresnel(f0, vDotH, uv, uv1);
|
|
3235
|
+
let filmMaximum = max(max(filmFresnel.r, filmFresnel.g), filmFresnel.b);
|
|
3236
|
+
let diffuseFresnel = select(fresnel, vec3<f32>(filmMaximum), u_atlas.iridescence.y > 0.0);
|
|
3237
|
+
let kd = (vec3<f32>(1.0) - diffuseFresnel) * (1.0 - metallic);` : "let kd = (vec3<f32>(1.0, 1.0, 1.0) - fresnel) * (1.0 - metallic);"}
|
|
2946
3238
|
let specular = fresnel * distribution * visibility;
|
|
2947
3239
|
let diffuse = kd * baseColor * diffuseBurley(nDotV, nDotL, lDotH, roughness) / 3.14159265;
|
|
2948
3240
|
var environment = baseColor * u_draw.params.z * (0.28 + 0.72 * clamp(normal.y * 0.5 + 0.5, 0.0, 1.0)) * occlusion;
|
|
2949
3241
|
var environmentSpecularContribution = vec3<f32>(0.0, 0.0, 0.0);
|
|
3242
|
+
var environmentExtensionRadiance = vec3<f32>(0.0);
|
|
2950
3243
|
if (u_draw.flags.w > 0.5) {
|
|
2951
3244
|
let reflectionDirection = reflect(-viewDirection, normal);
|
|
2952
3245
|
let diffuseUv = vec2<f32>(fract(atan2(normal.z, normal.x) / 6.2831853 + 0.5), acos(clamp(normal.y, -1.0, 1.0)) / 3.14159265);
|
|
@@ -2957,8 +3250,10 @@ fn shadePbr(normalInput: vec3<f32>, tangentFrame: vec4<f32>, uv: vec2<f32>, worl
|
|
|
2957
3250
|
let brdf = textureSampleLevel(u_brdfTexture, u_brdfSampler, vec2<f32>(nDotV, roughness), 0.0).rg;
|
|
2958
3251
|
let environmentFresnel = fresnelSchlickRoughness(nDotV, f0, roughness);
|
|
2959
3252
|
let environmentDiffuse = (vec3<f32>(1.0, 1.0, 1.0) - environmentFresnel) * (1.0 - metallic) * diffuseEnv * baseColor * u_draw.params.w * occlusion;
|
|
2960
|
-
let
|
|
3253
|
+
${atlas ? "let environmentF0 = atlasIridescenceEnvironmentF0(f0, nDotV, uv, uv1);" : "let environmentF0 = f0;"}
|
|
3254
|
+
let environmentSpecular = specularEnv * (environmentF0 * brdf.x + vec3<f32>(brdf.y, brdf.y, brdf.y)) * max(u_draw.reserved0.w, 0.0);
|
|
2961
3255
|
environmentSpecularContribution = environmentSpecular;
|
|
3256
|
+
environmentExtensionRadiance = specularEnv * max(u_draw.reserved0.w, 0.0);
|
|
2962
3257
|
environment = environment + environmentDiffuse + environmentSpecular;
|
|
2963
3258
|
}
|
|
2964
3259
|
// J2 native shadow projections: directional PCF mirrors GLSL
|
|
@@ -2998,7 +3293,8 @@ fn shadePbr(normalInput: vec3<f32>, tangentFrame: vec4<f32>, uv: vec2<f32>, worl
|
|
|
2998
3293
|
}
|
|
2999
3294
|
}
|
|
3000
3295
|
let legacyDirect = (diffuse + specular) * nDotL * 2.25 * shadow;
|
|
3001
|
-
let litOpaqueLinearColor = environment + select(legacyDirect, clusteredDirect, u_draw.materialFlags.w > 0.5)
|
|
3296
|
+
let litOpaqueLinearColor = environment + select(legacyDirect, clusteredDirect, u_draw.materialFlags.w > 0.5)
|
|
3297
|
+
${atlas ? "+ atlasExtensionLighting(normal, tangentFrame, viewDirection, lightDirection, uv, uv1, shadow, environmentExtensionRadiance, f0, roughness) + u_atlas.emissive.rgb * u_atlas.factors.y * mix(vec3<f32>(1.0), textureSample(u_emissiveTexture, u_emissiveSampler, atlasUv(4u, uv, uv1)).rgb, u_atlas.maps[4].control.z)" : ""};
|
|
3002
3298
|
let smoothedBodyColor = mix(baseColor, vec3<f32>(1.0, 0.88, 0.012), productBodyGate * 0.32);
|
|
3003
3299
|
let smoothedBeakColor = mix(baseColor, vec3<f32>(1.0, 0.24, 0.018), productOrangeGate * 0.82);
|
|
3004
3300
|
let softBodyProduct = smoothedBodyColor * (1.5 + 0.06 * nDotL) + specular * nDotL * 0.018;
|
|
@@ -3008,6 +3304,7 @@ fn shadePbr(normalInput: vec3<f32>, tangentFrame: vec4<f32>, uv: vec2<f32>, worl
|
|
|
3008
3304
|
let transmittedTint = baseColor * u_draw.params.w * (0.18 + 0.42 * clamp(1.0 - roughness, 0.0, 1.0)) + environmentSpecularContribution * 1.35;
|
|
3009
3305
|
let linearColor = mix(opaqueLinearColor, opaqueLinearColor * 0.22 + transmittedTint, transmission);
|
|
3010
3306
|
let outputAlpha = mix(materialAlpha, min(materialAlpha, 0.22), transmission);
|
|
3307
|
+
${atlas ? "if (materialAlpha < u_draw.material.x) { discard; }" : ""}
|
|
3011
3308
|
return vec4<f32>(encodePbrOutput(linearColor), outputAlpha);
|
|
3012
3309
|
}
|
|
3013
3310
|
`;
|
|
@@ -3044,7 +3341,7 @@ fn ${fragmentEntry}(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
3044
3341
|
`
|
|
3045
3342
|
};
|
|
3046
3343
|
}
|
|
3047
|
-
function nativeTexturedPbrShader(vertexEntry, fragmentEntry, marker, usesTangent) {
|
|
3344
|
+
function nativeTexturedPbrShader(vertexEntry, fragmentEntry, marker, usesTangent, atlas = false) {
|
|
3048
3345
|
return {
|
|
3049
3346
|
vertex: `// ${marker}
|
|
3050
3347
|
${nativeUniformStruct()}
|
|
@@ -3054,24 +3351,26 @@ struct VertexOutput {
|
|
|
3054
3351
|
@location(1) uv: vec2<f32>,
|
|
3055
3352
|
@location(2) worldPosition: vec3<f32>,
|
|
3056
3353
|
@location(3) tangent: vec4<f32>,
|
|
3354
|
+
${atlas ? "@location(4) uv1: vec2<f32>, @location(5) color: vec4<f32>," : ""}
|
|
3057
3355
|
};
|
|
3058
3356
|
|
|
3059
3357
|
@vertex
|
|
3060
|
-
fn ${vertexEntry}(@location(0) position: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) uv: vec2<f32>${usesTangent ? ", @location(3) tangent: vec4<f32>" : ""}) -> VertexOutput {
|
|
3358
|
+
fn ${vertexEntry}(@location(0) position: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) uv: vec2<f32>${usesTangent ? ", @location(3) tangent: vec4<f32>" : ""}${atlas ? ", @location(4) color: vec4<f32>, @location(7) uv1: vec2<f32>" : ""}) -> VertexOutput {
|
|
3061
3359
|
var output: VertexOutput;
|
|
3062
3360
|
let worldPosition = (u_draw.instance0 * vec4<f32>(position, 1.0)).xyz;
|
|
3063
3361
|
output.position = a3dWebGPUClipPosition(u_draw.modelViewProjection * vec4<f32>(position, 1.0));
|
|
3064
3362
|
output.normal = normalize((u_draw.normalMatrix * vec4<f32>(normal, 0.0)).xyz);
|
|
3065
3363
|
output.uv = uv;
|
|
3364
|
+
${atlas ? "output.uv1 = uv1; output.color = color;" : ""}
|
|
3066
3365
|
output.worldPosition = worldPosition;
|
|
3067
3366
|
${usesTangent ? "output.tangent = vec4<f32>(normalize((u_draw.normalMatrix * vec4<f32>(tangent.xyz, 0.0)).xyz), tangent.w);" : "output.tangent = vec4<f32>(1.0, 0.0, 0.0, 1.0);"}
|
|
3068
3367
|
return output;
|
|
3069
3368
|
}
|
|
3070
3369
|
`,
|
|
3071
|
-
fragment: `${nativePbrFragmentPrelude(marker)}
|
|
3370
|
+
fragment: `${nativePbrFragmentPrelude(marker, atlas)}
|
|
3072
3371
|
@fragment
|
|
3073
3372
|
fn ${fragmentEntry}(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
3074
|
-
return shadePbr(input.normal, input.tangent, input.uv, input.worldPosition, input.position.xy);
|
|
3373
|
+
return shadePbr(input.normal, input.tangent, input.uv, input.worldPosition, input.position.xy${atlas ? ", input.uv1, input.color" : ""});
|
|
3075
3374
|
}
|
|
3076
3375
|
`
|
|
3077
3376
|
};
|