@babylonjs/lite 1.4.0 → 1.6.0
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/dist/index.js +512 -512
- package/dist/index.js.map +1 -1
- package/index.d.ts +829 -28
- package/lib/audio/analyzer.js +65 -0
- package/lib/audio/analyzer.js.map +1 -0
- package/lib/audio/audio-bus.js +38 -0
- package/lib/audio/audio-bus.js.map +1 -0
- package/lib/audio/audio-engine.js +188 -0
- package/lib/audio/audio-engine.js.map +1 -0
- package/lib/audio/audio-fetch.js +18 -0
- package/lib/audio/audio-fetch.js.map +1 -0
- package/lib/audio/audio-param.js +96 -0
- package/lib/audio/audio-param.js.map +1 -0
- package/lib/audio/audio-signal.js +46 -0
- package/lib/audio/audio-signal.js.map +1 -0
- package/lib/audio/bus.js +33 -0
- package/lib/audio/bus.js.map +1 -0
- package/lib/audio/host-types.js +2 -0
- package/lib/audio/host-types.js.map +1 -0
- package/lib/audio/index.js +12 -0
- package/lib/audio/index.js.map +1 -0
- package/lib/audio/sound-buffer.js +59 -0
- package/lib/audio/sound-buffer.js.map +1 -0
- package/lib/audio/sound-source.js +57 -0
- package/lib/audio/sound-source.js.map +1 -0
- package/lib/audio/sound-sub-graph.js +72 -0
- package/lib/audio/sound-sub-graph.js.map +1 -0
- package/lib/audio/spatial.js +466 -0
- package/lib/audio/spatial.js.map +1 -0
- package/lib/audio/static-sound.js +313 -0
- package/lib/audio/static-sound.js.map +1 -0
- package/lib/audio/stereo.js +40 -0
- package/lib/audio/stereo.js.map +1 -0
- package/lib/audio/streaming-sound.js +377 -0
- package/lib/audio/streaming-sound.js.map +1 -0
- package/lib/audio/unmute-ui.js +72 -0
- package/lib/audio/unmute-ui.js.map +1 -0
- package/lib/audio/visualizer.js +101 -0
- package/lib/audio/visualizer.js.map +1 -0
- package/lib/camera/geospatial-camera-controls.js +22 -0
- package/lib/camera/geospatial-camera-controls.js.map +1 -1
- package/lib/camera/geospatial-camera-fly.js +2 -1
- package/lib/camera/geospatial-camera-fly.js.map +1 -1
- package/lib/effect/effect-renderer.js +1 -1
- package/lib/effect/effect-renderer.js.map +1 -1
- package/lib/engine/engine.js +1 -1
- package/lib/index.js +15 -1
- package/lib/index.js.map +1 -1
- package/lib/light/types.js.map +1 -1
- package/lib/loader-gltf/animation-pointer-basecolor.js +25 -0
- package/lib/loader-gltf/animation-pointer-basecolor.js.map +1 -0
- package/lib/loader-gltf/animation-pointer-ext.js +244 -0
- package/lib/loader-gltf/animation-pointer-ext.js.map +1 -0
- package/lib/loader-gltf/animation-pointer-lights.js +46 -0
- package/lib/loader-gltf/animation-pointer-lights.js.map +1 -0
- package/lib/loader-gltf/animation-pointer.js +4 -1
- package/lib/loader-gltf/animation-pointer.js.map +1 -1
- package/lib/loader-gltf/gltf-animation.js +5 -3
- package/lib/loader-gltf/gltf-animation.js.map +1 -1
- package/lib/loader-gltf/gltf-color-normalize.js +10 -1
- package/lib/loader-gltf/gltf-color-normalize.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-animation-pointer.js +67 -47
- package/lib/loader-gltf/gltf-feature-animation-pointer.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-lights-punctual.js +51 -9
- package/lib/loader-gltf/gltf-feature-lights-punctual.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-primitive.js +20 -0
- package/lib/loader-gltf/gltf-feature-primitive.js.map +1 -0
- package/lib/loader-gltf/gltf-feature-registry.js +25 -0
- package/lib/loader-gltf/gltf-feature-registry.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-skeleton.js +18 -3
- package/lib/loader-gltf/gltf-feature-skeleton.js.map +1 -1
- package/lib/loader-gltf/gltf-interleave.js +3 -2
- package/lib/loader-gltf/gltf-interleave.js.map +1 -1
- package/lib/loader-gltf/gltf-light-pointer-state.js +18 -0
- package/lib/loader-gltf/gltf-light-pointer-state.js.map +1 -0
- package/lib/loader-gltf/gltf-parser.js +7 -1
- package/lib/loader-gltf/gltf-parser.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder-ext.js +1 -1
- package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder.js +1 -1
- package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
- package/lib/loader-gltf/gltf-sampler-denorm.js +20 -0
- package/lib/loader-gltf/gltf-sampler-denorm.js.map +1 -0
- package/lib/loader-gltf/gltf-sampler-desc.js +11 -2
- package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
- package/lib/loader-gltf/gltf-uv-denorm.js +28 -0
- package/lib/loader-gltf/gltf-uv-denorm.js.map +1 -0
- package/lib/loader-gltf/load-gltf.js +15 -6
- package/lib/loader-gltf/load-gltf.js.map +1 -1
- package/lib/material/material-rebuild.js +4 -0
- package/lib/material/material-rebuild.js.map +1 -1
- package/lib/material/mesh-features.js +8 -1
- package/lib/material/mesh-features.js.map +1 -1
- package/lib/material/pbr/fragments/reflectance-fragment.js +1 -1
- package/lib/material/pbr/fragments/reflectance-fragment.js.map +1 -1
- package/lib/material/pbr/fragments/refraction-rtt-fragment.js +1 -1
- package/lib/material/pbr/fragments/refraction-rtt-fragment.js.map +1 -1
- package/lib/material/pbr/pbr-pipeline.js +7 -3
- package/lib/material/pbr/pbr-pipeline.js.map +1 -1
- package/lib/material/pbr/pbr-primitive-resolver.js +34 -0
- package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -0
- package/lib/material/pbr/pbr-renderable.js +1 -1
- package/lib/material/pbr/pbr-renderable.js.map +1 -1
- package/lib/material/shader/shader-material.js +9 -5
- package/lib/material/shader/shader-material.js.map +1 -1
- package/lib/material/shader/shader-thin-instance.js +1 -1
- package/lib/material/shader/shader-thin-instance.js.map +1 -1
- package/lib/material/standard/standard-renderable.js +1 -1
- package/lib/material/standard/standard-renderable.js.map +1 -1
- package/lib/mesh/mesh-dispose.js +1 -0
- package/lib/mesh/mesh-dispose.js.map +1 -1
- package/lib/mesh/thin-instance-cull-binding.js +15 -6
- package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
- package/lib/post-process/taa.js +193 -0
- package/lib/post-process/taa.js.map +1 -0
- package/lib/scene/scene-core.js +1 -0
- package/lib/scene/scene-core.js.map +1 -1
- package/lib/scene/scene-material-swap.js +2 -0
- package/lib/scene/scene-material-swap.js.map +1 -1
- package/lib/shadow/csm-shadow-task-hooks.js +67 -9
- package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
- package/lib/sprite/billboard-custom-shader.js +32 -32
- package/lib/sprite/billboard-custom-shader.js.map +1 -1
- package/lib/sprite/billboard-pipeline.js +54 -56
- package/lib/sprite/billboard-pipeline.js.map +1 -1
- package/lib/sprite/custom-shader-core.js +1 -1
- package/lib/sprite/custom-shader-core.js.map +1 -1
- package/lib/sprite/shared/sprite-atlas.js +2 -2
- package/lib/sprite/shared/sprite-atlas.js.map +1 -1
- package/lib/sprite/sprite-2d-coverage-gamma.js +58 -0
- package/lib/sprite/sprite-2d-coverage-gamma.js.map +1 -0
- package/lib/sprite/sprite-2d-uvscroll.js +39 -0
- package/lib/sprite/sprite-2d-uvscroll.js.map +1 -0
- package/lib/sprite/sprite-2d.js +6 -36
- package/lib/sprite/sprite-2d.js.map +1 -1
- package/lib/sprite/sprite-coverage-gamma-hook.js +10 -0
- package/lib/sprite/sprite-coverage-gamma-hook.js.map +1 -0
- package/lib/sprite/sprite-custom-shader.js +2 -2
- package/lib/sprite/sprite-custom-shader.js.map +1 -1
- package/lib/sprite/sprite-pipeline.js +61 -73
- package/lib/sprite/sprite-pipeline.js.map +1 -1
- package/lib/sprite/sprite-renderable.js +5 -5
- package/lib/sprite/sprite-renderable.js.map +1 -1
- package/lib/sprite/sprite-renderer.js +4 -4
- package/lib/sprite/sprite-renderer.js.map +1 -1
- package/lib/sprite/sprite-scene.js +1 -1
- package/lib/sprite/sprite-scene.js.map +1 -1
- package/lib/text/_gpu/text-pipeline.js +1 -1
- package/lib/text/_gpu/text-pipeline.js.map +1 -1
- package/lib/text/text-renderer.js +3 -1
- package/lib/text/text-renderer.js.map +1 -1
- package/package.json +3 -3
|
@@ -95,7 +95,7 @@ function createShaderInstancedRenderable(scene, material, packet, isOverride, h,
|
|
|
95
95
|
const bindings = h.getOrCreateShaderPipelineBindings(eng, material);
|
|
96
96
|
const vertexBuffers = [...bindings.vertexBuffers, ...instanceLayouts];
|
|
97
97
|
const pipeline = h.getOrCreateShaderPipeline(eng, sig, material, bindings, variantKey, vertexBuffers, instanceAttrs);
|
|
98
|
-
const cb = cull?.tryBind(r, scene, mesh, eng, hasColor, isTransparent, update);
|
|
98
|
+
const cb = cull?.tryBind(r, scene, mesh, eng, hasColor, isTransparent, update, sig);
|
|
99
99
|
return {
|
|
100
100
|
renderable: r,
|
|
101
101
|
pipeline,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader-thin-instance.js","sources":["../../../../src/material/shader/shader-thin-instance.ts"],"sourcesContent":["/** ShaderMaterial thin-instance support — dynamically imported ONLY when a\n * ShaderMaterial scene actually uses thin instances, so non-instanced scenes pull\n * in zero extra bytes and the shared `shader-renderable.ts` / `shader-pipeline.ts`\n * chunks stay identical to their non-instanced form.\n *\n * The renderable helpers this module needs (packet create/update, attribute\n * buffers, pipeline builders, the plain-mesh builder) are passed in as positional\n * arguments by `buildShaderGroup`, NOT imported. Importing them would force the\n * shared chunk to export them, which de-mangles their names and grows every\n * ShaderMaterial scene's bundle. As parameters they keep their mangled identity in\n * the shared chunk and are only named here, in this culling/instancing-only chunk.\n *\n * The instance buffer layout MUST match the buffers produced by\n * `thin-instance-gpu.ts` (matrix buffer arrayStride 64, 4x float32x4 at offsets\n * 0/16/32/48; color buffer arrayStride 16, float32x4 at offset 0). */\n\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { Material } from \"../material.js\";\nimport type { Mesh, MeshGPU } from \"../../mesh/mesh.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport type { UboSpec } from \"../../shader/fragment-types.js\";\nimport type { DrawUpdateContext, MeshGroupBuildResult, Renderable } from \"../../render/renderable.js\";\nimport type { ShaderAttributeName, ShaderMaterial } from \"./shader-material.js\";\nimport type { ShaderPipelineBindings } from \"./shader-pipeline.js\";\nimport type { ShaderPacket, ShaderRenderPass } from \"./shader-renderable.js\";\nimport { syncThinInstanceBuffers } from \"../../mesh/thin-instance-gpu.js\";\n\ntype CullModule = typeof import(\"../../mesh/thin-instance-cull-binding.js\");\n\n/** The shader-renderable helpers handed in positionally by `buildShaderGroup`. */\ninterface ShaderHelpers {\n buildPlain: (scene: SceneContext, meshes: Mesh[]) => MeshGroupBuildResult;\n createPacket: (scene: SceneContext, material: ShaderMaterial, systemSpec: UboSpec, mesh: Mesh) => ShaderPacket;\n updatePacket: (scene: SceneContext, material: ShaderMaterial, packet: ShaderPacket, context: DrawUpdateContext) => void;\n updateCustomUbo: (engine: EngineContext, material: ShaderMaterial) => void;\n getAttrBuffer: (engine: EngineContext, gpu: MeshGPU, name: ShaderAttributeName) => GPUBuffer;\n getOrCreateShaderPipeline: (\n engine: EngineContext,\n sig: RenderTargetSignature,\n material: ShaderMaterial,\n bindings: ShaderPipelineBindings,\n variantKey?: string,\n vertexBuffers?: readonly GPUVertexBufferLayout[],\n instanceAttrs?: string\n ) => GPURenderPipeline;\n getOrCreateShaderPipelineBindings: (engine: EngineContext, material: ShaderMaterial) => ShaderPipelineBindings;\n}\n\n/** Instance vertex buffer layouts. `baseLocation` is the first free shader\n * location after the material's own attributes. */\nfunction instanceVertexLayouts(baseLocation: number, hasColor: boolean): GPUVertexBufferLayout[] {\n const layouts: GPUVertexBufferLayout[] = [\n {\n arrayStride: 64,\n stepMode: \"instance\",\n attributes: [\n { shaderLocation: baseLocation, offset: 0, format: \"float32x4\" },\n { shaderLocation: baseLocation + 1, offset: 16, format: \"float32x4\" },\n { shaderLocation: baseLocation + 2, offset: 32, format: \"float32x4\" },\n { shaderLocation: baseLocation + 3, offset: 48, format: \"float32x4\" },\n ],\n },\n ];\n if (hasColor) {\n layouts.push({\n arrayStride: 16,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: baseLocation + 4, offset: 0, format: \"float32x4\" }],\n });\n }\n return layouts;\n}\n\n/** WGSL lines appended inside `VertexInput` for instanced variants. */\nfunction instancePreludeAttributes(baseLocation: number, hasColor: boolean): string {\n let wgsl = `@location(${baseLocation}) world0: vec4<f32>,\n@location(${baseLocation + 1}) world1: vec4<f32>,\n@location(${baseLocation + 2}) world2: vec4<f32>,\n@location(${baseLocation + 3}) world3: vec4<f32>,\n`;\n if (hasColor) {\n wgsl += `@location(${baseLocation + 4}) instanceColor: vec4<f32>,\n`;\n }\n return wgsl;\n}\n\n/** Build ONE thin-instance renderable for a ShaderMaterial mesh (opaque or\n * transparent). Marked `_direct` so instance buffers are re-bound fresh each\n * frame; this also prepares the renderable for opaque-only GPU culling. */\nfunction createShaderInstancedRenderable(\n scene: SceneContext,\n material: ShaderMaterial,\n packet: ShaderPacket,\n isOverride: boolean,\n h: ShaderHelpers,\n cull?: CullModule\n): Renderable {\n const isTransparent = material.needAlphaBlending;\n const mesh = packet.mesh;\n const ti = mesh.thinInstances!;\n const hasColor = !!ti.colors;\n const baseLocation = material.attributes.length;\n const instanceLayouts = instanceVertexLayouts(baseLocation, hasColor);\n const instanceAttrs = instancePreludeAttributes(baseLocation, hasColor);\n const variantKey = `|ti1c${hasColor ? 1 : 0}`;\n const wm = mesh.worldMatrix as unknown as ArrayLike<number>;\n const sortCenter: [number, number, number] = [wm[12]!, wm[13]!, wm[14]!];\n const update = (context: DrawUpdateContext): void => {\n if (packet._disposed) {\n return;\n }\n if (!isOverride && mesh.material !== material) {\n return;\n }\n h.updateCustomUbo(scene.surface.engine, material);\n h.updatePacket(scene, material, packet, context);\n if (isTransparent) {\n const m = mesh.worldMatrix as unknown as ArrayLike<number>;\n sortCenter[0] = m[12]!;\n sortCenter[1] = m[13]!;\n sortCenter[2] = m[14]!;\n }\n };\n const draw = (pass: ShaderRenderPass, engine: EngineContext, cullBinding?: import(\"../../mesh/thin-instance-cull-binding.js\").TiCullBinding): number => {\n if (packet._disposed) {\n return 0;\n }\n if (!isOverride && mesh.material !== material) {\n return 0;\n }\n if (ti.count <= 0) {\n return 0;\n }\n const gpu = mesh._gpu;\n let slot = 0;\n for (let i = 0; i < material.attributes.length; i++) {\n pass.setVertexBuffer(slot++, h.getAttrBuffer(engine, gpu, material.attributes[i]!));\n }\n slot = syncThinInstanceBuffers(engine, ti, pass, slot, hasColor, cullBinding?.cullDrawBufs);\n pass.setIndexBuffer(gpu.indexBuffer, gpu.indexFormat);\n pass.setBindGroup(1, packet._bindGroup);\n if (cullBinding) {\n cullBinding.draw(pass, gpu.indexCount, ti.count);\n } else {\n pass.drawIndexed(gpu.indexCount, ti.count);\n }\n return 1;\n };\n const r: Renderable = {\n order: mesh.renderOrder ?? (isTransparent ? 200 : 100),\n isTransparent,\n mesh,\n _worldCenter: sortCenter,\n bind(eng, sig) {\n const bindings = h.getOrCreateShaderPipelineBindings(eng, material);\n const vertexBuffers = [...bindings.vertexBuffers, ...instanceLayouts];\n const pipeline = h.getOrCreateShaderPipeline(eng, sig, material, bindings, variantKey, vertexBuffers, instanceAttrs);\n const cb = cull?.tryBind(r, scene, mesh, eng, hasColor, isTransparent, update);\n return {\n renderable: r,\n pipeline,\n update: cb ? cb.update : update,\n draw: (pass) => draw(pass, eng, cb),\n };\n },\n };\n (r as { _direct?: boolean })._direct = true;\n return r;\n}\n\n/** Build one instanced renderable for `mesh` (used by the combined `rebuildSingle`). */\nfunction buildInstancedSingle(scene: SceneContext, mesh: Mesh, material: ShaderMaterial, isOverride: boolean, h: ShaderHelpers, cull?: CullModule): Renderable {\n const bindings = h.getOrCreateShaderPipelineBindings(scene.surface.engine, material);\n const packet = h.createPacket(scene, material, bindings.systemSpec, mesh);\n return createShaderInstancedRenderable(scene, material, packet, isOverride, h, cull);\n}\n\n/** Group entry point used whenever a ShaderMaterial scene has at least one\n * thin-instanced mesh. Plain meshes flow through the passed-in `buildPlain`\n * (`buildShaderMaterialRenderables`); instanced meshes get a dedicated renderable. */\nexport function buildShaderRenderablesWithInstancing(\n scene: SceneContext,\n meshes: Mesh[],\n buildPlain: ShaderHelpers[\"buildPlain\"],\n createPacket: ShaderHelpers[\"createPacket\"],\n updatePacket: ShaderHelpers[\"updatePacket\"],\n updateCustomUbo: ShaderHelpers[\"updateCustomUbo\"],\n getAttrBuffer: ShaderHelpers[\"getAttrBuffer\"],\n getOrCreateShaderPipeline: ShaderHelpers[\"getOrCreateShaderPipeline\"],\n getOrCreateShaderPipelineBindings: ShaderHelpers[\"getOrCreateShaderPipelineBindings\"],\n cull?: CullModule\n): MeshGroupBuildResult {\n const h: ShaderHelpers = { buildPlain, createPacket, updatePacket, updateCustomUbo, getAttrBuffer, getOrCreateShaderPipeline, getOrCreateShaderPipelineBindings };\n const instanced: Mesh[] = [];\n const plain: Mesh[] = [];\n for (const mesh of meshes) {\n if (mesh.thinInstances) {\n instanced.push(mesh);\n } else {\n plain.push(mesh);\n }\n }\n\n const renderables: Renderable[] = [];\n let plainRebuild: MeshGroupBuildResult[\"rebuildSingle\"] | undefined;\n if (plain.length > 0) {\n const plainResult = buildPlain(scene, plain);\n renderables.push(...plainResult.renderables);\n plainRebuild = plainResult.rebuildSingle;\n }\n for (const mesh of instanced) {\n renderables.push(buildInstancedSingle(scene, mesh, mesh.material as ShaderMaterial, false, h, cull));\n }\n\n const rebuildSingle = (s: SceneContext, mesh: Mesh, materialOverride?: Material): Renderable => {\n const material = (materialOverride ?? mesh.material) as ShaderMaterial;\n if (mesh.thinInstances) {\n return buildInstancedSingle(s, mesh, material, materialOverride != null, h, cull);\n }\n if (plainRebuild) {\n return plainRebuild(s, mesh, materialOverride);\n }\n return buildPlain(s, [mesh]).rebuildSingle(s, mesh, materialOverride);\n };\n\n return { renderables, rebuildSingle };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shader-thin-instance.js","sources":["../../../../src/material/shader/shader-thin-instance.ts"],"sourcesContent":["/** ShaderMaterial thin-instance support — dynamically imported ONLY when a\n * ShaderMaterial scene actually uses thin instances, so non-instanced scenes pull\n * in zero extra bytes and the shared `shader-renderable.ts` / `shader-pipeline.ts`\n * chunks stay identical to their non-instanced form.\n *\n * The renderable helpers this module needs (packet create/update, attribute\n * buffers, pipeline builders, the plain-mesh builder) are passed in as positional\n * arguments by `buildShaderGroup`, NOT imported. Importing them would force the\n * shared chunk to export them, which de-mangles their names and grows every\n * ShaderMaterial scene's bundle. As parameters they keep their mangled identity in\n * the shared chunk and are only named here, in this culling/instancing-only chunk.\n *\n * The instance buffer layout MUST match the buffers produced by\n * `thin-instance-gpu.ts` (matrix buffer arrayStride 64, 4x float32x4 at offsets\n * 0/16/32/48; color buffer arrayStride 16, float32x4 at offset 0). */\n\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { Material } from \"../material.js\";\nimport type { Mesh, MeshGPU } from \"../../mesh/mesh.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport type { UboSpec } from \"../../shader/fragment-types.js\";\nimport type { DrawUpdateContext, MeshGroupBuildResult, Renderable } from \"../../render/renderable.js\";\nimport type { ShaderAttributeName, ShaderMaterial } from \"./shader-material.js\";\nimport type { ShaderPipelineBindings } from \"./shader-pipeline.js\";\nimport type { ShaderPacket, ShaderRenderPass } from \"./shader-renderable.js\";\nimport { syncThinInstanceBuffers } from \"../../mesh/thin-instance-gpu.js\";\n\ntype CullModule = typeof import(\"../../mesh/thin-instance-cull-binding.js\");\n\n/** The shader-renderable helpers handed in positionally by `buildShaderGroup`. */\ninterface ShaderHelpers {\n buildPlain: (scene: SceneContext, meshes: Mesh[]) => MeshGroupBuildResult;\n createPacket: (scene: SceneContext, material: ShaderMaterial, systemSpec: UboSpec, mesh: Mesh) => ShaderPacket;\n updatePacket: (scene: SceneContext, material: ShaderMaterial, packet: ShaderPacket, context: DrawUpdateContext) => void;\n updateCustomUbo: (engine: EngineContext, material: ShaderMaterial) => void;\n getAttrBuffer: (engine: EngineContext, gpu: MeshGPU, name: ShaderAttributeName) => GPUBuffer;\n getOrCreateShaderPipeline: (\n engine: EngineContext,\n sig: RenderTargetSignature,\n material: ShaderMaterial,\n bindings: ShaderPipelineBindings,\n variantKey?: string,\n vertexBuffers?: readonly GPUVertexBufferLayout[],\n instanceAttrs?: string\n ) => GPURenderPipeline;\n getOrCreateShaderPipelineBindings: (engine: EngineContext, material: ShaderMaterial) => ShaderPipelineBindings;\n}\n\n/** Instance vertex buffer layouts. `baseLocation` is the first free shader\n * location after the material's own attributes. */\nfunction instanceVertexLayouts(baseLocation: number, hasColor: boolean): GPUVertexBufferLayout[] {\n const layouts: GPUVertexBufferLayout[] = [\n {\n arrayStride: 64,\n stepMode: \"instance\",\n attributes: [\n { shaderLocation: baseLocation, offset: 0, format: \"float32x4\" },\n { shaderLocation: baseLocation + 1, offset: 16, format: \"float32x4\" },\n { shaderLocation: baseLocation + 2, offset: 32, format: \"float32x4\" },\n { shaderLocation: baseLocation + 3, offset: 48, format: \"float32x4\" },\n ],\n },\n ];\n if (hasColor) {\n layouts.push({\n arrayStride: 16,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: baseLocation + 4, offset: 0, format: \"float32x4\" }],\n });\n }\n return layouts;\n}\n\n/** WGSL lines appended inside `VertexInput` for instanced variants. */\nfunction instancePreludeAttributes(baseLocation: number, hasColor: boolean): string {\n let wgsl = `@location(${baseLocation}) world0: vec4<f32>,\n@location(${baseLocation + 1}) world1: vec4<f32>,\n@location(${baseLocation + 2}) world2: vec4<f32>,\n@location(${baseLocation + 3}) world3: vec4<f32>,\n`;\n if (hasColor) {\n wgsl += `@location(${baseLocation + 4}) instanceColor: vec4<f32>,\n`;\n }\n return wgsl;\n}\n\n/** Build ONE thin-instance renderable for a ShaderMaterial mesh (opaque or\n * transparent). Marked `_direct` so instance buffers are re-bound fresh each\n * frame; this also prepares the renderable for opaque-only GPU culling. */\nfunction createShaderInstancedRenderable(\n scene: SceneContext,\n material: ShaderMaterial,\n packet: ShaderPacket,\n isOverride: boolean,\n h: ShaderHelpers,\n cull?: CullModule\n): Renderable {\n const isTransparent = material.needAlphaBlending;\n const mesh = packet.mesh;\n const ti = mesh.thinInstances!;\n const hasColor = !!ti.colors;\n const baseLocation = material.attributes.length;\n const instanceLayouts = instanceVertexLayouts(baseLocation, hasColor);\n const instanceAttrs = instancePreludeAttributes(baseLocation, hasColor);\n const variantKey = `|ti1c${hasColor ? 1 : 0}`;\n const wm = mesh.worldMatrix as unknown as ArrayLike<number>;\n const sortCenter: [number, number, number] = [wm[12]!, wm[13]!, wm[14]!];\n const update = (context: DrawUpdateContext): void => {\n if (packet._disposed) {\n return;\n }\n if (!isOverride && mesh.material !== material) {\n return;\n }\n h.updateCustomUbo(scene.surface.engine, material);\n h.updatePacket(scene, material, packet, context);\n if (isTransparent) {\n const m = mesh.worldMatrix as unknown as ArrayLike<number>;\n sortCenter[0] = m[12]!;\n sortCenter[1] = m[13]!;\n sortCenter[2] = m[14]!;\n }\n };\n const draw = (pass: ShaderRenderPass, engine: EngineContext, cullBinding?: import(\"../../mesh/thin-instance-cull-binding.js\").TiCullBinding): number => {\n if (packet._disposed) {\n return 0;\n }\n if (!isOverride && mesh.material !== material) {\n return 0;\n }\n if (ti.count <= 0) {\n return 0;\n }\n const gpu = mesh._gpu;\n let slot = 0;\n for (let i = 0; i < material.attributes.length; i++) {\n pass.setVertexBuffer(slot++, h.getAttrBuffer(engine, gpu, material.attributes[i]!));\n }\n slot = syncThinInstanceBuffers(engine, ti, pass, slot, hasColor, cullBinding?.cullDrawBufs);\n pass.setIndexBuffer(gpu.indexBuffer, gpu.indexFormat);\n pass.setBindGroup(1, packet._bindGroup);\n if (cullBinding) {\n cullBinding.draw(pass, gpu.indexCount, ti.count);\n } else {\n pass.drawIndexed(gpu.indexCount, ti.count);\n }\n return 1;\n };\n const r: Renderable = {\n order: mesh.renderOrder ?? (isTransparent ? 200 : 100),\n isTransparent,\n mesh,\n _worldCenter: sortCenter,\n bind(eng, sig) {\n const bindings = h.getOrCreateShaderPipelineBindings(eng, material);\n const vertexBuffers = [...bindings.vertexBuffers, ...instanceLayouts];\n const pipeline = h.getOrCreateShaderPipeline(eng, sig, material, bindings, variantKey, vertexBuffers, instanceAttrs);\n const cb = cull?.tryBind(r, scene, mesh, eng, hasColor, isTransparent, update, sig);\n return {\n renderable: r,\n pipeline,\n update: cb ? cb.update : update,\n draw: (pass) => draw(pass, eng, cb),\n };\n },\n };\n (r as { _direct?: boolean })._direct = true;\n return r;\n}\n\n/** Build one instanced renderable for `mesh` (used by the combined `rebuildSingle`). */\nfunction buildInstancedSingle(scene: SceneContext, mesh: Mesh, material: ShaderMaterial, isOverride: boolean, h: ShaderHelpers, cull?: CullModule): Renderable {\n const bindings = h.getOrCreateShaderPipelineBindings(scene.surface.engine, material);\n const packet = h.createPacket(scene, material, bindings.systemSpec, mesh);\n return createShaderInstancedRenderable(scene, material, packet, isOverride, h, cull);\n}\n\n/** Group entry point used whenever a ShaderMaterial scene has at least one\n * thin-instanced mesh. Plain meshes flow through the passed-in `buildPlain`\n * (`buildShaderMaterialRenderables`); instanced meshes get a dedicated renderable. */\nexport function buildShaderRenderablesWithInstancing(\n scene: SceneContext,\n meshes: Mesh[],\n buildPlain: ShaderHelpers[\"buildPlain\"],\n createPacket: ShaderHelpers[\"createPacket\"],\n updatePacket: ShaderHelpers[\"updatePacket\"],\n updateCustomUbo: ShaderHelpers[\"updateCustomUbo\"],\n getAttrBuffer: ShaderHelpers[\"getAttrBuffer\"],\n getOrCreateShaderPipeline: ShaderHelpers[\"getOrCreateShaderPipeline\"],\n getOrCreateShaderPipelineBindings: ShaderHelpers[\"getOrCreateShaderPipelineBindings\"],\n cull?: CullModule\n): MeshGroupBuildResult {\n const h: ShaderHelpers = { buildPlain, createPacket, updatePacket, updateCustomUbo, getAttrBuffer, getOrCreateShaderPipeline, getOrCreateShaderPipelineBindings };\n const instanced: Mesh[] = [];\n const plain: Mesh[] = [];\n for (const mesh of meshes) {\n if (mesh.thinInstances) {\n instanced.push(mesh);\n } else {\n plain.push(mesh);\n }\n }\n\n const renderables: Renderable[] = [];\n let plainRebuild: MeshGroupBuildResult[\"rebuildSingle\"] | undefined;\n if (plain.length > 0) {\n const plainResult = buildPlain(scene, plain);\n renderables.push(...plainResult.renderables);\n plainRebuild = plainResult.rebuildSingle;\n }\n for (const mesh of instanced) {\n renderables.push(buildInstancedSingle(scene, mesh, mesh.material as ShaderMaterial, false, h, cull));\n }\n\n const rebuildSingle = (s: SceneContext, mesh: Mesh, materialOverride?: Material): Renderable => {\n const material = (materialOverride ?? mesh.material) as ShaderMaterial;\n if (mesh.thinInstances) {\n return buildInstancedSingle(s, mesh, material, materialOverride != null, h, cull);\n }\n if (plainRebuild) {\n return plainRebuild(s, mesh, materialOverride);\n }\n return buildPlain(s, [mesh]).rebuildSingle(s, mesh, materialOverride);\n };\n\n return { renderables, rebuildSingle };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -175,7 +175,7 @@ function buildStandardMeshRenderables(scene, meshes, factories) {
|
|
|
175
175
|
mesh,
|
|
176
176
|
bind(eng, sig) {
|
|
177
177
|
const pipeline = getOrCreateStandardPipeline(eng, sig, bindings);
|
|
178
|
-
const cb = cull?.tryBind(r, s, mesh, engine, hasInstanceColor, isTransparent, update);
|
|
178
|
+
const cb = cull?.tryBind(r, s, mesh, engine, hasInstanceColor, isTransparent, update, sig);
|
|
179
179
|
return {
|
|
180
180
|
renderable: r,
|
|
181
181
|
pipeline,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standard-renderable.js","sources":["../../../../src/material/standard/standard-renderable.ts"],"sourcesContent":["/** Standard mesh renderable — builds Renderables from Mesh + StandardMaterial.\n *\n * `buildStandardMeshRenderables` does shared per-scene setup, then delegates\n * per-mesh work to `buildSingleStandardRenderable`. The same single-mesh\n * function is reused by the material-swap path. */\n\nimport { F32 } from \"../../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { Mesh } from \"../../mesh/mesh.js\";\nimport type { Renderable, MeshGroupBuildResult } from \"../../render/renderable.js\";\nimport { collectStdBoundTextures } from \"./collect-std-bound-textures.js\";\nimport type { StandardMaterialProps } from \"./standard-material.js\";\nimport { _computeStandardMaterialFeatures, _standardShaderVariantKey } from \"./standard-material.js\";\nimport { acquireTexture, releaseTexture, clearSamplerCache } from \"../../resource/gpu-pool.js\";\nimport { createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { getOrCreateStandardBindings, getOrCreateStandardPipeline, createStandardMeshBindGroup, clearStandardPipelineCache, writeStdMaterialData } from \"./standard-pipeline.js\";\nimport { ESM_SHADOW_OUTPUT, NO_COLOR_OUTPUT, NEEDS_UV, NEEDS_UV2, HAS_OPACITY_TEXTURE, _getStdExts } from \"./standard-flags.js\";\nimport type { ShaderFragment } from \"../../shader/fragment-types.js\";\nimport type { ShadowGenerator } from \"../../shadow/shadow-generator.js\";\nimport { writeMeshLightSelection } from \"../../render/lights-ubo.js\";\nimport type { Material, MaterialRenderFeatures } from \"../material.js\";\nimport { _computeMeshFeatures, MSH_HAS_INSTANCE_COLOR, MSH_HAS_MORPH_TARGETS, MSH_HAS_THIN_INSTANCES, MSH_RECEIVE_SHADOWS } from \"../mesh-features.js\";\nimport { packMat4IntoF32 } from \"../../math/pack-mat4-into-f32.js\";\n\n/** Scratch buffer for material UBO writes (24 floats = 96 bytes). Reused across\n * every Standard renderable since binding updates are single-threaded per frame. */\nconst _stdMatScratch = new F32(24);\n\n/** Thin instance GPU sync callback type — loaded dynamically only when needed. */\ntype ThinInstanceSync = (\n engine: EngineContext,\n ti: any,\n pass: GPURenderPassEncoder | GPURenderBundleEncoder,\n slot: number,\n hasColor: boolean,\n drawBuffers?: import(\"../../mesh/thin-instance-gpu.js\").ThinInstanceDrawBuffers | null\n) => number;\n\n/** Fragment factories passed from the async group builder. */\nexport interface StdFragmentFactories {\n tiSync?: ThinInstanceSync;\n tiFragment?: (hasColor: boolean) => ShaderFragment;\n shadowFragment?: (shadowLights: import(\"./fragments/std-shadow-fragment.js\").ShadowLightSlot[]) => ShaderFragment;\n /** Present only when at least one mesh in the build has morph targets. */\n morphFragment?: () => ShaderFragment;\n /** Present only when the scene has at least one culling-enabled thin-instance mesh. */\n cull?: typeof import(\"../../mesh/thin-instance-cull-binding.js\");\n}\n\n/** Build Renderable(s) + a SceneUniformUpdater for a set of standard meshes.\n * The `rebuildSingle` closure is reused later (via `_rebuildSingle` on the group\n * builder) for material swaps + per-pass material overrides. */\nexport function buildStandardMeshRenderables(scene: SceneContext, meshes: Mesh[], factories: StdFragmentFactories): MeshGroupBuildResult {\n const engine = scene.surface.engine;\n const device = engine._device;\n const { tiSync, tiFragment, shadowFragment, cull, morphFragment } = factories;\n\n // Collect per-light shadow info.\n const shadowLights: { lightIndex: number; shadowType: \"esm\" | \"pcf\" | \"csm\"; gen: ShadowGenerator }[] = [];\n for (let i = 0; i < scene.lights.length; i++) {\n const sg = scene.lights[i]!.shadowGenerator;\n if (sg) {\n shadowLights.push({ lightIndex: i, shadowType: sg._shadowType, gen: sg });\n }\n }\n const hasSomeShadows = shadowLights.length > 0;\n\n // All receiving meshes in this build share the same shadow generators,\n // so keying the shadow BG by `bindings._shadowBGL` alone is correct.\n const shadowBGCache = new Map<GPUBindGroupLayout, GPUBindGroup>();\n // Closure used both for the initial per-mesh build below AND for later\n // material-swap / per-pass-override rebuilds (set on standardGroupBuilder._rebuildSingle).\n const rebuildSingle = (s: SceneContext, mesh: Mesh, materialOverride?: Material): Renderable => {\n const mat = (materialOverride ?? mesh.material) as StandardMaterialProps;\n const renderFeatures = (mat._renderFeatures ??= { features: _computeStandardMaterialFeatures(mat) }) as MaterialRenderFeatures;\n const isOverride = materialOverride != null;\n const features = renderFeatures.features;\n const shadowOutput = (features & (NO_COLOR_OUTPUT | ESM_SHADOW_OUTPUT)) !== 0;\n const receiveShadows = !shadowOutput && mesh.receiveShadows && hasSomeShadows;\n const meshFeatures = _computeMeshFeatures(mesh, receiveShadows);\n // Build per-feature fragment list (deduped via pipeline cache).\n const frags: ShaderFragment[] = [];\n // Keep morph first: composeStandardShader uses the first fragment's patch\n // to switch the placeholder morph bindings to storage buffers.\n if (meshFeatures & MSH_HAS_MORPH_TARGETS && morphFragment) {\n frags.push(morphFragment());\n }\n for (const ext of _getStdExts().values()) {\n if (features & ext._feature) {\n const f = ext._frag(features);\n if (f) {\n frags.push(f);\n }\n }\n }\n let shaderKey = \"\";\n if (meshFeatures & MSH_RECEIVE_SHADOWS && shadowFragment) {\n const slots = shadowLights.map((sl) => ({ lightIndex: sl.lightIndex, shadowType: sl.shadowType }));\n shaderKey = _standardShaderVariantKey(slots);\n frags.push(shadowFragment(slots));\n }\n if (meshFeatures & MSH_HAS_THIN_INSTANCES && tiFragment) {\n const hasColor = !!(meshFeatures & MSH_HAS_INSTANCE_COLOR);\n const tiFrag = tiFragment(hasColor);\n if (hasColor) {\n // Standard applies instance color to final color (BC), not to baseColor (AT) like PBR.\n const { _fragmentSlots: _fragmentSlots, ...rest } = tiFrag;\n frags.push({\n ...rest,\n _fragmentSlots: {\n BC: `color = vec4<f32>(color.rgb * input.vInstanceColor.rgb, color.a * input.vInstanceColor.a);`,\n },\n });\n } else {\n frags.push(tiFrag);\n }\n }\n const esmShadowDepthCode = (features & ESM_SHADOW_OUTPUT) !== 0 ? (mat as StandardMaterialProps & { readonly _esmShadowDepthCode: string })._esmShadowDepthCode : \"\";\n const bindings = getOrCreateStandardBindings(engine, features, meshFeatures, frags, shaderKey, esmShadowDepthCode, (mat as StandardMaterialProps).stencil ?? null);\n\n const meshShadowGens = receiveShadows ? shadowLights.map((sl) => sl.gen) : [];\n\n const meshUboData = new F32(bindings._composed._meshUboSpec._totalBytes / 4);\n const _packMeshWorld = engine._makePackMeshWorld?.(s as SceneContext) ?? packMat4IntoF32;\n _packMeshWorld(meshUboData, mesh.worldMatrix, 0, 0);\n writeMeshLightSelection(mesh, s.lights, meshUboData);\n const meshUBO = createUniformBuffer(engine, meshUboData);\n const textureLevel = (features & NEEDS_UV) !== 0 ? 1.0 : 0;\n const matData = new F32(24);\n writeStdMaterialData(matData, mat, textureLevel);\n const materialUBO = createUniformBuffer(engine, matData);\n const meshBindGroup = createStandardMeshBindGroup(engine, bindings, meshUBO, materialUBO, mat, mesh.morphTargets ?? null);\n\n // Shadow bind group (group 2) — shared across receiving meshes via shadowBGCache.\n let shadowBindGroup: GPUBindGroup | null = null;\n if (meshShadowGens.length > 0 && bindings._shadowBGL) {\n let cached = shadowBGCache.get(bindings._shadowBGL);\n if (!cached) {\n const entries: GPUBindGroupEntry[] = [];\n let b = 0;\n for (const sg of meshShadowGens) {\n entries.push({ binding: b++, resource: sg._depthTexture.createView() });\n entries.push({ binding: b++, resource: sg._depthSampler });\n entries.push({ binding: b++, resource: { buffer: sg._shadowUBO } });\n }\n cached = device.createBindGroup({ layout: bindings._shadowBGL, entries });\n shadowBGCache.set(bindings._shadowBGL, cached);\n }\n shadowBindGroup = cached;\n }\n\n const needsUV = (features & NEEDS_UV) !== 0;\n const needsUV2 = (features & NEEDS_UV2) !== 0;\n const hasThinInstances = (meshFeatures & MSH_HAS_THIN_INSTANCES) !== 0;\n const hasInstanceColor = (meshFeatures & MSH_HAS_INSTANCE_COLOR) !== 0;\n const isTransparent = !shadowOutput && ((features & HAS_OPACITY_TEXTURE) !== 0 || mat.alpha < 1);\n\n const boundTextures = collectStdBoundTextures(mat);\n for (const t of boundTextures) {\n acquireTexture(t);\n }\n s._meshDisposables.set(mesh, [\n () => {\n for (const t of boundTextures) {\n releaseTexture(t);\n }\n },\n ]);\n\n let _lastWorldVersion = mesh.worldMatrixVersion;\n let _lastLightsCount = s.lights.length;\n const sortCenter = [mesh.worldMatrix[12]!, mesh.worldMatrix[13]!, mesh.worldMatrix[14]!] as [number, number, number];\n const _baseUpdate = (): void => {\n const worldVersion = mesh.worldMatrixVersion;\n if (worldVersion !== _lastWorldVersion || s.lights.length !== _lastLightsCount) {\n sortCenter[0] = mesh.worldMatrix[12]!;\n sortCenter[1] = mesh.worldMatrix[13]!;\n sortCenter[2] = mesh.worldMatrix[14]!;\n _packMeshWorld(meshUboData, mesh.worldMatrix, 0, 0);\n writeMeshLightSelection(mesh, s.lights, meshUboData);\n device.queue.writeBuffer(meshUBO, 0, meshUboData as Float32Array<ArrayBuffer>);\n _lastWorldVersion = worldVersion;\n _lastLightsCount = s.lights.length;\n }\n const uboVersion = mat._uboVersion;\n if (uboVersion !== _lastUboVersion) {\n _lastUboVersion = uboVersion;\n _stdMatScratch.fill(0);\n writeStdMaterialData(_stdMatScratch, mat, textureLevel);\n device.queue.writeBuffer(materialUBO, 0, _stdMatScratch.buffer, 0, 96);\n }\n };\n // FO-version wrapper applied only when the engine has floating-origin\n // on. The wrapper lives in the dynamic-imported `floating-origin.ts`\n // module and is the sole owner of `_lastFoVersion` tracking. For\n // non-LWR engines `_wrapRenderableForFO` is undefined and `update`\n // is the bare closure — no FO bytes in the closure body.\n const _invalidate = (): void => {\n _lastWorldVersion = -1;\n };\n const update = engine._wrapRenderableForFO?.(_baseUpdate, s as SceneContext, _invalidate) ?? _baseUpdate;\n\n const draw = (pass: GPURenderPassEncoder | GPURenderBundleEncoder, cullBinding?: import(\"../../mesh/thin-instance-cull-binding.js\").TiCullBinding): number => {\n // For per-pass material overrides, skip the mesh.material === mat guard\n // because the override material is intentionally not the mesh's current one.\n if (!isOverride && mesh.material !== mat) {\n return 0;\n }\n const g = mesh._gpu;\n let slot = 0;\n const vb = g._vbLayout;\n pass.setVertexBuffer(slot++, g.positionBuffer, vb?._p?._offset);\n pass.setVertexBuffer(slot++, g.normalBuffer, vb?._n?._offset);\n if (needsUV) {\n pass.setVertexBuffer(slot++, g.uvBuffer, vb?._u?._offset);\n }\n if (needsUV2 && g.uv2Buffer) {\n pass.setVertexBuffer(slot++, g.uv2Buffer, vb?._u2?._offset);\n }\n\n const ti = hasThinInstances ? mesh.thinInstances : null;\n if (ti && tiSync) {\n slot = tiSync(engine, ti, pass, slot, hasInstanceColor, cullBinding?.cullDrawBufs);\n }\n\n pass.setIndexBuffer(g.indexBuffer, g.indexFormat);\n pass.setBindGroup(1, meshBindGroup);\n if (receiveShadows && shadowBindGroup) {\n pass.setBindGroup(2, shadowBindGroup);\n }\n if (cullBinding) {\n cullBinding.draw(pass, g.indexCount, ti!.count);\n } else if (ti && ti.count > 0) {\n pass.drawIndexed(g.indexCount, ti.count);\n } else {\n pass.drawIndexed(g.indexCount);\n }\n return 1;\n };\n\n const r: Renderable = {\n order: mesh.renderOrder ?? (isTransparent ? 200 : 100),\n isTransparent,\n mesh,\n bind(eng, sig) {\n const pipeline = getOrCreateStandardPipeline(eng as EngineContext, sig, bindings);\n // Opaque-only GPU culling (opt-in): tryBind gates on opt-in + transparency, returns the per-binding cull lifecycle.\n const cb = cull?.tryBind(r, s, mesh, engine, hasInstanceColor, isTransparent, update);\n return {\n renderable: r,\n pipeline,\n update: cb ? cb.update : update,\n draw: (pass) => draw(pass, cb),\n };\n },\n };\n r._worldCenter = sortCenter;\n let _lastUboVersion = mat._uboVersion;\n return r;\n };\n\n const renderables = meshes.map((m) => rebuildSingle(scene, m));\n\n scene._disposables.push(\n () => clearStandardPipelineCache(),\n () => clearSamplerCache(engine)\n );\n\n return { renderables, rebuildSingle };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"standard-renderable.js","sources":["../../../../src/material/standard/standard-renderable.ts"],"sourcesContent":["/** Standard mesh renderable — builds Renderables from Mesh + StandardMaterial.\n *\n * `buildStandardMeshRenderables` does shared per-scene setup, then delegates\n * per-mesh work to `buildSingleStandardRenderable`. The same single-mesh\n * function is reused by the material-swap path. */\n\nimport { F32 } from \"../../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene.js\";\nimport type { Mesh } from \"../../mesh/mesh.js\";\nimport type { Renderable, MeshGroupBuildResult } from \"../../render/renderable.js\";\nimport { collectStdBoundTextures } from \"./collect-std-bound-textures.js\";\nimport type { StandardMaterialProps } from \"./standard-material.js\";\nimport { _computeStandardMaterialFeatures, _standardShaderVariantKey } from \"./standard-material.js\";\nimport { acquireTexture, releaseTexture, clearSamplerCache } from \"../../resource/gpu-pool.js\";\nimport { createUniformBuffer } from \"../../resource/gpu-buffers.js\";\nimport { getOrCreateStandardBindings, getOrCreateStandardPipeline, createStandardMeshBindGroup, clearStandardPipelineCache, writeStdMaterialData } from \"./standard-pipeline.js\";\nimport { ESM_SHADOW_OUTPUT, NO_COLOR_OUTPUT, NEEDS_UV, NEEDS_UV2, HAS_OPACITY_TEXTURE, _getStdExts } from \"./standard-flags.js\";\nimport type { ShaderFragment } from \"../../shader/fragment-types.js\";\nimport type { ShadowGenerator } from \"../../shadow/shadow-generator.js\";\nimport { writeMeshLightSelection } from \"../../render/lights-ubo.js\";\nimport type { Material, MaterialRenderFeatures } from \"../material.js\";\nimport { _computeMeshFeatures, MSH_HAS_INSTANCE_COLOR, MSH_HAS_MORPH_TARGETS, MSH_HAS_THIN_INSTANCES, MSH_RECEIVE_SHADOWS } from \"../mesh-features.js\";\nimport { packMat4IntoF32 } from \"../../math/pack-mat4-into-f32.js\";\n\n/** Scratch buffer for material UBO writes (24 floats = 96 bytes). Reused across\n * every Standard renderable since binding updates are single-threaded per frame. */\nconst _stdMatScratch = new F32(24);\n\n/** Thin instance GPU sync callback type — loaded dynamically only when needed. */\ntype ThinInstanceSync = (\n engine: EngineContext,\n ti: any,\n pass: GPURenderPassEncoder | GPURenderBundleEncoder,\n slot: number,\n hasColor: boolean,\n drawBuffers?: import(\"../../mesh/thin-instance-gpu.js\").ThinInstanceDrawBuffers | null\n) => number;\n\n/** Fragment factories passed from the async group builder. */\nexport interface StdFragmentFactories {\n tiSync?: ThinInstanceSync;\n tiFragment?: (hasColor: boolean) => ShaderFragment;\n shadowFragment?: (shadowLights: import(\"./fragments/std-shadow-fragment.js\").ShadowLightSlot[]) => ShaderFragment;\n /** Present only when at least one mesh in the build has morph targets. */\n morphFragment?: () => ShaderFragment;\n /** Present only when the scene has at least one culling-enabled thin-instance mesh. */\n cull?: typeof import(\"../../mesh/thin-instance-cull-binding.js\");\n}\n\n/** Build Renderable(s) + a SceneUniformUpdater for a set of standard meshes.\n * The `rebuildSingle` closure is reused later (via `_rebuildSingle` on the group\n * builder) for material swaps + per-pass material overrides. */\nexport function buildStandardMeshRenderables(scene: SceneContext, meshes: Mesh[], factories: StdFragmentFactories): MeshGroupBuildResult {\n const engine = scene.surface.engine;\n const device = engine._device;\n const { tiSync, tiFragment, shadowFragment, cull, morphFragment } = factories;\n\n // Collect per-light shadow info.\n const shadowLights: { lightIndex: number; shadowType: \"esm\" | \"pcf\" | \"csm\"; gen: ShadowGenerator }[] = [];\n for (let i = 0; i < scene.lights.length; i++) {\n const sg = scene.lights[i]!.shadowGenerator;\n if (sg) {\n shadowLights.push({ lightIndex: i, shadowType: sg._shadowType, gen: sg });\n }\n }\n const hasSomeShadows = shadowLights.length > 0;\n\n // All receiving meshes in this build share the same shadow generators,\n // so keying the shadow BG by `bindings._shadowBGL` alone is correct.\n const shadowBGCache = new Map<GPUBindGroupLayout, GPUBindGroup>();\n // Closure used both for the initial per-mesh build below AND for later\n // material-swap / per-pass-override rebuilds (set on standardGroupBuilder._rebuildSingle).\n const rebuildSingle = (s: SceneContext, mesh: Mesh, materialOverride?: Material): Renderable => {\n const mat = (materialOverride ?? mesh.material) as StandardMaterialProps;\n const renderFeatures = (mat._renderFeatures ??= { features: _computeStandardMaterialFeatures(mat) }) as MaterialRenderFeatures;\n const isOverride = materialOverride != null;\n const features = renderFeatures.features;\n const shadowOutput = (features & (NO_COLOR_OUTPUT | ESM_SHADOW_OUTPUT)) !== 0;\n const receiveShadows = !shadowOutput && mesh.receiveShadows && hasSomeShadows;\n const meshFeatures = _computeMeshFeatures(mesh, receiveShadows);\n // Build per-feature fragment list (deduped via pipeline cache).\n const frags: ShaderFragment[] = [];\n // Keep morph first: composeStandardShader uses the first fragment's patch\n // to switch the placeholder morph bindings to storage buffers.\n if (meshFeatures & MSH_HAS_MORPH_TARGETS && morphFragment) {\n frags.push(morphFragment());\n }\n for (const ext of _getStdExts().values()) {\n if (features & ext._feature) {\n const f = ext._frag(features);\n if (f) {\n frags.push(f);\n }\n }\n }\n let shaderKey = \"\";\n if (meshFeatures & MSH_RECEIVE_SHADOWS && shadowFragment) {\n const slots = shadowLights.map((sl) => ({ lightIndex: sl.lightIndex, shadowType: sl.shadowType }));\n shaderKey = _standardShaderVariantKey(slots);\n frags.push(shadowFragment(slots));\n }\n if (meshFeatures & MSH_HAS_THIN_INSTANCES && tiFragment) {\n const hasColor = !!(meshFeatures & MSH_HAS_INSTANCE_COLOR);\n const tiFrag = tiFragment(hasColor);\n if (hasColor) {\n // Standard applies instance color to final color (BC), not to baseColor (AT) like PBR.\n const { _fragmentSlots: _fragmentSlots, ...rest } = tiFrag;\n frags.push({\n ...rest,\n _fragmentSlots: {\n BC: `color = vec4<f32>(color.rgb * input.vInstanceColor.rgb, color.a * input.vInstanceColor.a);`,\n },\n });\n } else {\n frags.push(tiFrag);\n }\n }\n const esmShadowDepthCode = (features & ESM_SHADOW_OUTPUT) !== 0 ? (mat as StandardMaterialProps & { readonly _esmShadowDepthCode: string })._esmShadowDepthCode : \"\";\n const bindings = getOrCreateStandardBindings(engine, features, meshFeatures, frags, shaderKey, esmShadowDepthCode, (mat as StandardMaterialProps).stencil ?? null);\n\n const meshShadowGens = receiveShadows ? shadowLights.map((sl) => sl.gen) : [];\n\n const meshUboData = new F32(bindings._composed._meshUboSpec._totalBytes / 4);\n const _packMeshWorld = engine._makePackMeshWorld?.(s as SceneContext) ?? packMat4IntoF32;\n _packMeshWorld(meshUboData, mesh.worldMatrix, 0, 0);\n writeMeshLightSelection(mesh, s.lights, meshUboData);\n const meshUBO = createUniformBuffer(engine, meshUboData);\n const textureLevel = (features & NEEDS_UV) !== 0 ? 1.0 : 0;\n const matData = new F32(24);\n writeStdMaterialData(matData, mat, textureLevel);\n const materialUBO = createUniformBuffer(engine, matData);\n const meshBindGroup = createStandardMeshBindGroup(engine, bindings, meshUBO, materialUBO, mat, mesh.morphTargets ?? null);\n\n // Shadow bind group (group 2) — shared across receiving meshes via shadowBGCache.\n let shadowBindGroup: GPUBindGroup | null = null;\n if (meshShadowGens.length > 0 && bindings._shadowBGL) {\n let cached = shadowBGCache.get(bindings._shadowBGL);\n if (!cached) {\n const entries: GPUBindGroupEntry[] = [];\n let b = 0;\n for (const sg of meshShadowGens) {\n entries.push({ binding: b++, resource: sg._depthTexture.createView() });\n entries.push({ binding: b++, resource: sg._depthSampler });\n entries.push({ binding: b++, resource: { buffer: sg._shadowUBO } });\n }\n cached = device.createBindGroup({ layout: bindings._shadowBGL, entries });\n shadowBGCache.set(bindings._shadowBGL, cached);\n }\n shadowBindGroup = cached;\n }\n\n const needsUV = (features & NEEDS_UV) !== 0;\n const needsUV2 = (features & NEEDS_UV2) !== 0;\n const hasThinInstances = (meshFeatures & MSH_HAS_THIN_INSTANCES) !== 0;\n const hasInstanceColor = (meshFeatures & MSH_HAS_INSTANCE_COLOR) !== 0;\n const isTransparent = !shadowOutput && ((features & HAS_OPACITY_TEXTURE) !== 0 || mat.alpha < 1);\n\n const boundTextures = collectStdBoundTextures(mat);\n for (const t of boundTextures) {\n acquireTexture(t);\n }\n s._meshDisposables.set(mesh, [\n () => {\n for (const t of boundTextures) {\n releaseTexture(t);\n }\n },\n ]);\n\n let _lastWorldVersion = mesh.worldMatrixVersion;\n let _lastLightsCount = s.lights.length;\n const sortCenter = [mesh.worldMatrix[12]!, mesh.worldMatrix[13]!, mesh.worldMatrix[14]!] as [number, number, number];\n const _baseUpdate = (): void => {\n const worldVersion = mesh.worldMatrixVersion;\n if (worldVersion !== _lastWorldVersion || s.lights.length !== _lastLightsCount) {\n sortCenter[0] = mesh.worldMatrix[12]!;\n sortCenter[1] = mesh.worldMatrix[13]!;\n sortCenter[2] = mesh.worldMatrix[14]!;\n _packMeshWorld(meshUboData, mesh.worldMatrix, 0, 0);\n writeMeshLightSelection(mesh, s.lights, meshUboData);\n device.queue.writeBuffer(meshUBO, 0, meshUboData as Float32Array<ArrayBuffer>);\n _lastWorldVersion = worldVersion;\n _lastLightsCount = s.lights.length;\n }\n const uboVersion = mat._uboVersion;\n if (uboVersion !== _lastUboVersion) {\n _lastUboVersion = uboVersion;\n _stdMatScratch.fill(0);\n writeStdMaterialData(_stdMatScratch, mat, textureLevel);\n device.queue.writeBuffer(materialUBO, 0, _stdMatScratch.buffer, 0, 96);\n }\n };\n // FO-version wrapper applied only when the engine has floating-origin\n // on. The wrapper lives in the dynamic-imported `floating-origin.ts`\n // module and is the sole owner of `_lastFoVersion` tracking. For\n // non-LWR engines `_wrapRenderableForFO` is undefined and `update`\n // is the bare closure — no FO bytes in the closure body.\n const _invalidate = (): void => {\n _lastWorldVersion = -1;\n };\n const update = engine._wrapRenderableForFO?.(_baseUpdate, s as SceneContext, _invalidate) ?? _baseUpdate;\n\n const draw = (pass: GPURenderPassEncoder | GPURenderBundleEncoder, cullBinding?: import(\"../../mesh/thin-instance-cull-binding.js\").TiCullBinding): number => {\n // For per-pass material overrides, skip the mesh.material === mat guard\n // because the override material is intentionally not the mesh's current one.\n if (!isOverride && mesh.material !== mat) {\n return 0;\n }\n const g = mesh._gpu;\n let slot = 0;\n const vb = g._vbLayout;\n pass.setVertexBuffer(slot++, g.positionBuffer, vb?._p?._offset);\n pass.setVertexBuffer(slot++, g.normalBuffer, vb?._n?._offset);\n if (needsUV) {\n pass.setVertexBuffer(slot++, g.uvBuffer, vb?._u?._offset);\n }\n if (needsUV2 && g.uv2Buffer) {\n pass.setVertexBuffer(slot++, g.uv2Buffer, vb?._u2?._offset);\n }\n\n const ti = hasThinInstances ? mesh.thinInstances : null;\n if (ti && tiSync) {\n slot = tiSync(engine, ti, pass, slot, hasInstanceColor, cullBinding?.cullDrawBufs);\n }\n\n pass.setIndexBuffer(g.indexBuffer, g.indexFormat);\n pass.setBindGroup(1, meshBindGroup);\n if (receiveShadows && shadowBindGroup) {\n pass.setBindGroup(2, shadowBindGroup);\n }\n if (cullBinding) {\n cullBinding.draw(pass, g.indexCount, ti!.count);\n } else if (ti && ti.count > 0) {\n pass.drawIndexed(g.indexCount, ti.count);\n } else {\n pass.drawIndexed(g.indexCount);\n }\n return 1;\n };\n\n const r: Renderable = {\n order: mesh.renderOrder ?? (isTransparent ? 200 : 100),\n isTransparent,\n mesh,\n bind(eng, sig) {\n const pipeline = getOrCreateStandardPipeline(eng as EngineContext, sig, bindings);\n // Opaque-only GPU culling (opt-in): tryBind gates on opt-in + transparency, returns the per-binding cull lifecycle.\n const cb = cull?.tryBind(r, s, mesh, engine, hasInstanceColor, isTransparent, update, sig);\n return {\n renderable: r,\n pipeline,\n update: cb ? cb.update : update,\n draw: (pass) => draw(pass, cb),\n };\n },\n };\n r._worldCenter = sortCenter;\n let _lastUboVersion = mat._uboVersion;\n return r;\n };\n\n const renderables = meshes.map((m) => rebuildSingle(scene, m));\n\n scene._disposables.push(\n () => clearStandardPipelineCache(),\n () => clearSamplerCache(engine)\n );\n\n return { renderables, rebuildSingle };\n}\n"],"names":[],"mappings":"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"}
|
package/lib/mesh/mesh-dispose.js
CHANGED
|
@@ -6,6 +6,7 @@ function disposeMeshGpu(mesh) {
|
|
|
6
6
|
g.indexBuffer.destroy();
|
|
7
7
|
g.tangentBuffer?.destroy();
|
|
8
8
|
g.uv2Buffer?.destroy();
|
|
9
|
+
g.colorBuffer?.destroy();
|
|
9
10
|
mesh.thinInstances?._gpuBuffer?.destroy();
|
|
10
11
|
mesh.thinInstances?._colorGpuBuffer?.destroy();
|
|
11
12
|
const sk = mesh.skeleton;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh-dispose.js","sources":["../../../src/mesh/mesh-dispose.ts"],"sourcesContent":["import type { Mesh } from \"./mesh.js\";\n\n/** Destroy all GPU resources owned by a mesh (vertex buffers, skeleton, morph targets). */\nexport function disposeMeshGpu(mesh: Mesh): void {\n const g = mesh._gpu;\n g.positionBuffer.destroy();\n g.normalBuffer.destroy();\n g.uvBuffer.destroy();\n g.indexBuffer.destroy();\n g.tangentBuffer?.destroy();\n g.uv2Buffer?.destroy();\n mesh.thinInstances?._gpuBuffer?.destroy();\n mesh.thinInstances?._colorGpuBuffer?.destroy();\n const sk = mesh.skeleton;\n if (sk) {\n sk.boneTexture.destroy();\n sk.jointsBuffer.destroy();\n sk.weightsBuffer.destroy();\n sk.joints1Buffer?.destroy();\n sk.weights1Buffer?.destroy();\n }\n if (mesh.morphTargets) {\n mesh.morphTargets.deltasBuffer.destroy();\n mesh.morphTargets.weightsBuffer.destroy();\n }\n}\n"],"names":[],"mappings":"AAGO,SAAS,eAAe,IAAA,EAAkB;AAC7C,EAAA,MAAM,IAAI,IAAA,CAAK,IAAA;AACf,EAAA,CAAA,CAAE,eAAe,OAAA,EAAQ;AACzB,EAAA,CAAA,CAAE,aAAa,OAAA,EAAQ;AACvB,EAAA,CAAA,CAAE,SAAS,OAAA,EAAQ;AACnB,EAAA,CAAA,CAAE,YAAY,OAAA,EAAQ;AACtB,EAAA,CAAA,CAAE,eAAe,OAAA,EAAQ;AACzB,EAAA,CAAA,CAAE,WAAW,OAAA,EAAQ;AACrB,EAAA,IAAA,CAAK,aAAA,EAAe,YAAY,OAAA,EAAQ;AACxC,EAAA,IAAA,CAAK,aAAA,EAAe,iBAAiB,OAAA,EAAQ;AAC7C,EAAA,MAAM,KAAK,IAAA,CAAK,QAAA;AAChB,EAAA,IAAI,EAAA,EAAI;AACJ,IAAA,EAAA,CAAG,YAAY,OAAA,EAAQ;AACvB,IAAA,EAAA,CAAG,aAAa,OAAA,EAAQ;AACxB,IAAA,EAAA,CAAG,cAAc,OAAA,EAAQ;AACzB,IAAA,EAAA,CAAG,eAAe,OAAA,EAAQ;AAC1B,IAAA,EAAA,CAAG,gBAAgB,OAAA,EAAQ;AAAA,EAC/B;AACA,EAAA,IAAI,KAAK,YAAA,EAAc;AACnB,IAAA,IAAA,CAAK,YAAA,CAAa,aAAa,OAAA,EAAQ;AACvC,IAAA,IAAA,CAAK,YAAA,CAAa,cAAc,OAAA,EAAQ;AAAA,EAC5C;AACJ;;;;"}
|
|
1
|
+
{"version":3,"file":"mesh-dispose.js","sources":["../../../src/mesh/mesh-dispose.ts"],"sourcesContent":["import type { Mesh } from \"./mesh.js\";\n\n/** Destroy all GPU resources owned by a mesh (vertex buffers, skeleton, morph targets). */\nexport function disposeMeshGpu(mesh: Mesh): void {\n const g = mesh._gpu;\n g.positionBuffer.destroy();\n g.normalBuffer.destroy();\n g.uvBuffer.destroy();\n g.indexBuffer.destroy();\n g.tangentBuffer?.destroy();\n g.uv2Buffer?.destroy();\n g.colorBuffer?.destroy();\n mesh.thinInstances?._gpuBuffer?.destroy();\n mesh.thinInstances?._colorGpuBuffer?.destroy();\n const sk = mesh.skeleton;\n if (sk) {\n sk.boneTexture.destroy();\n sk.jointsBuffer.destroy();\n sk.weightsBuffer.destroy();\n sk.joints1Buffer?.destroy();\n sk.weights1Buffer?.destroy();\n }\n if (mesh.morphTargets) {\n mesh.morphTargets.deltasBuffer.destroy();\n mesh.morphTargets.weightsBuffer.destroy();\n }\n}\n"],"names":[],"mappings":"AAGO,SAAS,eAAe,IAAA,EAAkB;AAC7C,EAAA,MAAM,IAAI,IAAA,CAAK,IAAA;AACf,EAAA,CAAA,CAAE,eAAe,OAAA,EAAQ;AACzB,EAAA,CAAA,CAAE,aAAa,OAAA,EAAQ;AACvB,EAAA,CAAA,CAAE,SAAS,OAAA,EAAQ;AACnB,EAAA,CAAA,CAAE,YAAY,OAAA,EAAQ;AACtB,EAAA,CAAA,CAAE,eAAe,OAAA,EAAQ;AACzB,EAAA,CAAA,CAAE,WAAW,OAAA,EAAQ;AACrB,EAAA,CAAA,CAAE,aAAa,OAAA,EAAQ;AACvB,EAAA,IAAA,CAAK,aAAA,EAAe,YAAY,OAAA,EAAQ;AACxC,EAAA,IAAA,CAAK,aAAA,EAAe,iBAAiB,OAAA,EAAQ;AAC7C,EAAA,MAAM,KAAK,IAAA,CAAK,QAAA;AAChB,EAAA,IAAI,EAAA,EAAI;AACJ,IAAA,EAAA,CAAG,YAAY,OAAA,EAAQ;AACvB,IAAA,EAAA,CAAG,aAAa,OAAA,EAAQ;AACxB,IAAA,EAAA,CAAG,cAAc,OAAA,EAAQ;AACzB,IAAA,EAAA,CAAG,eAAe,OAAA,EAAQ;AAC1B,IAAA,EAAA,CAAG,gBAAgB,OAAA,EAAQ;AAAA,EAC/B;AACA,EAAA,IAAI,KAAK,YAAA,EAAc;AACnB,IAAA,IAAA,CAAK,YAAA,CAAa,aAAa,OAAA,EAAQ;AACvC,IAAA,IAAA,CAAK,YAAA,CAAa,cAAc,OAAA,EAAQ;AAAA,EAC5C;AACJ;;;;"}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import { destroyTiCullState, prepareTiCull
|
|
1
|
+
import { createTiCullState, destroyTiCullState, prepareTiCull } from './thin-instance-gpu-culling.js';
|
|
2
2
|
|
|
3
|
-
function tryBind(renderable, scene, mesh, engine, hasColor, excluded, baseUpdate) {
|
|
3
|
+
function tryBind(renderable, scene, mesh, engine, hasColor, excluded, baseUpdate, signature) {
|
|
4
4
|
const ti = mesh.thinInstances;
|
|
5
5
|
if (excluded || !ti?._gpuCullingEnabled) {
|
|
6
6
|
return void 0;
|
|
7
7
|
}
|
|
8
8
|
renderable._direct = true;
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
const holder = renderable;
|
|
10
|
+
const cache = holder._tiCullStates ??= /* @__PURE__ */ new WeakMap();
|
|
11
|
+
let state = cache.get(signature);
|
|
12
|
+
if (!state) {
|
|
13
|
+
state = createTiCullState();
|
|
14
|
+
cache.set(signature, state);
|
|
15
|
+
const owned = state;
|
|
16
|
+
scene._meshDisposables.get(mesh)?.push(() => {
|
|
17
|
+
destroyTiCullState(owned);
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
state._localSphereReady = false;
|
|
21
|
+
}
|
|
13
22
|
const binding = {
|
|
14
23
|
cullDrawBufs: null,
|
|
15
24
|
_args: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thin-instance-cull-binding.js","sources":["../../../src/mesh/thin-instance-cull-binding.ts"],"sourcesContent":["/** Shared per-binding GPU frustum-culling lifecycle for thin-instanced renderables.\n *\n * Dynamically imported only when a scene enables thin-instance GPU culling, and\n * it statically pulls in the compute-cull module — so non-culling scenes fetch\n * neither this helper nor `thin-instance-gpu-culling.ts`.\n *\n * Factored here so Standard, PBR, and ShaderMaterial renderables share one\n * implementation of the cull lifecycle instead of copy-pasting it three times.\n * `tryBind` is the single seam a renderable's `bind()` calls: it does the\n * opaque-only gate + per-mesh `_gpuCullingEnabled` check, marks the renderable\n * `_direct` (read by the render task's buildBindings right after `bind()`\n * returns), and creates the per-binding state. The renderable then reads\n * `cullDrawBufs` for the compacted instance source and calls `binding.draw(...)`\n * for the indirect-vs-fallback draw call. Keeping these few seams tiny is what\n * lets non-culling scenes — which still fetch the per-material renderable\n * chunks — stay within their bundle-size ceilings. */\n\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { SceneContext } from \"../scene/scene.js\";\nimport type { DrawUpdateContext, Renderable } from \"../render/renderable.js\";\nimport type { Mesh } from \"./mesh.js\";\nimport type { ThinInstanceDrawBuffers } from \"./thin-instance-gpu.js\";\nimport { createTiCullState, destroyTiCullState, prepareTiCull } from \"./thin-instance-gpu-culling.js\";\n\n/** Per-binding cull lifecycle. The renderable's `bind()` obtains one from\n * `tryBind`, uses `update` as the binding's update, reads `cullDrawBufs` (the\n * compacted instance source) and calls `draw()` for the final draw call. */\nexport interface TiCullBinding {\n /** Run the binding's base update, then dispatch the compute cull pass and stash the result. */\n update(context: DrawUpdateContext): void;\n /** Compacted visible-instance buffers, or null to fall back to a full instanced draw. */\n cullDrawBufs: ThinInstanceDrawBuffers | null;\n /** @internal Indirect draw-args buffer (null until/unless culling ran this frame). */\n _args: GPUBuffer | null;\n /** Issue the indirect (culled) draw when visible instances were compacted, else a full instanced draw. */\n draw(pass: GPURenderPassEncoder | GPURenderBundleEncoder, indexCount: number, instanceCount: number): void;\n}\n\n/** Create a per-binding cull lifecycle for one thin-instanced renderable binding,\n * iff the mesh opts in and is not excluded (transparent / transmissive — v1 is\n * opaque-only). Marks the renderable `_direct` so it leaves the cached opaque\n * bundle; this is safe to do during `bind()` because buildBindings reads\n * `_direct` only after `bind()` returns. Returns undefined when culling does not\n * apply, so the caller falls back to a normal instanced draw. */\nexport function tryBind(\n renderable: Renderable,\n scene: SceneContext,\n mesh: Mesh,\n engine: EngineContext,\n hasColor: boolean,\n excluded: boolean,\n baseUpdate: ((context: DrawUpdateContext) => void) | undefined\n): TiCullBinding | undefined {\n const ti = mesh.thinInstances;\n if (excluded || !ti?._gpuCullingEnabled) {\n return undefined;\n }\n (renderable as { _direct?: boolean })._direct = true;\n const state = createTiCullState();\n
|
|
1
|
+
{"version":3,"file":"thin-instance-cull-binding.js","sources":["../../../src/mesh/thin-instance-cull-binding.ts"],"sourcesContent":["/** Shared per-binding GPU frustum-culling lifecycle for thin-instanced renderables.\n *\n * Dynamically imported only when a scene enables thin-instance GPU culling, and\n * it statically pulls in the compute-cull module — so non-culling scenes fetch\n * neither this helper nor `thin-instance-gpu-culling.ts`.\n *\n * Factored here so Standard, PBR, and ShaderMaterial renderables share one\n * implementation of the cull lifecycle instead of copy-pasting it three times.\n * `tryBind` is the single seam a renderable's `bind()` calls: it does the\n * opaque-only gate + per-mesh `_gpuCullingEnabled` check, marks the renderable\n * `_direct` (read by the render task's buildBindings right after `bind()`\n * returns), and creates the per-binding state. The renderable then reads\n * `cullDrawBufs` for the compacted instance source and calls `binding.draw(...)`\n * for the indirect-vs-fallback draw call. Keeping these few seams tiny is what\n * lets non-culling scenes — which still fetch the per-material renderable\n * chunks — stay within their bundle-size ceilings. */\n\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { SceneContext } from \"../scene/scene.js\";\nimport type { DrawUpdateContext, Renderable } from \"../render/renderable.js\";\nimport type { Mesh } from \"./mesh.js\";\nimport type { ThinInstanceDrawBuffers } from \"./thin-instance-gpu.js\";\nimport { createTiCullState, destroyTiCullState, prepareTiCull, type ThinInstanceGpuCullState } from \"./thin-instance-gpu-culling.js\";\n\n/** Per-binding cull lifecycle. The renderable's `bind()` obtains one from\n * `tryBind`, uses `update` as the binding's update, reads `cullDrawBufs` (the\n * compacted instance source) and calls `draw()` for the final draw call. */\nexport interface TiCullBinding {\n /** Run the binding's base update, then dispatch the compute cull pass and stash the result. */\n update(context: DrawUpdateContext): void;\n /** Compacted visible-instance buffers, or null to fall back to a full instanced draw. */\n cullDrawBufs: ThinInstanceDrawBuffers | null;\n /** @internal Indirect draw-args buffer (null until/unless culling ran this frame). */\n _args: GPUBuffer | null;\n /** Issue the indirect (culled) draw when visible instances were compacted, else a full instanced draw. */\n draw(pass: GPURenderPassEncoder | GPURenderBundleEncoder, indexCount: number, instanceCount: number): void;\n}\n\n/** @internal Renderable augmented with its per-signature cull-state cache (see `tryBind`). */\ntype CullCachingRenderable = Renderable & { _tiCullStates?: WeakMap<RenderTargetSignature, ThinInstanceGpuCullState> };\n\n/** Create a per-binding cull lifecycle for one thin-instanced renderable binding,\n * iff the mesh opts in and is not excluded (transparent / transmissive — v1 is\n * opaque-only). Marks the renderable `_direct` so it leaves the cached opaque\n * bundle; this is safe to do during `bind()` because buildBindings reads\n * `_direct` only after `bind()` returns. Returns undefined when culling does not\n * apply, so the caller falls back to a normal instanced draw.\n *\n * The cull STATE (visible/args/params GPU buffers) is REUSED across re-binds: it\n * is cached on the renderable, keyed by the pass's render-target signature.\n * `buildBindings` re-binds every renderable on each `_renderableVersion` bump\n * (i.e. on ANY geometry edit anywhere in the scene), so allocating a fresh state\n * here each time both leaked the previous state's buffers (freed only on mesh\n * dispose) AND churned Dawn's allocator by reallocating these buffers every edit\n * — multi-MB per edit. Reusing keeps `ensureCullBuffers` a no-op when the\n * instance capacity is unchanged. Keying by signature keeps a renderable drawn\n * in several passes (e.g. main + shadow) on an independent cull state per pass.\n * Each cached state is freed once, on mesh disposal. */\nexport function tryBind(\n renderable: Renderable,\n scene: SceneContext,\n mesh: Mesh,\n engine: EngineContext,\n hasColor: boolean,\n excluded: boolean,\n baseUpdate: ((context: DrawUpdateContext) => void) | undefined,\n signature: RenderTargetSignature\n): TiCullBinding | undefined {\n const ti = mesh.thinInstances;\n if (excluded || !ti?._gpuCullingEnabled) {\n return undefined;\n }\n (renderable as { _direct?: boolean })._direct = true;\n const holder = renderable as CullCachingRenderable;\n const cache = (holder._tiCullStates ??= new WeakMap());\n let state = cache.get(signature);\n if (!state) {\n state = createTiCullState();\n cache.set(signature, state);\n const owned = state;\n scene._meshDisposables.get(mesh)?.push(() => {\n destroyTiCullState(owned);\n });\n } else {\n // The mesh geometry may have been resized since the last bind (resizeMeshGeometry bumps the renderable\n // version, which re-binds us); recompute the local bounding sphere so culling stays accurate.\n state._localSphereReady = false;\n }\n const binding: TiCullBinding = {\n cullDrawBufs: null,\n _args: null,\n update(context: DrawUpdateContext): void {\n baseUpdate?.(context);\n const res = prepareTiCull(engine, state, mesh, mesh._gpu, ti, hasColor, context);\n binding.cullDrawBufs = res?.drawBuffers ?? null;\n binding._args = res?.argsBuffer ?? null;\n },\n draw(pass: GPURenderPassEncoder | GPURenderBundleEncoder, indexCount: number, instanceCount: number): void {\n if (binding._args) {\n pass.drawIndexedIndirect(binding._args, 0);\n } else {\n pass.drawIndexed(indexCount, instanceCount);\n }\n },\n };\n return binding;\n}\n"],"names":[],"mappings":";;AA2DO,SAAS,OAAA,CACZ,YACA,KAAA,EACA,IAAA,EACA,QACA,QAAA,EACA,QAAA,EACA,YACA,SAAA,EACyB;AACzB,EAAA,MAAM,KAAK,IAAA,CAAK,aAAA;AAChB,EAAA,IAAI,QAAA,IAAY,CAAC,EAAA,EAAI,kBAAA,EAAoB;AACrC,IAAA,OAAO,MAAA;AAAA,EACX;AACA,EAAC,WAAqC,OAAA,GAAU,IAAA;AAChD,EAAA,MAAM,MAAA,GAAS,UAAA;AACf,EAAA,MAAM,KAAA,GAAS,MAAA,CAAO,aAAA,qBAAkB,IAAI,OAAA,EAAQ;AACpD,EAAA,IAAI,KAAA,GAAQ,KAAA,CAAM,GAAA,CAAI,SAAS,CAAA;AAC/B,EAAA,IAAI,CAAC,KAAA,EAAO;AACR,IAAA,KAAA,GAAQ,iBAAA,EAAkB;AAC1B,IAAA,KAAA,CAAM,GAAA,CAAI,WAAW,KAAK,CAAA;AAC1B,IAAA,MAAM,KAAA,GAAQ,KAAA;AACd,IAAA,KAAA,CAAM,gBAAA,CAAiB,GAAA,CAAI,IAAI,CAAA,EAAG,KAAK,MAAM;AACzC,MAAA,kBAAA,CAAmB,KAAK,CAAA;AAAA,IAC5B,CAAC,CAAA;AAAA,EACL,CAAA,MAAO;AAGH,IAAA,KAAA,CAAM,iBAAA,GAAoB,KAAA;AAAA,EAC9B;AACA,EAAA,MAAM,OAAA,GAAyB;AAAA,IAC3B,YAAA,EAAc,IAAA;AAAA,IACd,KAAA,EAAO,IAAA;AAAA,IACP,OAAO,OAAA,EAAkC;AACrC,MAAA,UAAA,GAAa,OAAO,CAAA;AACpB,MAAA,MAAM,GAAA,GAAM,cAAc,MAAA,EAAQ,KAAA,EAAO,MAAM,IAAA,CAAK,IAAA,EAAM,EAAA,EAAI,QAAA,EAAU,OAAO,CAAA;AAC/E,MAAA,OAAA,CAAQ,YAAA,GAAe,KAAK,WAAA,IAAe,IAAA;AAC3C,MAAA,OAAA,CAAQ,KAAA,GAAQ,KAAK,UAAA,IAAc,IAAA;AAAA,IACvC,CAAA;AAAA,IACA,IAAA,CAAK,IAAA,EAAqD,UAAA,EAAoB,aAAA,EAA6B;AACvG,MAAA,IAAI,QAAQ,KAAA,EAAO;AACf,QAAA,IAAA,CAAK,mBAAA,CAAoB,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAAA,MAC7C,CAAA,MAAO;AACH,QAAA,IAAA,CAAK,WAAA,CAAY,YAAY,aAAa,CAAA;AAAA,MAC9C;AAAA,IACJ;AAAA,GACJ;AACA,EAAA,OAAO,OAAA;AACX;;;;"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { F32 } from '../engine/typed-arrays.js';
|
|
2
|
+
import { createRenderTarget, disposeRenderTarget, buildRenderTarget } from '../engine/render-target.js';
|
|
3
|
+
import { createPostProcessTask } from '../frame-graph/post-process-task.js';
|
|
4
|
+
|
|
5
|
+
const TAA_HISTORY_TEXTURE_WGSL = `@group(0) @binding(2) var taaHistory:texture_2d<f32>;`;
|
|
6
|
+
const TAA_UNIFORM_WGSL = `struct TaaParams{factor:f32,p0:f32,p1:f32,p2:f32}
|
|
7
|
+
@group(0) @binding(3) var<uniform> taaParams:TaaParams;`;
|
|
8
|
+
const TAA_FRAGMENT_WGSL = `fn applyPostProcess(color:vec4f, uv:vec2f)->vec4f{let h=textureSample(taaHistory,sourceSampler,uv);return mix(h,color,taaParams.factor);}`;
|
|
9
|
+
const TAA_COPY_FRAGMENT_WGSL = `fn applyPostProcess(color:vec4f, uv:vec2f)->vec4f{return color;}`;
|
|
10
|
+
function createTaaPostProcessTask(config, engine, scene) {
|
|
11
|
+
const name = config.name ?? "taa";
|
|
12
|
+
const source = config.sourceTexture;
|
|
13
|
+
const target = config.targetTexture ?? null;
|
|
14
|
+
const samples = Math.max(1, Math.floor(config.samples ?? 8));
|
|
15
|
+
const sizeRef = source._descriptor.size;
|
|
16
|
+
const history = createRenderTarget({ lbl: `${name}-history`, format: "rgba16float", samples: 1, size: sizeRef });
|
|
17
|
+
const temp = createRenderTarget({ lbl: `${name}-temp`, format: "rgba16float", samples: 1, size: sizeRef });
|
|
18
|
+
const blend = createPostProcessTask(
|
|
19
|
+
{
|
|
20
|
+
name: `${name}-blend`,
|
|
21
|
+
sourceTexture: source,
|
|
22
|
+
// Nearest sampling reads the exact co-located texel of both the current
|
|
23
|
+
// frame and the history (all three targets share a resolution).
|
|
24
|
+
sourceSamplingMode: "nearest",
|
|
25
|
+
targetTexture: temp,
|
|
26
|
+
_shader: {
|
|
27
|
+
extraTextureWGSL: TAA_HISTORY_TEXTURE_WGSL,
|
|
28
|
+
extraTextures: [history],
|
|
29
|
+
uniformWGSL: TAA_UNIFORM_WGSL,
|
|
30
|
+
uniformBinding: 3,
|
|
31
|
+
uniformByteLength: 16,
|
|
32
|
+
writeUniforms(data) {
|
|
33
|
+
data[0] = task._factor;
|
|
34
|
+
},
|
|
35
|
+
fragmentWGSL: TAA_FRAGMENT_WGSL
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
engine,
|
|
39
|
+
scene
|
|
40
|
+
);
|
|
41
|
+
const present = createPostProcessTask(
|
|
42
|
+
{
|
|
43
|
+
name: `${name}-present`,
|
|
44
|
+
sourceTexture: temp,
|
|
45
|
+
sourceSamplingMode: "nearest",
|
|
46
|
+
targetTexture: target ?? engine.scRT,
|
|
47
|
+
_shader: { fragmentWGSL: TAA_COPY_FRAGMENT_WGSL }
|
|
48
|
+
},
|
|
49
|
+
engine,
|
|
50
|
+
scene
|
|
51
|
+
);
|
|
52
|
+
const historyUpdate = createPostProcessTask(
|
|
53
|
+
{
|
|
54
|
+
name: `${name}-history-update`,
|
|
55
|
+
sourceTexture: temp,
|
|
56
|
+
sourceSamplingMode: "nearest",
|
|
57
|
+
targetTexture: history,
|
|
58
|
+
_shader: { fragmentWGSL: TAA_COPY_FRAGMENT_WGSL }
|
|
59
|
+
},
|
|
60
|
+
engine,
|
|
61
|
+
scene
|
|
62
|
+
);
|
|
63
|
+
const task = {
|
|
64
|
+
name,
|
|
65
|
+
engine,
|
|
66
|
+
scene,
|
|
67
|
+
_passes: [],
|
|
68
|
+
sourceTexture: source,
|
|
69
|
+
targetTexture: target,
|
|
70
|
+
outputTexture: target ?? engine.scRT,
|
|
71
|
+
factor: config.factor ?? 0.05,
|
|
72
|
+
samples,
|
|
73
|
+
disableOnCameraMove: config.disableOnCameraMove ?? true,
|
|
74
|
+
_blend: blend,
|
|
75
|
+
_present: present,
|
|
76
|
+
_historyUpdate: historyUpdate,
|
|
77
|
+
_history: history,
|
|
78
|
+
_temp: temp,
|
|
79
|
+
_sourceRenderTask: config.sourceRenderTask,
|
|
80
|
+
_halton: generateHalton(samples),
|
|
81
|
+
_haltonIndex: 0,
|
|
82
|
+
_jitterScratch: new F32(16),
|
|
83
|
+
_firstUpdate: true,
|
|
84
|
+
_lastCamVer: -1,
|
|
85
|
+
_factor: 1,
|
|
86
|
+
record() {
|
|
87
|
+
const { width: w, height: h } = resolveSourceSize(task.sourceTexture);
|
|
88
|
+
ensurePersistentTarget(history, engine, w, h);
|
|
89
|
+
ensurePersistentTarget(temp, engine, w, h);
|
|
90
|
+
blend.record();
|
|
91
|
+
present.record();
|
|
92
|
+
historyUpdate.record();
|
|
93
|
+
task._firstUpdate = true;
|
|
94
|
+
task._haltonIndex = 0;
|
|
95
|
+
task._lastCamVer = -1;
|
|
96
|
+
},
|
|
97
|
+
execute() {
|
|
98
|
+
const cam = task._sourceRenderTask.scene.camera;
|
|
99
|
+
const camVer = cam ? cam.worldMatrixVersion : 0;
|
|
100
|
+
const moved = camVer !== task._lastCamVer;
|
|
101
|
+
task._lastCamVer = camVer;
|
|
102
|
+
const reset = task._firstUpdate || moved && task.disableOnCameraMove;
|
|
103
|
+
task._factor = reset ? 1 : task.factor;
|
|
104
|
+
blend.updateUniforms();
|
|
105
|
+
let draws = blend.execute?.() ?? 0;
|
|
106
|
+
draws += present.execute?.() ?? 0;
|
|
107
|
+
draws += historyUpdate.execute?.() ?? 0;
|
|
108
|
+
task._firstUpdate = false;
|
|
109
|
+
advanceJitter(task);
|
|
110
|
+
return draws;
|
|
111
|
+
},
|
|
112
|
+
updateUniforms() {
|
|
113
|
+
blend.updateUniforms();
|
|
114
|
+
},
|
|
115
|
+
dispose() {
|
|
116
|
+
task._passes.length = 0;
|
|
117
|
+
blend.dispose();
|
|
118
|
+
present.dispose();
|
|
119
|
+
historyUpdate.dispose();
|
|
120
|
+
history._eager = false;
|
|
121
|
+
temp._eager = false;
|
|
122
|
+
disposeRenderTarget(history);
|
|
123
|
+
disposeRenderTarget(temp);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
return task;
|
|
127
|
+
}
|
|
128
|
+
function ensurePersistentTarget(rt, engine, width, height) {
|
|
129
|
+
if (rt._eager && rt._width === width && rt._height === height) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
rt._eager = false;
|
|
133
|
+
disposeRenderTarget(rt);
|
|
134
|
+
rt._descriptor.size = { width, height };
|
|
135
|
+
buildRenderTarget(rt, engine);
|
|
136
|
+
rt._eager = true;
|
|
137
|
+
}
|
|
138
|
+
function resolveSourceSize(source) {
|
|
139
|
+
if (source._width > 0 && source._height > 0) {
|
|
140
|
+
return { width: source._width, height: source._height };
|
|
141
|
+
}
|
|
142
|
+
const size = source._descriptor.size;
|
|
143
|
+
if ("canvas" in size) {
|
|
144
|
+
return { width: size.canvas.width, height: size.canvas.height };
|
|
145
|
+
}
|
|
146
|
+
return { width: size.width, height: size.height };
|
|
147
|
+
}
|
|
148
|
+
function generateHalton(samples) {
|
|
149
|
+
const seq = new F32(samples * 2);
|
|
150
|
+
for (let i = 1; i <= samples; i++) {
|
|
151
|
+
seq[(i - 1) * 2] = halton(i, 2) - 0.5;
|
|
152
|
+
seq[(i - 1) * 2 + 1] = halton(i, 3) - 0.5;
|
|
153
|
+
}
|
|
154
|
+
return seq;
|
|
155
|
+
}
|
|
156
|
+
function halton(index, base) {
|
|
157
|
+
let fraction = 1;
|
|
158
|
+
let result = 0;
|
|
159
|
+
while (index > 0) {
|
|
160
|
+
fraction /= base;
|
|
161
|
+
result += fraction * (index % base);
|
|
162
|
+
index = Math.floor(index / base);
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
function advanceJitter(task) {
|
|
167
|
+
const src = task._sourceRenderTask;
|
|
168
|
+
const clean = src._suData;
|
|
169
|
+
const w = task.sourceTexture._width;
|
|
170
|
+
const h = task.sourceTexture._height;
|
|
171
|
+
if (w <= 0 || h <= 0) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const jx = task._halton[task._haltonIndex] / (w / 2);
|
|
175
|
+
const jy = task._halton[task._haltonIndex + 1] / (h / 2);
|
|
176
|
+
task._haltonIndex += 2;
|
|
177
|
+
if (task._haltonIndex >= task._halton.length) {
|
|
178
|
+
task._haltonIndex = 0;
|
|
179
|
+
}
|
|
180
|
+
const out = task._jitterScratch;
|
|
181
|
+
for (let c = 0; c < 4; c++) {
|
|
182
|
+
const b = c * 4;
|
|
183
|
+
const w3 = clean[b + 3];
|
|
184
|
+
out[b] = clean[b] + jx * w3;
|
|
185
|
+
out[b + 1] = clean[b + 1] + jy * w3;
|
|
186
|
+
out[b + 2] = clean[b + 2];
|
|
187
|
+
out[b + 3] = w3;
|
|
188
|
+
}
|
|
189
|
+
task.engine._device.queue.writeBuffer(src._sceneUBO, 0, out);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export { createTaaPostProcessTask };
|
|
193
|
+
//# sourceMappingURL=taa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taa.js","sources":["../../../src/post-process/taa.ts"],"sourcesContent":["// Temporal Anti-Aliasing (TAA) — a frame-graph post-process task.\n//\n// TAA jitters the camera projection by a sub-pixel Halton offset every frame and\n// accumulates a moving average of consecutive (jittered) frames. Spreading the\n// supersampling over time yields high-quality edge anti-aliasing without rendering\n// the scene multiple times per frame. The accumulated history converges to a\n// supersampled image after a few dozen frames.\n//\n// This task is a pure frame-graph node: add it at the END of a chain whose source\n// render task draws the scene into `sourceTexture`. Each frame it:\n// 1. blend : temp = mix(history, current, factor) (history bound as extra)\n// 2. present : temp -> targetTexture (e.g. the swapchain)\n// 3. historyUpd : temp -> history (becomes next frame's history)\n// 4. advances the Halton sequence and writes the jittered viewProjection into the\n// *source render task's* scene UBO so the NEXT frame renders sub-pixel shifted.\n//\n// `factor` is the blend weight of the current frame (BJS default 0.05). On the first\n// frame and on a camera-move reset it is forced to 1 (output == current) so no stale\n// history bleeds in.\n//\n// The jitter is injected by overwriting only the viewProjection slice (bytes 0..63)\n// of the source task's already-packed scene UBO. The source task's UBO write is\n// cached on the camera's worldMatrixVersion, so with a static camera our jittered\n// matrix survives each frame; when the camera moves the source re-packs a clean\n// matrix (a natural reset) and we set factor=1 for that frame. This needs zero\n// changes to the shared camera / scene-uniform hot path — so scenes that do not use\n// TAA pay nothing.\n\nimport { F32 } from \"../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport { buildRenderTarget, createRenderTarget, disposeRenderTarget } from \"../engine/render-target.js\";\nimport { createPostProcessTask, type PostProcessTask, type PostProcessTaskSettings } from \"../frame-graph/post-process-task.js\";\nimport type { RenderTask } from \"../frame-graph/render-task.js\";\nimport type { Task } from \"../frame-graph/task.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\n\n/** Configuration for `createTaaPostProcessTask`. */\nexport interface TaaPostProcessTaskConfig extends PostProcessTaskSettings {\n /** The render task that draws the scene into `sourceTexture`. TAA jitters this\n * task's camera projection each frame (mirrors BJS `FrameGraphTAATask.objectRendererTask`). */\n sourceRenderTask: RenderTask;\n /** Blend weight of the current frame against the accumulated history (default: 0.05). */\n factor?: number;\n /** Number of jitter samples in the Halton sequence (default: 8). */\n samples?: number;\n /** Force a one-frame reset (output == current) whenever the camera moves (default: true).\n * Avoids ghosting while the view changes. */\n disableOnCameraMove?: boolean;\n}\n\n/** A Temporal Anti-Aliasing post-process task: accumulates jittered frames into an\n * anti-aliased image. Inject at the end of a frame-graph chain. */\nexport interface TaaPostProcessTask extends Task, PostProcessTaskSettings {\n readonly name: string;\n sourceTexture: RenderTarget;\n targetTexture: RenderTarget | null;\n outputTexture: RenderTarget;\n /** Blend weight of the current frame (smaller = smoother / slower convergence). */\n factor: number;\n /** Number of Halton jitter samples. */\n readonly samples: number;\n /** Reset to the current frame whenever the camera moves. */\n disableOnCameraMove: boolean;\n /** Recompute and upload the blend pass uniforms from current settings. */\n updateUniforms(): void;\n}\n\ninterface TaaTaskInternal extends TaaPostProcessTask {\n _blend: PostProcessTask;\n _present: PostProcessTask;\n _historyUpdate: PostProcessTask;\n _history: RenderTarget;\n _temp: RenderTarget;\n _sourceRenderTask: RenderTask;\n /** Raw Halton offsets in [-0.5, 0.5): [x0,y0, x1,y1, ...]. Scaled per-frame by source size. */\n _halton: Float32Array;\n _haltonIndex: number;\n _jitterScratch: Float32Array;\n _firstUpdate: boolean;\n _lastCamVer: number;\n _factor: number;\n}\n\nconst TAA_HISTORY_TEXTURE_WGSL = `@group(0) @binding(2) var taaHistory:texture_2d<f32>;`;\n\nconst TAA_UNIFORM_WGSL = `struct TaaParams{factor:f32,p0:f32,p1:f32,p2:f32}\n@group(0) @binding(3) var<uniform> taaParams:TaaParams;`;\n\n// mix(history, current, factor): factor=1 -> current only (first frame / reset).\nconst TAA_FRAGMENT_WGSL = `fn applyPostProcess(color:vec4f, uv:vec2f)->vec4f{let h=textureSample(taaHistory,sourceSampler,uv);return mix(h,color,taaParams.factor);}`;\n\n// Identity passthrough used by the present + history-update copies.\nconst TAA_COPY_FRAGMENT_WGSL = `fn applyPostProcess(color:vec4f, uv:vec2f)->vec4f{return color;}`;\n\n/**\n * Create a Temporal Anti-Aliasing post-process task.\n * @param config - Source texture + source render task, blend factor, sample count.\n * @param engine - The owning engine.\n * @param scene - Optional owning scene.\n * @returns The TAA post-process task. Add it at the end of the frame-graph chain.\n */\nexport function createTaaPostProcessTask(config: TaaPostProcessTaskConfig, engine: EngineContext, scene?: SceneContext): TaaPostProcessTask {\n const name = config.name ?? \"taa\";\n const source = config.sourceTexture;\n const target = config.targetTexture ?? null;\n // Clamp to >= 1: a zero/negative sample count would make `generateHalton` return an\n // empty sequence and `advanceJitter` write NaN jitter offsets into the source UBO.\n const samples = Math.max(1, Math.floor(config.samples ?? 8));\n const sizeRef = source._descriptor.size;\n\n // History accumulates at RGBA16F so the 0.05 moving average does not band on\n // an 8-bit buffer (matches BJS half-float history).\n const history = createRenderTarget({ lbl: `${name}-history`, format: \"rgba16float\", samples: 1, size: sizeRef });\n const temp = createRenderTarget({ lbl: `${name}-temp`, format: \"rgba16float\", samples: 1, size: sizeRef });\n\n const blend = createPostProcessTask(\n {\n name: `${name}-blend`,\n sourceTexture: source,\n // Nearest sampling reads the exact co-located texel of both the current\n // frame and the history (all three targets share a resolution).\n sourceSamplingMode: \"nearest\",\n targetTexture: temp,\n _shader: {\n extraTextureWGSL: TAA_HISTORY_TEXTURE_WGSL,\n extraTextures: [history],\n uniformWGSL: TAA_UNIFORM_WGSL,\n uniformBinding: 3,\n uniformByteLength: 16,\n writeUniforms(data) {\n data[0] = task._factor;\n },\n fragmentWGSL: TAA_FRAGMENT_WGSL,\n },\n },\n engine,\n scene\n );\n const present = createPostProcessTask(\n {\n name: `${name}-present`,\n sourceTexture: temp,\n sourceSamplingMode: \"nearest\",\n targetTexture: target ?? engine.scRT,\n _shader: { fragmentWGSL: TAA_COPY_FRAGMENT_WGSL },\n },\n engine,\n scene\n );\n const historyUpdate = createPostProcessTask(\n {\n name: `${name}-history-update`,\n sourceTexture: temp,\n sourceSamplingMode: \"nearest\",\n targetTexture: history,\n _shader: { fragmentWGSL: TAA_COPY_FRAGMENT_WGSL },\n },\n engine,\n scene\n );\n\n const task: TaaTaskInternal = {\n name,\n engine,\n scene,\n _passes: [],\n sourceTexture: source,\n targetTexture: target,\n outputTexture: target ?? engine.scRT,\n factor: config.factor ?? 0.05,\n samples,\n disableOnCameraMove: config.disableOnCameraMove ?? true,\n _blend: blend,\n _present: present,\n _historyUpdate: historyUpdate,\n _history: history,\n _temp: temp,\n _sourceRenderTask: config.sourceRenderTask,\n _halton: generateHalton(samples),\n _haltonIndex: 0,\n _jitterScratch: new F32(16),\n _firstUpdate: true,\n _lastCamVer: -1,\n _factor: 1,\n record(): void {\n // History + temp are persistent ping-pong buffers: allocate them once\n // (eager), sized to the source, and only reallocate on a real size change.\n // Marking them eager makes the sub-tasks' internal `buildRenderTarget`\n // no-op on them — critical because `historyUpdate` targets `history`, and a\n // rebuild there would destroy the texture `blend`'s bind group references.\n const { width: w, height: h } = resolveSourceSize(task.sourceTexture);\n ensurePersistentTarget(history, engine, w, h);\n ensurePersistentTarget(temp, engine, w, h);\n blend.record();\n present.record();\n historyUpdate.record();\n task._firstUpdate = true;\n task._haltonIndex = 0;\n task._lastCamVer = -1;\n },\n execute(): number {\n const cam = task._sourceRenderTask.scene.camera;\n const camVer = cam ? cam.worldMatrixVersion : 0;\n const moved = camVer !== task._lastCamVer;\n task._lastCamVer = camVer;\n\n // factor=1 on the first frame and on camera-move reset: take the current\n // (un-jittered) frame verbatim, discarding stale history.\n const reset = task._firstUpdate || (moved && task.disableOnCameraMove);\n task._factor = reset ? 1 : task.factor;\n blend.updateUniforms();\n\n let draws = blend.execute?.() ?? 0;\n draws += present.execute?.() ?? 0;\n draws += historyUpdate.execute?.() ?? 0;\n\n task._firstUpdate = false;\n\n // Prepare the NEXT frame's jitter: advance the Halton sequence and write the\n // jittered viewProjection into the source task's UBO. Always done — even on a\n // reset frame — so accumulation starts immediately on the following frame.\n // The blend `factor` reset already prevents stale-history bleed, and a still-\n // moving camera re-packs a clean matrix next frame anyway (overwriting this).\n advanceJitter(task);\n return draws;\n },\n updateUniforms(): void {\n blend.updateUniforms();\n },\n dispose(): void {\n task._passes.length = 0;\n blend.dispose();\n present.dispose();\n historyUpdate.dispose();\n // Clear the eager flag so the persistent buffers are actually freed.\n history._eager = false;\n temp._eager = false;\n disposeRenderTarget(history);\n disposeRenderTarget(temp);\n },\n };\n return task;\n}\n\n/** Allocate (or, on a size change, reallocate) a persistent ping-pong target sized\n * `width`×`height`. The target is marked `_eager` so the post-process sub-tasks'\n * internal `buildRenderTarget` no-ops on it, keeping accumulated history alive across\n * frames and preventing a rebuild from destroying a texture still bound elsewhere. */\nfunction ensurePersistentTarget(rt: RenderTarget, engine: EngineContext, width: number, height: number): void {\n if (rt._eager && rt._width === width && rt._height === height) {\n return;\n }\n rt._eager = false;\n disposeRenderTarget(rt);\n rt._descriptor.size = { width, height };\n buildRenderTarget(rt, engine);\n rt._eager = true;\n}\n\n/** Resolve a render target's pixel size: prefer its allocated dimensions, falling back\n * to the descriptor's surface (multi-surface safe — does not assume the engine canvas)\n * or explicit pixel size before the target has been built. */\nfunction resolveSourceSize(source: RenderTarget): { width: number; height: number } {\n if (source._width > 0 && source._height > 0) {\n return { width: source._width, height: source._height };\n }\n const size = source._descriptor.size;\n if (\"canvas\" in size) {\n return { width: size.canvas.width, height: size.canvas.height };\n }\n return { width: size.width, height: size.height };\n}\n\n/** Generate `samples` 2D Halton offsets (base 2 / base 3) centered on [-0.5, 0.5). */\nfunction generateHalton(samples: number): Float32Array {\n const seq = new F32(samples * 2);\n for (let i = 1; i <= samples; i++) {\n seq[(i - 1) * 2] = halton(i, 2) - 0.5;\n seq[(i - 1) * 2 + 1] = halton(i, 3) - 0.5;\n }\n return seq;\n}\n\nfunction halton(index: number, base: number): number {\n let fraction = 1;\n let result = 0;\n while (index > 0) {\n fraction /= base;\n result += fraction * (index % base);\n index = Math.floor(index / base);\n }\n return result;\n}\n\n/** Advance the Halton sequence and overwrite the source task's viewProjection\n * (column-major bytes 0..63 of its scene UBO) with a sub-pixel jittered matrix. */\nfunction advanceJitter(task: TaaTaskInternal): void {\n const src = task._sourceRenderTask;\n const clean = src._suData;\n const w = task.sourceTexture._width;\n const h = task.sourceTexture._height;\n if (w <= 0 || h <= 0) {\n return;\n }\n\n // NDC sub-pixel offset: one pixel spans 2/size in NDC, so size/2 is the denominator.\n const jx = task._halton[task._haltonIndex]! / (w / 2);\n const jy = task._halton[task._haltonIndex + 1]! / (h / 2);\n task._haltonIndex += 2;\n if (task._haltonIndex >= task._halton.length) {\n task._haltonIndex = 0;\n }\n\n // Translate the projected image by (jx, jy) in NDC: clip.xy += (jx,jy)*clip.w.\n // Column-major: row r, col c lives at c*4+r. Add j*row3 to row0 / row1.\n const out = task._jitterScratch;\n for (let c = 0; c < 4; c++) {\n const b = c * 4;\n const w3 = clean[b + 3]!;\n out[b] = clean[b]! + jx * w3;\n out[b + 1] = clean[b + 1]! + jy * w3;\n out[b + 2] = clean[b + 2]!;\n out[b + 3] = w3;\n }\n task.engine._device.queue.writeBuffer(src._sceneUBO, 0, out as Float32Array<ArrayBuffer>);\n}\n"],"names":[],"mappings":"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"}
|
package/lib/scene/scene-core.js
CHANGED