@babylonjs/lite 1.11.0 → 1.13.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/CHANGELOG.md +35 -0
- package/dist/index.js +444 -368
- package/dist/index.js.map +1 -1
- package/index.d.ts +208 -6
- package/lib/asset-container.js.map +1 -1
- package/lib/audio/index.js +1 -0
- package/lib/audio/index.js.map +1 -1
- package/lib/audio/media-stream-output.js +44 -0
- package/lib/audio/media-stream-output.js.map +1 -0
- package/lib/engine/engine.js +1 -1
- package/lib/frame-graph/render-task.js +1 -1
- package/lib/frame-graph/render-task.js.map +1 -1
- package/lib/frame-graph/shadow-inputs.js +10 -1
- package/lib/frame-graph/shadow-inputs.js.map +1 -1
- package/lib/frame-graph/transmission.js +1 -16
- package/lib/frame-graph/transmission.js.map +1 -1
- package/lib/index.js +6 -3
- package/lib/index.js.map +1 -1
- package/lib/loader-gltf/gltf-json-asset.js +1 -1
- package/lib/loader-gltf/gltf-json-asset.js.map +1 -1
- package/lib/loader-gltf/gltf-multi-buffer.js +2 -10
- package/lib/loader-gltf/gltf-multi-buffer.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder-ext.js +4 -18
- package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder.js +17 -14
- package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
- package/lib/loader-gltf/gltf-sampler-desc.js +3 -16
- package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
- package/lib/material/node/blocks/ambient-occlusion-block.js +1 -4
- package/lib/material/node/blocks/ambient-occlusion-block.js.map +1 -1
- package/lib/material/node/blocks/biplanar-block.js +3 -6
- package/lib/material/node/blocks/biplanar-block.js.map +1 -1
- package/lib/material/node/blocks/image-source.js +2 -5
- package/lib/material/node/blocks/image-source.js.map +1 -1
- package/lib/material/node/blocks/input-block.js +5 -26
- package/lib/material/node/blocks/input-block.js.map +1 -1
- package/lib/material/node/blocks/pbr-mr-helper-full.js +5 -8
- package/lib/material/node/blocks/pbr-mr-helper-full.js.map +1 -1
- package/lib/material/node/blocks/reflection-texture-block.js +1 -4
- package/lib/material/node/blocks/reflection-texture-block.js.map +1 -1
- package/lib/material/node/blocks/texture-block.js +2 -5
- package/lib/material/node/blocks/texture-block.js.map +1 -1
- package/lib/material/node/blocks/triplanar-block.js +3 -6
- package/lib/material/node/blocks/triplanar-block.js.map +1 -1
- package/lib/material/node/node-emitter.js +24 -1
- package/lib/material/node/node-emitter.js.map +1 -1
- package/lib/material/node/node-geometry-renderable.js +2 -2
- package/lib/material/node/node-material.js +1 -22
- package/lib/material/node/node-material.js.map +1 -1
- package/lib/material/node/node-types.js.map +1 -1
- package/lib/material/pbr/fragments/shadow-only-fragment.js +68 -0
- package/lib/material/pbr/fragments/shadow-only-fragment.js.map +1 -0
- package/lib/material/pbr/pbr-flag-bits.js.map +1 -1
- package/lib/material/pbr/pbr-material.js.map +1 -1
- package/lib/material/pbr/pbr-primitive-resolver.js +2 -2
- package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -1
- package/lib/material/pbr/pbr-renderable.js +3 -0
- package/lib/material/pbr/pbr-renderable.js.map +1 -1
- package/lib/material/pbr/pbr-template.js +1 -0
- package/lib/material/pbr/pbr-template.js.map +1 -1
- package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js +2 -8
- package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js.map +1 -1
- package/lib/mesh/get-mesh-geometry.js +24 -0
- package/lib/mesh/get-mesh-geometry.js.map +1 -0
- package/lib/mesh/mesh-dispose.js +2 -0
- package/lib/mesh/mesh-dispose.js.map +1 -1
- package/lib/mesh/mesh.js +2 -8
- package/lib/mesh/mesh.js.map +1 -1
- package/lib/mesh/thin-instance-cull-binding.js +54 -3
- package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
- package/lib/mesh/thin-instance-gpu-culling.js +241 -24
- package/lib/mesh/thin-instance-gpu-culling.js.map +1 -1
- package/lib/mesh/thin-instance.js +112 -1
- package/lib/mesh/thin-instance.js.map +1 -1
- package/lib/picking/gpu-picker.js +4 -2
- package/lib/picking/gpu-picker.js.map +1 -1
- package/lib/picking/picking-pipeline.js +1 -1
- package/lib/picking/picking-pipeline.js.map +1 -1
- package/lib/picking/picking-shader.js +38 -16
- package/lib/picking/picking-shader.js.map +1 -1
- package/lib/scene/scene-core.js +7 -2
- package/lib/scene/scene-core.js.map +1 -1
- package/lib/scene/scene-node.js +2 -6
- package/lib/scene/scene-node.js.map +1 -1
- package/lib/scene/scene-remove.js +70 -1
- package/lib/scene/scene-remove.js.map +1 -1
- package/lib/scene/transform-node.js +3 -0
- package/lib/scene/transform-node.js.map +1 -1
- package/lib/scene/world-matrix-state.js +7 -1
- package/lib/scene/world-matrix-state.js.map +1 -1
- package/lib/shadow/csm-directional-shadow-generator.js +22 -1
- package/lib/shadow/csm-directional-shadow-generator.js.map +1 -1
- package/lib/shadow/csm-shadow-task-hooks.js +19 -11
- package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
- package/lib/shadow/esm-directional-shadow-generator.js +2 -51
- package/lib/shadow/esm-directional-shadow-generator.js.map +1 -1
- package/lib/shadow/pcf-directional-shadow-generator.js +2 -48
- package/lib/shadow/pcf-directional-shadow-generator.js.map +1 -1
- package/lib/shadow/shadow-base.js +48 -1
- package/lib/shadow/shadow-base.js.map +1 -1
- package/lib/text/text-renderable.js +2 -10
- package/lib/text/text-renderable.js.map +1 -1
- package/lib/texture/texture-array.js +96 -0
- package/lib/texture/texture-array.js.map +1 -0
- package/package.json +3 -3
|
@@ -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 and creates the\n * 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 {\n createTiCullState,\n destroyTiCullState,\n getComputeDispatchBatch,\n prepareTiCull,\n type ComputeDispatchBatch,\n type ThinInstanceGpuCullState,\n} 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 /** @internal Shared task-local compute submission batch. */\n _updateBatch: ComputeDispatchBatch;\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). Returns undefined when culling does not apply, so the caller\n * falls back to a normal instanced draw. Opaque culling\n * stays bundle-compatible because its compacted buffers and indirect args are\n * stable; cull-state transitions bump the bundle invalidation epoch.\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 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 updateBatch = getComputeDispatchBatch(signature);\n const binding: TiCullBinding = {\n cullDrawBufs: null,\n _args: null,\n _updateBatch: updateBatch,\n update(context: DrawUpdateContext): void {\n baseUpdate?.(context);\n const res = prepareTiCull(engine, state, mesh, mesh._gpu, ti, hasColor, context, updateBatch);\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 if (ti._drawArgsBuffer) {\n pass.drawIndexedIndirect(ti._drawArgsBuffer, 0);\n } else {\n pass.drawIndexed(indexCount, instanceCount);\n }\n },\n };\n return binding;\n}\n"],"names":[],"mappings":";;AAmEO,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,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,WAAA,GAAc,wBAAwB,SAAS,CAAA;AACrD,EAAA,MAAM,OAAA,GAAyB;AAAA,IAC3B,YAAA,EAAc,IAAA;AAAA,IACd,KAAA,EAAO,IAAA;AAAA,IACP,YAAA,EAAc,WAAA;AAAA,IACd,OAAO,OAAA,EAAkC;AACrC,MAAA,UAAA,GAAa,OAAO,CAAA;AACpB,MAAA,MAAM,GAAA,GAAM,aAAA,CAAc,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,KAAK,IAAA,EAAM,EAAA,EAAI,QAAA,EAAU,OAAA,EAAS,WAAW,CAAA;AAC5F,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,MAAA,IAAW,GAAG,eAAA,EAAiB;AAC3B,QAAA,IAAA,CAAK,mBAAA,CAAoB,EAAA,CAAG,eAAA,EAAiB,CAAC,CAAA;AAAA,MAClD,CAAA,MAAO;AACH,QAAA,IAAA,CAAK,WAAA,CAAY,YAAY,aAAa,CAAA;AAAA,MAC9C;AAAA,IACJ;AAAA,GACJ;AACA,EAAA,OAAO,OAAA;AACX;;;;"}
|
|
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 and creates the\n * 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 { ThinInstanceData } from \"./thin-instance.js\";\nimport type { ThinInstanceDrawBuffers } from \"./thin-instance-gpu.js\";\nimport {\n createTiCullState,\n destroyTiCullState,\n getComputeDispatchBatch,\n prepareTiCull,\n publishTiLodBucket,\n type ComputeDispatchBatch,\n type ThinInstanceGpuCullState,\n} 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 /** @internal Shared task-local compute submission batch. */\n _updateBatch: ComputeDispatchBatch;\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). Returns undefined when culling does not apply, so the caller\n * falls back to a normal instanced draw. Opaque culling\n * stays bundle-compatible because its compacted buffers and indirect args are\n * stable; cull-state transitions bump the bundle invalidation epoch.\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 (!ti) {\n return undefined;\n }\n if (ti._lodSource) {\n if (excluded) {\n throw new Error(\"Thin-instance LOD partners require an opaque, non-transmissive material\");\n }\n // The partner consumes buffers published by another renderable's update, so its vertex/indirect\n // handles must be resolved at draw time rather than captured in an opaque render bundle.\n (renderable as { _direct?: boolean })._direct = true;\n // This mesh is the LOD partner of a GPU-culled mesh: it consumes the far bucket that mesh's\n // culling compacts for this pass and never draws its own instance count (see bindLodPartner).\n return bindLodPartner(ti, signature, hasColor, baseUpdate);\n }\n if (excluded || !ti._gpuCullingEnabled) {\n return undefined;\n }\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 updateBatch = getComputeDispatchBatch(signature);\n const binding: TiCullBinding = {\n cullDrawBufs: null,\n _args: null,\n _updateBatch: updateBatch,\n update(context: DrawUpdateContext): void {\n baseUpdate?.(context);\n const partner = ti._lodPartner ?? null;\n const res = prepareTiCull(engine, state, mesh, mesh._gpu, ti, hasColor, context, updateBatch, partner);\n binding.cullDrawBufs = res?.drawBuffers ?? null;\n binding._args = res?.argsBuffer ?? null;\n if (ti._lodBuckets) {\n publishTiLodBucket(ti, signature, res);\n }\n },\n draw(pass: GPURenderPassEncoder | GPURenderBundleEncoder, indexCount: number, instanceCount: number): void {\n if (binding._args) {\n pass.drawIndexedIndirect(binding._args, 0);\n } else if (ti._drawArgsBuffer) {\n pass.drawIndexedIndirect(ti._drawArgsBuffer, 0);\n } else {\n pass.drawIndexed(indexCount, instanceCount);\n }\n },\n };\n return binding;\n}\n\n/** @internal Binding for the LOD partner of a GPU-culled mesh (`setThinInstanceLodPartner`). Its update\n * looks up the far bucket the source mesh's culling published for this pass's signature; its draw issues\n * ONLY that bucket's indirect draw — with no bucket (source not culling this pass, or culling fell back)\n * it draws nothing, so the partner can never fall back to its own instance count and double-draw. */\nfunction bindLodPartner(ti: ThinInstanceData, signature: RenderTargetSignature, hasColor: boolean, baseUpdate: ((context: DrawUpdateContext) => void) | undefined): TiCullBinding {\n const currentBucket = () => {\n const bucket = ti._lodBuckets?.get(signature);\n if (!bucket?.active) {\n return null;\n }\n if (hasColor && !bucket.colorBuffer) {\n throw new Error(\"Thin-instance LOD partner requires the source draw to provide instance colors\");\n }\n return bucket;\n };\n const binding: TiCullBinding = {\n get cullDrawBufs() {\n return currentBucket();\n },\n get _args() {\n return currentBucket()?.argsBuffer ?? null;\n },\n _updateBatch: getComputeDispatchBatch(signature),\n update(context: DrawUpdateContext): void {\n baseUpdate?.(context);\n },\n draw(pass: GPURenderPassEncoder | GPURenderBundleEncoder, indexCount: number, instanceCount: number): void {\n const bucket = currentBucket();\n if (bucket) {\n pass.drawIndexedIndirect(bucket.argsBuffer, 0);\n } else if (!ti._lodSource) {\n if (ti._drawArgsBuffer) {\n pass.drawIndexedIndirect(ti._drawArgsBuffer, 0);\n } else {\n pass.drawIndexed(indexCount, instanceCount);\n }\n }\n },\n };\n return binding;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -3,13 +3,17 @@ import { BU } from '../engine/gpu-flags.js';
|
|
|
3
3
|
import { getViewProjectionMatrix } from '../camera/camera.js';
|
|
4
4
|
import { syncThinInstanceGpuData } from './thin-instance-gpu.js';
|
|
5
5
|
import { bumpVisibilityEpoch } from '../engine/engine.js';
|
|
6
|
+
import { retireGpuResources } from '../engine/gpu-resource-retirement.js';
|
|
6
7
|
|
|
7
8
|
const WORKGROUP_SIZE = 64;
|
|
8
9
|
const PARAM_BYTES = 192;
|
|
10
|
+
const LOD_PARAM_BYTES = 224;
|
|
9
11
|
const COUNT_U32_OFFSET = 44;
|
|
10
12
|
const MESH_WORLD_FLOAT_OFFSET = 24;
|
|
11
13
|
const LOCAL_SPHERE_FLOAT_OFFSET = 40;
|
|
12
14
|
const BOUNDS_PAD_F32_OFFSET = 45;
|
|
15
|
+
const CAM_POS_DIST_F32_OFFSET = 48;
|
|
16
|
+
const LOD_BAND_F32_OFFSET = 52;
|
|
13
17
|
const INDIRECT_ARGS_BYTES = 20;
|
|
14
18
|
const CULL_WGSL_NO_COLOR = (
|
|
15
19
|
/* wgsl */
|
|
@@ -54,9 +58,76 @@ let outIndex=atomicAdd(&args[1],1u);
|
|
|
54
58
|
dstMatrices[outIndex]=srcMatrices[i];
|
|
55
59
|
dstColors[outIndex]=srcColors[i];
|
|
56
60
|
}`;
|
|
61
|
+
const CULL_WGSL_LOD_NO_COLOR = (
|
|
62
|
+
/* wgsl */
|
|
63
|
+
`
|
|
64
|
+
struct CullParams{planes:array<vec4<f32>,6>,meshWorld:mat4x4<f32>,localSphere:vec4<f32>,count:u32,boundsPad:f32,camPosDist:vec4<f32>,lodBand:f32};
|
|
65
|
+
@group(0)@binding(0)var<storage,read> srcMatrices:array<mat4x4<f32>>;
|
|
66
|
+
@group(0)@binding(1)var<storage,read_write> dstMatrices:array<mat4x4<f32>>;
|
|
67
|
+
@group(0)@binding(2)var<storage,read_write> args:array<atomic<u32>>;
|
|
68
|
+
@group(0)@binding(3)var<uniform> params:CullParams;
|
|
69
|
+
@group(0)@binding(6)var<storage,read_write> lodMatrices:array<mat4x4<f32>>;
|
|
70
|
+
@group(0)@binding(7)var<storage,read_write> lodArgs:array<atomic<u32>>;
|
|
71
|
+
fn visible(world:mat4x4<f32>)->bool{
|
|
72
|
+
let center=(world*vec4<f32>(params.localSphere.xyz,1.0)).xyz;
|
|
73
|
+
let sx=length(world[0].xyz);
|
|
74
|
+
let sy=length(world[1].xyz);
|
|
75
|
+
let sz=length(world[2].xyz);
|
|
76
|
+
let radius=params.localSphere.w*max(max(sx,sy),sz)+params.boundsPad+0.0001;
|
|
77
|
+
for(var i=0u;i<6u;i++){
|
|
78
|
+
let p=params.planes[i];
|
|
79
|
+
if(dot(p.xyz,center)+p.w < -radius){return false;}
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
fn isNear(world:mat4x4<f32>,i:u32)->bool{
|
|
84
|
+
let center=(world*vec4<f32>(params.localSphere.xyz,1.0)).xyz;
|
|
85
|
+
var h=i*747796405u+2891336453u;
|
|
86
|
+
h=((h>>((h>>28u)+4u))^h)*277803737u;
|
|
87
|
+
h=(h>>22u)^h;
|
|
88
|
+
let dither=(f32(h)*(1.0/4294967295.0)-0.5)*params.lodBand;
|
|
89
|
+
return distance(center,params.camPosDist.xyz)<params.camPosDist.w+dither;
|
|
90
|
+
}
|
|
91
|
+
@compute @workgroup_size(64)
|
|
92
|
+
fn mainLod(@builtin(global_invocation_id) gid:vec3<u32>){
|
|
93
|
+
let i=gid.x;
|
|
94
|
+
if(i>=params.count){return;}
|
|
95
|
+
let world=params.meshWorld*srcMatrices[i];
|
|
96
|
+
if(!visible(world)){return;}
|
|
97
|
+
if(isNear(world,i)){
|
|
98
|
+
let outIndex=atomicAdd(&args[1],1u);
|
|
99
|
+
dstMatrices[outIndex]=srcMatrices[i];
|
|
100
|
+
}else{
|
|
101
|
+
let outIndex=atomicAdd(&lodArgs[1],1u);
|
|
102
|
+
lodMatrices[outIndex]=srcMatrices[i];
|
|
103
|
+
}
|
|
104
|
+
}`
|
|
105
|
+
);
|
|
106
|
+
const CULL_WGSL_LOD_COLOR = `${CULL_WGSL_LOD_NO_COLOR}
|
|
107
|
+
@group(0)@binding(4)var<storage,read> srcColors:array<vec4<f32>>;
|
|
108
|
+
@group(0)@binding(5)var<storage,read_write> dstColors:array<vec4<f32>>;
|
|
109
|
+
@group(0)@binding(8)var<storage,read_write> lodColors:array<vec4<f32>>;
|
|
110
|
+
@compute @workgroup_size(64)
|
|
111
|
+
fn mainLodColor(@builtin(global_invocation_id) gid:vec3<u32>){
|
|
112
|
+
let i=gid.x;
|
|
113
|
+
if(i>=params.count){return;}
|
|
114
|
+
let world=params.meshWorld*srcMatrices[i];
|
|
115
|
+
if(!visible(world)){return;}
|
|
116
|
+
if(isNear(world,i)){
|
|
117
|
+
let outIndex=atomicAdd(&args[1],1u);
|
|
118
|
+
dstMatrices[outIndex]=srcMatrices[i];
|
|
119
|
+
dstColors[outIndex]=srcColors[i];
|
|
120
|
+
}else{
|
|
121
|
+
let outIndex=atomicAdd(&lodArgs[1],1u);
|
|
122
|
+
lodMatrices[outIndex]=srcMatrices[i];
|
|
123
|
+
lodColors[outIndex]=srcColors[i];
|
|
124
|
+
}
|
|
125
|
+
}`;
|
|
57
126
|
let _cachedDevice = null;
|
|
58
127
|
let _pipelineNoColor = null;
|
|
59
128
|
let _pipelineColor = null;
|
|
129
|
+
let _pipelineLodNoColor = null;
|
|
130
|
+
let _pipelineLodColor = null;
|
|
60
131
|
let _dispatchBatches = null;
|
|
61
132
|
function getComputeDispatchBatch(signature) {
|
|
62
133
|
_dispatchBatches ??= /* @__PURE__ */ new WeakMap();
|
|
@@ -100,7 +171,7 @@ function getComputeDispatchBatch(signature) {
|
|
|
100
171
|
return batch;
|
|
101
172
|
}
|
|
102
173
|
function createTiCullState() {
|
|
103
|
-
const paramsBytes = new ArrayBuffer(
|
|
174
|
+
const paramsBytes = new ArrayBuffer(LOD_PARAM_BYTES);
|
|
104
175
|
return {
|
|
105
176
|
_capacity: 0,
|
|
106
177
|
_visibleMatrixBuffer: null,
|
|
@@ -119,7 +190,13 @@ function createTiCullState() {
|
|
|
119
190
|
_argsData: new U32(5),
|
|
120
191
|
_drawBuffers: null,
|
|
121
192
|
_indexCount: -1,
|
|
122
|
-
_active: false
|
|
193
|
+
_active: false,
|
|
194
|
+
_lodActive: false,
|
|
195
|
+
_lodMatrixBuffer: null,
|
|
196
|
+
_lodColorBuffer: null,
|
|
197
|
+
_lodArgsBuffer: null,
|
|
198
|
+
_lodIndexCount: -1,
|
|
199
|
+
_lodArgsZeroed: false
|
|
123
200
|
};
|
|
124
201
|
}
|
|
125
202
|
function destroyTiCullState(state) {
|
|
@@ -127,31 +204,31 @@ function destroyTiCullState(state) {
|
|
|
127
204
|
state._visibleColorBuffer?.destroy();
|
|
128
205
|
state._argsBuffer?.destroy();
|
|
129
206
|
state._paramsBuffer?.destroy();
|
|
207
|
+
state._lodMatrixBuffer?.destroy();
|
|
208
|
+
state._lodColorBuffer?.destroy();
|
|
209
|
+
state._lodArgsBuffer?.destroy();
|
|
130
210
|
state._visibleMatrixBuffer = null;
|
|
131
211
|
state._visibleColorBuffer = null;
|
|
132
212
|
state._argsBuffer = null;
|
|
133
213
|
state._paramsBuffer = null;
|
|
214
|
+
state._lodMatrixBuffer = null;
|
|
215
|
+
state._lodColorBuffer = null;
|
|
216
|
+
state._lodArgsBuffer = null;
|
|
134
217
|
state._bindGroup = null;
|
|
135
218
|
state._drawBuffers = null;
|
|
136
219
|
}
|
|
137
|
-
function prepareTiCull(engine, state, mesh, gpu, ti, hasColor, context, dispatchBatch) {
|
|
220
|
+
function prepareTiCull(engine, state, mesh, gpu, ti, hasColor, context, dispatchBatch, lodMesh) {
|
|
138
221
|
const camera = context._camera;
|
|
139
222
|
if (!ti._gpuCullingEnabled || !camera || mesh.visible === false || ti.count === 0) {
|
|
140
|
-
|
|
141
|
-
state._drawBuffers = null;
|
|
142
|
-
return null;
|
|
223
|
+
return cullFallback(engine, state);
|
|
143
224
|
}
|
|
144
225
|
if (hasColor && !ti.colors) {
|
|
145
|
-
|
|
146
|
-
state._drawBuffers = null;
|
|
147
|
-
return null;
|
|
226
|
+
return cullFallback(engine, state);
|
|
148
227
|
}
|
|
149
228
|
const positions = mesh._cpuPositions;
|
|
150
229
|
if (!state._localSphereReady || state._localPositions !== positions || state._localBoundMin !== mesh.boundMin || state._localBoundMax !== mesh.boundMax) {
|
|
151
230
|
if (!computeLocalSphere(mesh, state._localSphere)) {
|
|
152
|
-
|
|
153
|
-
state._drawBuffers = null;
|
|
154
|
-
return null;
|
|
231
|
+
return cullFallback(engine, state);
|
|
155
232
|
}
|
|
156
233
|
state._localSphereReady = true;
|
|
157
234
|
state._localPositions = positions;
|
|
@@ -162,16 +239,15 @@ function prepareTiCull(engine, state, mesh, gpu, ti, hasColor, context, dispatch
|
|
|
162
239
|
const sourceMatrixBuffer = ti._gpuBuffer;
|
|
163
240
|
const sourceColorBuffer = hasColor ? ti._colorGpuBuffer : null;
|
|
164
241
|
if (!sourceMatrixBuffer || hasColor && !sourceColorBuffer) {
|
|
165
|
-
|
|
166
|
-
state._drawBuffers = null;
|
|
167
|
-
return null;
|
|
242
|
+
return cullFallback(engine, state);
|
|
168
243
|
}
|
|
169
|
-
|
|
244
|
+
const lod = lodMesh ?? null;
|
|
245
|
+
ensureCullBuffers(engine, state, ti._capacity, hasColor, lod !== null);
|
|
170
246
|
const visibleMatrixBuffer = state._visibleMatrixBuffer;
|
|
171
247
|
const visibleColorBuffer = hasColor ? state._visibleColorBuffer : null;
|
|
172
248
|
const argsBuffer = state._argsBuffer;
|
|
173
249
|
const paramsBuffer = state._paramsBuffer;
|
|
174
|
-
const pipeline = getCullPipeline(engine, hasColor);
|
|
250
|
+
const pipeline = getCullPipeline(engine, hasColor, lod !== null);
|
|
175
251
|
if (state._bindGroup === null || state._srcMatrixBuffer !== sourceMatrixBuffer || state._srcColorBuffer !== sourceColorBuffer || state._hasColor !== hasColor) {
|
|
176
252
|
const entries = [
|
|
177
253
|
{ binding: 0, resource: { buffer: sourceMatrixBuffer } },
|
|
@@ -182,6 +258,12 @@ function prepareTiCull(engine, state, mesh, gpu, ti, hasColor, context, dispatch
|
|
|
182
258
|
if (hasColor) {
|
|
183
259
|
entries.push({ binding: 4, resource: { buffer: sourceColorBuffer } }, { binding: 5, resource: { buffer: visibleColorBuffer } });
|
|
184
260
|
}
|
|
261
|
+
if (lod) {
|
|
262
|
+
entries.push({ binding: 6, resource: { buffer: state._lodMatrixBuffer } }, { binding: 7, resource: { buffer: state._lodArgsBuffer } });
|
|
263
|
+
if (hasColor) {
|
|
264
|
+
entries.push({ binding: 8, resource: { buffer: state._lodColorBuffer } });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
185
267
|
state._bindGroup = engine._device.createBindGroup({ layout: pipeline.getBindGroupLayout(0), entries });
|
|
186
268
|
state._srcMatrixBuffer = sourceMatrixBuffer;
|
|
187
269
|
state._srcColorBuffer = sourceColorBuffer;
|
|
@@ -189,7 +271,7 @@ function prepareTiCull(engine, state, mesh, gpu, ti, hasColor, context, dispatch
|
|
|
189
271
|
}
|
|
190
272
|
const v = camera.viewport;
|
|
191
273
|
const aspect = context.targetWidth / context.targetHeight * (v ? v.width / v.height : 1);
|
|
192
|
-
writeCullParams(engine, state, mesh, gpu.indexCount, ti.count, camera, aspect);
|
|
274
|
+
writeCullParams(engine, state, mesh, gpu.indexCount, ti.count, camera, aspect, lod);
|
|
193
275
|
const dispatch = {
|
|
194
276
|
pipeline,
|
|
195
277
|
bindGroup: state._bindGroup,
|
|
@@ -206,10 +288,76 @@ function prepareTiCull(engine, state, mesh, gpu, ti, hasColor, context, dispatch
|
|
|
206
288
|
}
|
|
207
289
|
state._drawBuffers = { matrixBuffer: visibleMatrixBuffer, colorBuffer: visibleColorBuffer };
|
|
208
290
|
setCullActive(state, true);
|
|
291
|
+
if (lod) {
|
|
292
|
+
return {
|
|
293
|
+
drawBuffers: state._drawBuffers,
|
|
294
|
+
argsBuffer,
|
|
295
|
+
lodDrawBuffers: { matrixBuffer: state._lodMatrixBuffer, colorBuffer: hasColor ? state._lodColorBuffer : null },
|
|
296
|
+
lodArgsBuffer: state._lodArgsBuffer
|
|
297
|
+
};
|
|
298
|
+
}
|
|
209
299
|
return { drawBuffers: state._drawBuffers, argsBuffer };
|
|
210
300
|
}
|
|
211
|
-
function
|
|
301
|
+
function cullFallback(engine, state) {
|
|
302
|
+
if (state._lodArgsBuffer && !state._lodArgsZeroed) {
|
|
303
|
+
engine._currentEncoder.clearBuffer(state._lodArgsBuffer, 4, 4);
|
|
304
|
+
state._lodArgsZeroed = true;
|
|
305
|
+
}
|
|
306
|
+
setCullActive(state, false);
|
|
307
|
+
state._drawBuffers = null;
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
function publishTiLodBucket(ti, signature, result) {
|
|
311
|
+
const lodDrawBuffers = result?.lodDrawBuffers;
|
|
312
|
+
const lodArgsBuffer = result?.lodArgsBuffer;
|
|
313
|
+
const buckets = ti._lodBuckets;
|
|
314
|
+
if (lodDrawBuffers && lodArgsBuffer && buckets) {
|
|
315
|
+
let bucket2 = buckets.get(signature);
|
|
316
|
+
if (!bucket2) {
|
|
317
|
+
bucket2 = { matrixBuffer: lodDrawBuffers.matrixBuffer, colorBuffer: lodDrawBuffers.colorBuffer, argsBuffer: lodArgsBuffer, active: true };
|
|
318
|
+
buckets.set(signature, bucket2);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
bucket2.matrixBuffer = lodDrawBuffers.matrixBuffer;
|
|
322
|
+
bucket2.colorBuffer = lodDrawBuffers.colorBuffer;
|
|
323
|
+
bucket2.argsBuffer = lodArgsBuffer;
|
|
324
|
+
bucket2.active = true;
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const bucket = ti._lodBuckets?.get(signature);
|
|
328
|
+
if (bucket) {
|
|
329
|
+
bucket.active = false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function ensureCullBuffers(engine, state, capacity, hasColor, lod) {
|
|
212
333
|
const device = engine._device;
|
|
334
|
+
if (state._lodActive !== lod) {
|
|
335
|
+
state._paramsBuffer?.destroy();
|
|
336
|
+
state._paramsBuffer = null;
|
|
337
|
+
state._bindGroup = null;
|
|
338
|
+
if (!lod) {
|
|
339
|
+
const lodMat = state._lodMatrixBuffer;
|
|
340
|
+
const lodCol = state._lodColorBuffer;
|
|
341
|
+
const lodArgs = state._lodArgsBuffer;
|
|
342
|
+
if (lodArgs && !state._lodArgsZeroed) {
|
|
343
|
+
engine._currentEncoder.clearBuffer(lodArgs, 4, 4);
|
|
344
|
+
}
|
|
345
|
+
if (lodMat || lodArgs) {
|
|
346
|
+
retireGpuResources(engine, () => {
|
|
347
|
+
lodMat?.destroy();
|
|
348
|
+
lodCol?.destroy();
|
|
349
|
+
lodArgs?.destroy();
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
state._lodMatrixBuffer = null;
|
|
353
|
+
state._lodColorBuffer = null;
|
|
354
|
+
state._lodArgsBuffer = null;
|
|
355
|
+
state._lodIndexCount = -1;
|
|
356
|
+
state._lodArgsZeroed = false;
|
|
357
|
+
}
|
|
358
|
+
state._lodActive = lod;
|
|
359
|
+
bumpVisibilityEpoch();
|
|
360
|
+
}
|
|
213
361
|
if (state._capacity < capacity) {
|
|
214
362
|
state._visibleMatrixBuffer?.destroy();
|
|
215
363
|
state._visibleColorBuffer?.destroy();
|
|
@@ -234,6 +382,34 @@ function ensureCullBuffers(engine, state, capacity, hasColor) {
|
|
|
234
382
|
state._drawBuffers = null;
|
|
235
383
|
bumpVisibilityEpoch();
|
|
236
384
|
}
|
|
385
|
+
if (lod && (!state._lodMatrixBuffer || state._lodMatrixBuffer.size < state._capacity * 64 || hasColor && !state._lodColorBuffer)) {
|
|
386
|
+
const oldMat = state._lodMatrixBuffer;
|
|
387
|
+
const oldCol = state._lodColorBuffer;
|
|
388
|
+
if (oldMat) {
|
|
389
|
+
retireGpuResources(engine, () => {
|
|
390
|
+
oldMat.destroy();
|
|
391
|
+
oldCol?.destroy();
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
state._lodMatrixBuffer = device.createBuffer({
|
|
395
|
+
size: Math.max(state._capacity * 64, 4),
|
|
396
|
+
usage: BU.VERTEX | BU.STORAGE
|
|
397
|
+
});
|
|
398
|
+
state._lodColorBuffer = hasColor ? device.createBuffer({
|
|
399
|
+
size: Math.max(state._capacity * 16, 4),
|
|
400
|
+
usage: BU.VERTEX | BU.STORAGE
|
|
401
|
+
}) : null;
|
|
402
|
+
state._bindGroup = null;
|
|
403
|
+
bumpVisibilityEpoch();
|
|
404
|
+
}
|
|
405
|
+
if (lod && !state._lodArgsBuffer) {
|
|
406
|
+
state._lodArgsBuffer = device.createBuffer({
|
|
407
|
+
size: INDIRECT_ARGS_BYTES,
|
|
408
|
+
usage: BU.INDIRECT | BU.STORAGE | BU.COPY_DST
|
|
409
|
+
});
|
|
410
|
+
state._lodIndexCount = -1;
|
|
411
|
+
state._lodArgsZeroed = false;
|
|
412
|
+
}
|
|
237
413
|
if (!state._argsBuffer) {
|
|
238
414
|
state._argsBuffer = device.createBuffer({
|
|
239
415
|
size: INDIRECT_ARGS_BYTES,
|
|
@@ -242,17 +418,33 @@ function ensureCullBuffers(engine, state, capacity, hasColor) {
|
|
|
242
418
|
}
|
|
243
419
|
if (!state._paramsBuffer) {
|
|
244
420
|
state._paramsBuffer = device.createBuffer({
|
|
245
|
-
size: PARAM_BYTES,
|
|
421
|
+
size: lod ? LOD_PARAM_BYTES : PARAM_BYTES,
|
|
246
422
|
usage: BU.UNIFORM | BU.COPY_DST
|
|
247
423
|
});
|
|
248
424
|
}
|
|
249
425
|
}
|
|
250
|
-
function getCullPipeline(engine, hasColor) {
|
|
426
|
+
function getCullPipeline(engine, hasColor, lod) {
|
|
251
427
|
const device = engine._device;
|
|
252
428
|
if (_cachedDevice !== device) {
|
|
253
429
|
_cachedDevice = device;
|
|
254
430
|
_pipelineNoColor = null;
|
|
255
431
|
_pipelineColor = null;
|
|
432
|
+
_pipelineLodNoColor = null;
|
|
433
|
+
_pipelineLodColor = null;
|
|
434
|
+
}
|
|
435
|
+
if (lod) {
|
|
436
|
+
if (hasColor) {
|
|
437
|
+
_pipelineLodColor ??= device.createComputePipeline({
|
|
438
|
+
layout: "auto",
|
|
439
|
+
compute: { module: device.createShaderModule({ code: CULL_WGSL_LOD_COLOR }), entryPoint: "mainLodColor" }
|
|
440
|
+
});
|
|
441
|
+
return _pipelineLodColor;
|
|
442
|
+
}
|
|
443
|
+
_pipelineLodNoColor ??= device.createComputePipeline({
|
|
444
|
+
layout: "auto",
|
|
445
|
+
compute: { module: device.createShaderModule({ code: CULL_WGSL_LOD_NO_COLOR }), entryPoint: "mainLod" }
|
|
446
|
+
});
|
|
447
|
+
return _pipelineLodNoColor;
|
|
256
448
|
}
|
|
257
449
|
if (hasColor) {
|
|
258
450
|
_pipelineColor ??= device.createComputePipeline({
|
|
@@ -267,7 +459,7 @@ function getCullPipeline(engine, hasColor) {
|
|
|
267
459
|
});
|
|
268
460
|
return _pipelineNoColor;
|
|
269
461
|
}
|
|
270
|
-
function writeCullParams(engine, state, mesh, indexCount, instanceCount, camera, aspect) {
|
|
462
|
+
function writeCullParams(engine, state, mesh, indexCount, instanceCount, camera, aspect, lodMesh) {
|
|
271
463
|
const params = state._paramsF32;
|
|
272
464
|
const viewProjection = getViewProjectionMatrix(camera, aspect);
|
|
273
465
|
writeFrustumPlanes(params, viewProjection);
|
|
@@ -275,6 +467,14 @@ function writeCullParams(engine, state, mesh, indexCount, instanceCount, camera,
|
|
|
275
467
|
params.set(state._localSphere, LOCAL_SPHERE_FLOAT_OFFSET);
|
|
276
468
|
state._paramsU32[COUNT_U32_OFFSET] = instanceCount;
|
|
277
469
|
params[BOUNDS_PAD_F32_OFFSET] = mesh.thinInstances?._cullBoundsPad ?? 0;
|
|
470
|
+
if (lodMesh) {
|
|
471
|
+
const cw = camera.worldMatrix;
|
|
472
|
+
params[CAM_POS_DIST_F32_OFFSET] = cw[12];
|
|
473
|
+
params[CAM_POS_DIST_F32_OFFSET + 1] = cw[13];
|
|
474
|
+
params[CAM_POS_DIST_F32_OFFSET + 2] = cw[14];
|
|
475
|
+
params[CAM_POS_DIST_F32_OFFSET + 3] = mesh.thinInstances?._lodDistance ?? 0;
|
|
476
|
+
params[LOD_BAND_F32_OFFSET] = mesh.thinInstances?._lodBand ?? 0;
|
|
477
|
+
}
|
|
278
478
|
if (state._indexCount !== indexCount) {
|
|
279
479
|
const args = state._argsData;
|
|
280
480
|
args[0] = indexCount;
|
|
@@ -287,7 +487,24 @@ function writeCullParams(engine, state, mesh, indexCount, instanceCount, camera,
|
|
|
287
487
|
} else {
|
|
288
488
|
engine._currentEncoder.clearBuffer(state._argsBuffer, 4, 4);
|
|
289
489
|
}
|
|
290
|
-
|
|
490
|
+
if (lodMesh) {
|
|
491
|
+
const lodGpu = lodMesh._gpu;
|
|
492
|
+
const lodIndexCount = lodGpu ? lodGpu.indexCount : 0;
|
|
493
|
+
if (state._lodIndexCount !== lodIndexCount) {
|
|
494
|
+
const args = state._argsData;
|
|
495
|
+
args[0] = lodIndexCount;
|
|
496
|
+
args[1] = 0;
|
|
497
|
+
args[2] = 0;
|
|
498
|
+
args[3] = 0;
|
|
499
|
+
args[4] = 0;
|
|
500
|
+
engine._device.queue.writeBuffer(state._lodArgsBuffer, 0, args.buffer, args.byteOffset, args.byteLength);
|
|
501
|
+
state._lodIndexCount = lodIndexCount;
|
|
502
|
+
} else {
|
|
503
|
+
engine._currentEncoder.clearBuffer(state._lodArgsBuffer, 4, 4);
|
|
504
|
+
}
|
|
505
|
+
state._lodArgsZeroed = false;
|
|
506
|
+
}
|
|
507
|
+
engine._device.queue.writeBuffer(state._paramsBuffer, 0, state._paramsBytes, 0, lodMesh ? LOD_PARAM_BYTES : PARAM_BYTES);
|
|
291
508
|
}
|
|
292
509
|
function setCullActive(state, active) {
|
|
293
510
|
if (state._active !== active) {
|
|
@@ -356,5 +573,5 @@ function computeLocalSphere(mesh, out) {
|
|
|
356
573
|
return true;
|
|
357
574
|
}
|
|
358
575
|
|
|
359
|
-
export { createTiCullState, destroyTiCullState, getComputeDispatchBatch, prepareTiCull };
|
|
576
|
+
export { createTiCullState, destroyTiCullState, getComputeDispatchBatch, prepareTiCull, publishTiLodBucket };
|
|
360
577
|
//# sourceMappingURL=thin-instance-gpu-culling.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thin-instance-gpu-culling.js","sources":["../../../src/mesh/thin-instance-gpu-culling.ts"],"sourcesContent":["/** GPU frustum culling for opt-in thin instances.\n *\n * Dynamically imported only when a scene enables thin-instance GPU culling.\n * Each render binding owns its own state so render tasks with different cameras\n * never clobber one another's compacted instance buffers or indirect args.\n */\n\nimport { F32, U32 } from \"../engine/typed-arrays.js\";\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { Camera } from \"../camera/camera.js\";\nimport { getViewProjectionMatrix } from \"../camera/camera.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { DrawUpdateBatch, DrawUpdateContext } from \"../render/renderable.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport type { Mesh, MeshGPU } from \"./mesh.js\";\nimport type { ThinInstanceData } from \"./thin-instance.js\";\nimport { syncThinInstanceGpuData } from \"./thin-instance-gpu.js\";\nimport type { ThinInstanceDrawBuffers } from \"./thin-instance-gpu.js\";\nimport { bumpVisibilityEpoch } from \"../engine/engine.js\";\n\nconst WORKGROUP_SIZE = 64;\nconst PARAM_BYTES = 192;\nconst COUNT_U32_OFFSET = 44;\nconst MESH_WORLD_FLOAT_OFFSET = 24;\nconst LOCAL_SPHERE_FLOAT_OFFSET = 40;\nconst BOUNDS_PAD_F32_OFFSET = 45;\nconst INDIRECT_ARGS_BYTES = 20;\n\nconst CULL_WGSL_NO_COLOR = /* wgsl */ `\nstruct CullParams{planes:array<vec4<f32>,6>,meshWorld:mat4x4<f32>,localSphere:vec4<f32>,count:u32,boundsPad:f32};\n@group(0)@binding(0)var<storage,read> srcMatrices:array<mat4x4<f32>>;\n@group(0)@binding(1)var<storage,read_write> dstMatrices:array<mat4x4<f32>>;\n@group(0)@binding(2)var<storage,read_write> args:array<atomic<u32>>;\n@group(0)@binding(3)var<uniform> params:CullParams;\nfn visible(world:mat4x4<f32>)->bool{\nlet center=(world*vec4<f32>(params.localSphere.xyz,1.0)).xyz;\nlet sx=length(world[0].xyz);\nlet sy=length(world[1].xyz);\nlet sz=length(world[2].xyz);\nlet radius=params.localSphere.w*max(max(sx,sy),sz)+params.boundsPad+0.0001;\nfor(var i=0u;i<6u;i++){\nlet p=params.planes[i];\nif(dot(p.xyz,center)+p.w < -radius){return false;}\n}\nreturn true;\n}\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) gid:vec3<u32>){\nlet i=gid.x;\nif(i>=params.count){return;}\nlet world=params.meshWorld*srcMatrices[i];\nif(!visible(world)){return;}\nlet outIndex=atomicAdd(&args[1],1u);\ndstMatrices[outIndex]=srcMatrices[i];\n}`;\n\nconst CULL_WGSL_COLOR = `${CULL_WGSL_NO_COLOR}\n@group(0)@binding(4)var<storage,read> srcColors:array<vec4<f32>>;\n@group(0)@binding(5)var<storage,read_write> dstColors:array<vec4<f32>>;\n@compute @workgroup_size(64)\nfn mainColor(@builtin(global_invocation_id) gid:vec3<u32>){\nlet i=gid.x;\nif(i>=params.count){return;}\nlet world=params.meshWorld*srcMatrices[i];\nif(!visible(world)){return;}\nlet outIndex=atomicAdd(&args[1],1u);\ndstMatrices[outIndex]=srcMatrices[i];\ndstColors[outIndex]=srcColors[i];\n}`;\n\n/** Per-render-binding GPU culling state. */\nexport interface ThinInstanceGpuCullState {\n /** @internal */\n _capacity: number;\n /** @internal */\n _visibleMatrixBuffer: GPUBuffer | null;\n /** @internal */\n _visibleColorBuffer: GPUBuffer | null;\n /** @internal */\n _argsBuffer: GPUBuffer | null;\n /** @internal */\n _paramsBuffer: GPUBuffer | null;\n /** @internal */\n _bindGroup: GPUBindGroup | null;\n /** @internal */\n _srcMatrixBuffer: GPUBuffer | null;\n /** @internal */\n _srcColorBuffer: GPUBuffer | null;\n /** @internal */\n _hasColor: boolean;\n /** @internal */\n _localSphereReady: boolean;\n /** @internal CPU geometry reference used to build `_localSphere`. */\n _localPositions?: Float32Array;\n /** @internal Bounds references used to detect same-buffer geometry updates. */\n _localBoundMin?: Mesh[\"boundMin\"];\n /** @internal Bounds references used to detect same-buffer geometry updates. */\n _localBoundMax?: Mesh[\"boundMax\"];\n /** @internal */\n _localSphere: Float32Array;\n /** @internal */\n _paramsBytes: ArrayBuffer;\n /** @internal */\n _paramsF32: Float32Array;\n /** @internal */\n _paramsU32: Uint32Array;\n /** @internal */\n _argsData: Uint32Array;\n /** @internal */\n _drawBuffers: ThinInstanceDrawBuffers | null;\n /** @internal */\n _indexCount: number;\n /** @internal */\n _active: boolean;\n}\n\n/** Result consumed by a material draw closure after culling has run for the active pass. */\nexport interface ThinInstanceGpuCullResult {\n readonly drawBuffers: ThinInstanceDrawBuffers;\n readonly argsBuffer: GPUBuffer;\n}\n\ninterface ComputeDispatch {\n readonly pipeline: GPUComputePipeline;\n readonly bindGroup: GPUBindGroup;\n readonly workgroupsX: number;\n}\n\n/** @internal Task-local batch that submits all culling work through one compute pass. */\nexport interface ComputeDispatchBatch extends DrawUpdateBatch {\n queue(dispatch: ComputeDispatch): void;\n}\n\nlet _cachedDevice: GPUDevice | null = null;\nlet _pipelineNoColor: GPUComputePipeline | null = null;\nlet _pipelineColor: GPUComputePipeline | null = null;\nlet _dispatchBatches: WeakMap<RenderTargetSignature, ComputeDispatchBatch> | null = null;\n\n/** @internal Return the compute batch associated with one render task. */\nexport function getComputeDispatchBatch(signature: RenderTargetSignature): ComputeDispatchBatch {\n _dispatchBatches ??= new WeakMap();\n let batch = _dispatchBatches.get(signature);\n if (batch) {\n return batch;\n }\n const dispatches: ComputeDispatch[] = [];\n let count = 0;\n batch = {\n reset(): void {\n count = 0;\n },\n flush(engine): void {\n if (count === 0) {\n return;\n }\n const pass = engine._currentEncoder.beginComputePass();\n let lastPipeline: GPUComputePipeline | null = null;\n for (let i = 0; i < count; i++) {\n const dispatch = dispatches[i]!;\n if (dispatch.pipeline !== lastPipeline) {\n pass.setPipeline(dispatch.pipeline);\n lastPipeline = dispatch.pipeline;\n }\n pass.setBindGroup(0, dispatch.bindGroup);\n pass.dispatchWorkgroups(dispatch.workgroupsX);\n }\n pass.end();\n },\n destroy(): void {\n dispatches.length = 0;\n count = 0;\n _dispatchBatches?.delete(signature);\n },\n queue(dispatch): void {\n dispatches[count++] = dispatch;\n },\n };\n _dispatchBatches.set(signature, batch);\n return batch;\n}\n\n/** Create per-binding culling state. */\nexport function createTiCullState(): ThinInstanceGpuCullState {\n const paramsBytes = new ArrayBuffer(PARAM_BYTES);\n return {\n _capacity: 0,\n _visibleMatrixBuffer: null,\n _visibleColorBuffer: null,\n _argsBuffer: null,\n _paramsBuffer: null,\n _bindGroup: null,\n _srcMatrixBuffer: null,\n _srcColorBuffer: null,\n _hasColor: false,\n _localSphereReady: false,\n _localSphere: new F32(4),\n _paramsBytes: paramsBytes,\n _paramsF32: new F32(paramsBytes),\n _paramsU32: new U32(paramsBytes),\n _argsData: new U32(5),\n _drawBuffers: null,\n _indexCount: -1,\n _active: false,\n };\n}\n\n/** Destroy GPU resources owned by a per-binding cull state. */\nexport function destroyTiCullState(state: ThinInstanceGpuCullState): void {\n state._visibleMatrixBuffer?.destroy();\n state._visibleColorBuffer?.destroy();\n state._argsBuffer?.destroy();\n state._paramsBuffer?.destroy();\n state._visibleMatrixBuffer = null;\n state._visibleColorBuffer = null;\n state._argsBuffer = null;\n state._paramsBuffer = null;\n state._bindGroup = null;\n state._drawBuffers = null;\n}\n\n/** Run culling for one render binding and return buffers for the subsequent indirect draw. */\nexport function prepareTiCull(\n engine: EngineContext,\n state: ThinInstanceGpuCullState,\n mesh: Mesh,\n gpu: MeshGPU,\n ti: ThinInstanceData,\n hasColor: boolean,\n context: DrawUpdateContext,\n dispatchBatch?: ComputeDispatchBatch\n): ThinInstanceGpuCullResult | null {\n const camera = context._camera;\n if (!ti._gpuCullingEnabled || !camera || mesh.visible === false || ti.count === 0) {\n setCullActive(state, false);\n state._drawBuffers = null;\n return null;\n }\n if (hasColor && !ti.colors) {\n setCullActive(state, false);\n state._drawBuffers = null;\n return null;\n }\n const positions = mesh._cpuPositions;\n if (!state._localSphereReady || state._localPositions !== positions || state._localBoundMin !== mesh.boundMin || state._localBoundMax !== mesh.boundMax) {\n if (!computeLocalSphere(mesh as Mesh, state._localSphere)) {\n setCullActive(state, false);\n state._drawBuffers = null;\n return null;\n }\n state._localSphereReady = true;\n state._localPositions = positions;\n state._localBoundMin = mesh.boundMin;\n state._localBoundMax = mesh.boundMax;\n }\n\n syncThinInstanceGpuData(engine, ti, hasColor);\n const sourceMatrixBuffer = ti._gpuBuffer;\n const sourceColorBuffer = hasColor ? ti._colorGpuBuffer : null;\n if (!sourceMatrixBuffer || (hasColor && !sourceColorBuffer)) {\n setCullActive(state, false);\n state._drawBuffers = null;\n return null;\n }\n\n ensureCullBuffers(engine, state, ti._capacity, hasColor);\n const visibleMatrixBuffer = state._visibleMatrixBuffer!;\n const visibleColorBuffer = hasColor ? state._visibleColorBuffer! : null;\n const argsBuffer = state._argsBuffer!;\n const paramsBuffer = state._paramsBuffer!;\n const pipeline = getCullPipeline(engine, hasColor);\n\n if (state._bindGroup === null || state._srcMatrixBuffer !== sourceMatrixBuffer || state._srcColorBuffer !== sourceColorBuffer || state._hasColor !== hasColor) {\n const entries: GPUBindGroupEntry[] = [\n { binding: 0, resource: { buffer: sourceMatrixBuffer } },\n { binding: 1, resource: { buffer: visibleMatrixBuffer } },\n { binding: 2, resource: { buffer: argsBuffer } },\n { binding: 3, resource: { buffer: paramsBuffer } },\n ];\n if (hasColor) {\n entries.push({ binding: 4, resource: { buffer: sourceColorBuffer! } }, { binding: 5, resource: { buffer: visibleColorBuffer! } });\n }\n state._bindGroup = engine._device.createBindGroup({ layout: pipeline.getBindGroupLayout(0), entries });\n state._srcMatrixBuffer = sourceMatrixBuffer;\n state._srcColorBuffer = sourceColorBuffer;\n state._hasColor = hasColor;\n }\n\n const v = camera.viewport;\n const aspect = (context.targetWidth / context.targetHeight) * (v ? v.width / v.height : 1);\n writeCullParams(engine, state, mesh, gpu.indexCount, ti.count, camera, aspect);\n\n const dispatch = {\n pipeline,\n bindGroup: state._bindGroup,\n workgroupsX: Math.ceil(ti.count / WORKGROUP_SIZE),\n };\n if (dispatchBatch) {\n dispatchBatch.queue(dispatch);\n } else {\n const pass = engine._currentEncoder.beginComputePass();\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, state._bindGroup);\n pass.dispatchWorkgroups(dispatch.workgroupsX);\n pass.end();\n }\n\n state._drawBuffers = { matrixBuffer: visibleMatrixBuffer, colorBuffer: visibleColorBuffer };\n setCullActive(state, true);\n return { drawBuffers: state._drawBuffers, argsBuffer };\n}\n\nfunction ensureCullBuffers(engine: EngineContext, state: ThinInstanceGpuCullState, capacity: number, hasColor: boolean): void {\n const device = engine._device;\n if (state._capacity < capacity) {\n state._visibleMatrixBuffer?.destroy();\n state._visibleColorBuffer?.destroy();\n state._visibleMatrixBuffer = device.createBuffer({\n size: Math.max(capacity * 64, 4),\n usage: BU.VERTEX | BU.STORAGE,\n });\n state._visibleColorBuffer = hasColor\n ? device.createBuffer({\n size: Math.max(capacity * 16, 4),\n usage: BU.VERTEX | BU.STORAGE,\n })\n : null;\n state._capacity = capacity;\n state._bindGroup = null;\n state._drawBuffers = null;\n bumpVisibilityEpoch();\n } else if (hasColor && !state._visibleColorBuffer) {\n state._visibleColorBuffer = device.createBuffer({\n size: Math.max(state._capacity * 16, 4),\n usage: BU.VERTEX | BU.STORAGE,\n });\n state._bindGroup = null;\n state._drawBuffers = null;\n bumpVisibilityEpoch();\n }\n if (!state._argsBuffer) {\n state._argsBuffer = device.createBuffer({\n size: INDIRECT_ARGS_BYTES,\n usage: BU.INDIRECT | BU.STORAGE | BU.COPY_DST,\n });\n }\n if (!state._paramsBuffer) {\n state._paramsBuffer = device.createBuffer({\n size: PARAM_BYTES,\n usage: BU.UNIFORM | BU.COPY_DST,\n });\n }\n}\n\nfunction getCullPipeline(engine: EngineContext, hasColor: boolean): GPUComputePipeline {\n const device = engine._device;\n if (_cachedDevice !== device) {\n _cachedDevice = device;\n _pipelineNoColor = null;\n _pipelineColor = null;\n }\n if (hasColor) {\n _pipelineColor ??= device.createComputePipeline({\n layout: \"auto\",\n compute: { module: device.createShaderModule({ code: CULL_WGSL_COLOR }), entryPoint: \"mainColor\" },\n });\n return _pipelineColor;\n }\n _pipelineNoColor ??= device.createComputePipeline({\n layout: \"auto\",\n compute: { module: device.createShaderModule({ code: CULL_WGSL_NO_COLOR }), entryPoint: \"main\" },\n });\n return _pipelineNoColor;\n}\n\nfunction writeCullParams(engine: EngineContext, state: ThinInstanceGpuCullState, mesh: Mesh, indexCount: number, instanceCount: number, camera: Camera, aspect: number): void {\n const params = state._paramsF32;\n const viewProjection = getViewProjectionMatrix(camera, aspect);\n writeFrustumPlanes(params, viewProjection);\n params.set(mesh.worldMatrix, MESH_WORLD_FLOAT_OFFSET);\n params.set(state._localSphere, LOCAL_SPHERE_FLOAT_OFFSET);\n state._paramsU32[COUNT_U32_OFFSET] = instanceCount;\n params[BOUNDS_PAD_F32_OFFSET] = mesh.thinInstances?._cullBoundsPad ?? 0;\n\n if (state._indexCount !== indexCount) {\n const args = state._argsData;\n args[0] = indexCount;\n args[1] = 0;\n args[2] = 0;\n args[3] = 0;\n args[4] = 0;\n engine._device.queue.writeBuffer(state._argsBuffer!, 0, args.buffer, args.byteOffset, args.byteLength);\n state._indexCount = indexCount;\n } else {\n engine._currentEncoder.clearBuffer(state._argsBuffer!, 4, 4);\n }\n engine._device.queue.writeBuffer(state._paramsBuffer!, 0, state._paramsBytes);\n}\n\nfunction setCullActive(state: ThinInstanceGpuCullState, active: boolean): void {\n if (state._active !== active) {\n state._active = active;\n bumpVisibilityEpoch();\n }\n}\n\nfunction writeFrustumPlanes(out: Float32Array, m: Mat4): void {\n writePlane(out, 0, m[3]! + m[0]!, m[7]! + m[4]!, m[11]! + m[8]!, m[15]! + m[12]!);\n writePlane(out, 4, m[3]! - m[0]!, m[7]! - m[4]!, m[11]! - m[8]!, m[15]! - m[12]!);\n writePlane(out, 8, m[3]! + m[1]!, m[7]! + m[5]!, m[11]! + m[9]!, m[15]! + m[13]!);\n writePlane(out, 12, m[3]! - m[1]!, m[7]! - m[5]!, m[11]! - m[9]!, m[15]! - m[13]!);\n writePlane(out, 16, m[2]!, m[6]!, m[10]!, m[14]!);\n writePlane(out, 20, m[3]! - m[2]!, m[7]! - m[6]!, m[11]! - m[10]!, m[15]! - m[14]!);\n}\n\nfunction writePlane(out: Float32Array, offset: number, x: number, y: number, z: number, w: number): void {\n const invLen = 1 / Math.hypot(x, y, z);\n out[offset] = x * invLen;\n out[offset + 1] = y * invLen;\n out[offset + 2] = z * invLen;\n out[offset + 3] = w * invLen;\n}\n\nfunction computeLocalSphere(mesh: Mesh, out: Float32Array): boolean {\n const positions = mesh._cpuPositions;\n if (!positions || positions.length < 3) {\n return false;\n }\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (let i = 0; i < positions.length; i += 3) {\n const x = positions[i]!;\n const y = positions[i + 1]!;\n const z = positions[i + 2]!;\n if (x < minX) {\n minX = x;\n }\n if (x > maxX) {\n maxX = x;\n }\n if (y < minY) {\n minY = y;\n }\n if (y > maxY) {\n maxY = y;\n }\n if (z < minZ) {\n minZ = z;\n }\n if (z > maxZ) {\n maxZ = z;\n }\n }\n if (!isFinite(minX)) {\n return false;\n }\n const cx = (minX + maxX) * 0.5;\n const cy = (minY + maxY) * 0.5;\n const cz = (minZ + maxZ) * 0.5;\n const dx = maxX - cx;\n const dy = maxY - cy;\n const dz = maxZ - cz;\n out[0] = cx;\n out[1] = cy;\n out[2] = cz;\n out[3] = Math.hypot(dx, dy, dz);\n return true;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"thin-instance-gpu-culling.js","sources":["../../../src/mesh/thin-instance-gpu-culling.ts"],"sourcesContent":["/** GPU frustum culling for opt-in thin instances.\n *\n * Dynamically imported only when a scene enables thin-instance GPU culling.\n * Each render binding owns its own state so render tasks with different cameras\n * never clobber one another's compacted instance buffers or indirect args.\n */\n\nimport { F32, U32 } from \"../engine/typed-arrays.js\";\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { Camera } from \"../camera/camera.js\";\nimport { getViewProjectionMatrix } from \"../camera/camera.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { DrawUpdateBatch, DrawUpdateContext } from \"../render/renderable.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport type { Mesh, MeshGPU } from \"./mesh.js\";\nimport type { ThinInstanceData } from \"./thin-instance.js\";\nimport { syncThinInstanceGpuData } from \"./thin-instance-gpu.js\";\nimport type { ThinInstanceDrawBuffers } from \"./thin-instance-gpu.js\";\nimport { bumpVisibilityEpoch } from \"../engine/engine.js\";\nimport { retireGpuResources } from \"../engine/gpu-resource-retirement.js\";\n\nconst WORKGROUP_SIZE = 64;\nconst PARAM_BYTES = 192;\n// Two-bucket (LOD partner) params append camPosDist (vec4: camera xyz + threshold distance)\n// and lodBand after the base struct's implicit 16-byte tail padding.\nconst LOD_PARAM_BYTES = 224;\nconst COUNT_U32_OFFSET = 44;\nconst MESH_WORLD_FLOAT_OFFSET = 24;\nconst LOCAL_SPHERE_FLOAT_OFFSET = 40;\nconst BOUNDS_PAD_F32_OFFSET = 45;\nconst CAM_POS_DIST_F32_OFFSET = 48;\nconst LOD_BAND_F32_OFFSET = 52;\nconst INDIRECT_ARGS_BYTES = 20;\n\nconst CULL_WGSL_NO_COLOR = /* wgsl */ `\nstruct CullParams{planes:array<vec4<f32>,6>,meshWorld:mat4x4<f32>,localSphere:vec4<f32>,count:u32,boundsPad:f32};\n@group(0)@binding(0)var<storage,read> srcMatrices:array<mat4x4<f32>>;\n@group(0)@binding(1)var<storage,read_write> dstMatrices:array<mat4x4<f32>>;\n@group(0)@binding(2)var<storage,read_write> args:array<atomic<u32>>;\n@group(0)@binding(3)var<uniform> params:CullParams;\nfn visible(world:mat4x4<f32>)->bool{\nlet center=(world*vec4<f32>(params.localSphere.xyz,1.0)).xyz;\nlet sx=length(world[0].xyz);\nlet sy=length(world[1].xyz);\nlet sz=length(world[2].xyz);\nlet radius=params.localSphere.w*max(max(sx,sy),sz)+params.boundsPad+0.0001;\nfor(var i=0u;i<6u;i++){\nlet p=params.planes[i];\nif(dot(p.xyz,center)+p.w < -radius){return false;}\n}\nreturn true;\n}\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) gid:vec3<u32>){\nlet i=gid.x;\nif(i>=params.count){return;}\nlet world=params.meshWorld*srcMatrices[i];\nif(!visible(world)){return;}\nlet outIndex=atomicAdd(&args[1],1u);\ndstMatrices[outIndex]=srcMatrices[i];\n}`;\n\nconst CULL_WGSL_COLOR = `${CULL_WGSL_NO_COLOR}\n@group(0)@binding(4)var<storage,read> srcColors:array<vec4<f32>>;\n@group(0)@binding(5)var<storage,read_write> dstColors:array<vec4<f32>>;\n@compute @workgroup_size(64)\nfn mainColor(@builtin(global_invocation_id) gid:vec3<u32>){\nlet i=gid.x;\nif(i>=params.count){return;}\nlet world=params.meshWorld*srcMatrices[i];\nif(!visible(world)){return;}\nlet outIndex=atomicAdd(&args[1],1u);\ndstMatrices[outIndex]=srcMatrices[i];\ndstColors[outIndex]=srcColors[i];\n}`;\n\n// Two-bucket variant used when the mesh has a LOD partner: in-frustum instances partition by camera\n// distance — near keeps the mesh's own compacted bucket, far fills the partner's bucket. `isNear`\n// dithers the threshold per instance by ±lodBand/2 via a pure hash of the instance index (PCG), so\n// the split is deterministic frame-to-frame with no time or randomness input.\nconst CULL_WGSL_LOD_NO_COLOR = /* wgsl */ `\nstruct CullParams{planes:array<vec4<f32>,6>,meshWorld:mat4x4<f32>,localSphere:vec4<f32>,count:u32,boundsPad:f32,camPosDist:vec4<f32>,lodBand:f32};\n@group(0)@binding(0)var<storage,read> srcMatrices:array<mat4x4<f32>>;\n@group(0)@binding(1)var<storage,read_write> dstMatrices:array<mat4x4<f32>>;\n@group(0)@binding(2)var<storage,read_write> args:array<atomic<u32>>;\n@group(0)@binding(3)var<uniform> params:CullParams;\n@group(0)@binding(6)var<storage,read_write> lodMatrices:array<mat4x4<f32>>;\n@group(0)@binding(7)var<storage,read_write> lodArgs:array<atomic<u32>>;\nfn visible(world:mat4x4<f32>)->bool{\nlet center=(world*vec4<f32>(params.localSphere.xyz,1.0)).xyz;\nlet sx=length(world[0].xyz);\nlet sy=length(world[1].xyz);\nlet sz=length(world[2].xyz);\nlet radius=params.localSphere.w*max(max(sx,sy),sz)+params.boundsPad+0.0001;\nfor(var i=0u;i<6u;i++){\nlet p=params.planes[i];\nif(dot(p.xyz,center)+p.w < -radius){return false;}\n}\nreturn true;\n}\nfn isNear(world:mat4x4<f32>,i:u32)->bool{\nlet center=(world*vec4<f32>(params.localSphere.xyz,1.0)).xyz;\nvar h=i*747796405u+2891336453u;\nh=((h>>((h>>28u)+4u))^h)*277803737u;\nh=(h>>22u)^h;\nlet dither=(f32(h)*(1.0/4294967295.0)-0.5)*params.lodBand;\nreturn distance(center,params.camPosDist.xyz)<params.camPosDist.w+dither;\n}\n@compute @workgroup_size(64)\nfn mainLod(@builtin(global_invocation_id) gid:vec3<u32>){\nlet i=gid.x;\nif(i>=params.count){return;}\nlet world=params.meshWorld*srcMatrices[i];\nif(!visible(world)){return;}\nif(isNear(world,i)){\nlet outIndex=atomicAdd(&args[1],1u);\ndstMatrices[outIndex]=srcMatrices[i];\n}else{\nlet outIndex=atomicAdd(&lodArgs[1],1u);\nlodMatrices[outIndex]=srcMatrices[i];\n}\n}`;\n\nconst CULL_WGSL_LOD_COLOR = `${CULL_WGSL_LOD_NO_COLOR}\n@group(0)@binding(4)var<storage,read> srcColors:array<vec4<f32>>;\n@group(0)@binding(5)var<storage,read_write> dstColors:array<vec4<f32>>;\n@group(0)@binding(8)var<storage,read_write> lodColors:array<vec4<f32>>;\n@compute @workgroup_size(64)\nfn mainLodColor(@builtin(global_invocation_id) gid:vec3<u32>){\nlet i=gid.x;\nif(i>=params.count){return;}\nlet world=params.meshWorld*srcMatrices[i];\nif(!visible(world)){return;}\nif(isNear(world,i)){\nlet outIndex=atomicAdd(&args[1],1u);\ndstMatrices[outIndex]=srcMatrices[i];\ndstColors[outIndex]=srcColors[i];\n}else{\nlet outIndex=atomicAdd(&lodArgs[1],1u);\nlodMatrices[outIndex]=srcMatrices[i];\nlodColors[outIndex]=srcColors[i];\n}\n}`;\n\n/** Per-render-binding GPU culling state. */\nexport interface ThinInstanceGpuCullState {\n /** @internal */\n _capacity: number;\n /** @internal */\n _visibleMatrixBuffer: GPUBuffer | null;\n /** @internal */\n _visibleColorBuffer: GPUBuffer | null;\n /** @internal */\n _argsBuffer: GPUBuffer | null;\n /** @internal */\n _paramsBuffer: GPUBuffer | null;\n /** @internal */\n _bindGroup: GPUBindGroup | null;\n /** @internal */\n _srcMatrixBuffer: GPUBuffer | null;\n /** @internal */\n _srcColorBuffer: GPUBuffer | null;\n /** @internal */\n _hasColor: boolean;\n /** @internal */\n _localSphereReady: boolean;\n /** @internal CPU geometry reference used to build `_localSphere`. */\n _localPositions?: Float32Array;\n /** @internal Bounds references used to detect same-buffer geometry updates. */\n _localBoundMin?: Mesh[\"boundMin\"];\n /** @internal Bounds references used to detect same-buffer geometry updates. */\n _localBoundMax?: Mesh[\"boundMax\"];\n /** @internal */\n _localSphere: Float32Array;\n /** @internal */\n _paramsBytes: ArrayBuffer;\n /** @internal */\n _paramsF32: Float32Array;\n /** @internal */\n _paramsU32: Uint32Array;\n /** @internal */\n _argsData: Uint32Array;\n /** @internal */\n _drawBuffers: ThinInstanceDrawBuffers | null;\n /** @internal */\n _indexCount: number;\n /** @internal */\n _active: boolean;\n /** @internal Whether the current pipeline/bind-group/params target the two-bucket LOD variant. */\n _lodActive: boolean;\n /** @internal Far-bucket compacted matrices (two-bucket variant only). */\n _lodMatrixBuffer: GPUBuffer | null;\n /** @internal Far-bucket compacted colors (two-bucket variant with instance colors only). */\n _lodColorBuffer: GPUBuffer | null;\n /** @internal Far-bucket indirect draw args consumed by the LOD partner's draw. */\n _lodArgsBuffer: GPUBuffer | null;\n /** @internal Last index count (the partner mesh's) written to `_lodArgsBuffer`. */\n _lodIndexCount: number;\n /** @internal True once the far-bucket args were zeroed for a fallback frame (reset when culling runs). */\n _lodArgsZeroed: boolean;\n}\n\n/** Result consumed by a material draw closure after culling has run for the active pass. */\nexport interface ThinInstanceGpuCullResult {\n readonly drawBuffers: ThinInstanceDrawBuffers;\n readonly argsBuffer: GPUBuffer;\n /** Far-bucket compacted instance buffers for the LOD partner's draw (two-bucket variant only). */\n readonly lodDrawBuffers?: ThinInstanceDrawBuffers;\n /** Far-bucket indirect args for the LOD partner's draw (two-bucket variant only). */\n readonly lodArgsBuffer?: GPUBuffer;\n}\n\ninterface ComputeDispatch {\n readonly pipeline: GPUComputePipeline;\n readonly bindGroup: GPUBindGroup;\n readonly workgroupsX: number;\n}\n\n/** @internal Task-local batch that submits all culling work through one compute pass. */\nexport interface ComputeDispatchBatch extends DrawUpdateBatch {\n queue(dispatch: ComputeDispatch): void;\n}\n\nlet _cachedDevice: GPUDevice | null = null;\nlet _pipelineNoColor: GPUComputePipeline | null = null;\nlet _pipelineColor: GPUComputePipeline | null = null;\nlet _pipelineLodNoColor: GPUComputePipeline | null = null;\nlet _pipelineLodColor: GPUComputePipeline | null = null;\nlet _dispatchBatches: WeakMap<RenderTargetSignature, ComputeDispatchBatch> | null = null;\n\n/** @internal Return the compute batch associated with one render task. */\nexport function getComputeDispatchBatch(signature: RenderTargetSignature): ComputeDispatchBatch {\n _dispatchBatches ??= new WeakMap();\n let batch = _dispatchBatches.get(signature);\n if (batch) {\n return batch;\n }\n const dispatches: ComputeDispatch[] = [];\n let count = 0;\n batch = {\n reset(): void {\n count = 0;\n },\n flush(engine): void {\n if (count === 0) {\n return;\n }\n const pass = engine._currentEncoder.beginComputePass();\n let lastPipeline: GPUComputePipeline | null = null;\n for (let i = 0; i < count; i++) {\n const dispatch = dispatches[i]!;\n if (dispatch.pipeline !== lastPipeline) {\n pass.setPipeline(dispatch.pipeline);\n lastPipeline = dispatch.pipeline;\n }\n pass.setBindGroup(0, dispatch.bindGroup);\n pass.dispatchWorkgroups(dispatch.workgroupsX);\n }\n pass.end();\n },\n destroy(): void {\n dispatches.length = 0;\n count = 0;\n _dispatchBatches?.delete(signature);\n },\n queue(dispatch): void {\n dispatches[count++] = dispatch;\n },\n };\n _dispatchBatches.set(signature, batch);\n return batch;\n}\n\n/** Create per-binding culling state. */\nexport function createTiCullState(): ThinInstanceGpuCullState {\n // CPU scratch is sized for the larger two-bucket variant; single-bucket states\n // only ever upload the first PARAM_BYTES of it.\n const paramsBytes = new ArrayBuffer(LOD_PARAM_BYTES);\n return {\n _capacity: 0,\n _visibleMatrixBuffer: null,\n _visibleColorBuffer: null,\n _argsBuffer: null,\n _paramsBuffer: null,\n _bindGroup: null,\n _srcMatrixBuffer: null,\n _srcColorBuffer: null,\n _hasColor: false,\n _localSphereReady: false,\n _localSphere: new F32(4),\n _paramsBytes: paramsBytes,\n _paramsF32: new F32(paramsBytes),\n _paramsU32: new U32(paramsBytes),\n _argsData: new U32(5),\n _drawBuffers: null,\n _indexCount: -1,\n _active: false,\n _lodActive: false,\n _lodMatrixBuffer: null,\n _lodColorBuffer: null,\n _lodArgsBuffer: null,\n _lodIndexCount: -1,\n _lodArgsZeroed: false,\n };\n}\n\n/** Destroy GPU resources owned by a per-binding cull state. */\nexport function destroyTiCullState(state: ThinInstanceGpuCullState): void {\n state._visibleMatrixBuffer?.destroy();\n state._visibleColorBuffer?.destroy();\n state._argsBuffer?.destroy();\n state._paramsBuffer?.destroy();\n state._lodMatrixBuffer?.destroy();\n state._lodColorBuffer?.destroy();\n state._lodArgsBuffer?.destroy();\n state._visibleMatrixBuffer = null;\n state._visibleColorBuffer = null;\n state._argsBuffer = null;\n state._paramsBuffer = null;\n state._lodMatrixBuffer = null;\n state._lodColorBuffer = null;\n state._lodArgsBuffer = null;\n state._bindGroup = null;\n state._drawBuffers = null;\n}\n\n/** Run culling for one render binding and return buffers for the subsequent indirect draw. */\nexport function prepareTiCull(\n engine: EngineContext,\n state: ThinInstanceGpuCullState,\n mesh: Mesh,\n gpu: MeshGPU,\n ti: ThinInstanceData,\n hasColor: boolean,\n context: DrawUpdateContext,\n dispatchBatch?: ComputeDispatchBatch,\n lodMesh?: Mesh | null\n): ThinInstanceGpuCullResult | null {\n const camera = context._camera;\n if (!ti._gpuCullingEnabled || !camera || mesh.visible === false || ti.count === 0) {\n return cullFallback(engine, state);\n }\n if (hasColor && !ti.colors) {\n return cullFallback(engine, state);\n }\n const positions = mesh._cpuPositions;\n if (!state._localSphereReady || state._localPositions !== positions || state._localBoundMin !== mesh.boundMin || state._localBoundMax !== mesh.boundMax) {\n if (!computeLocalSphere(mesh as Mesh, state._localSphere)) {\n return cullFallback(engine, state);\n }\n state._localSphereReady = true;\n state._localPositions = positions;\n state._localBoundMin = mesh.boundMin;\n state._localBoundMax = mesh.boundMax;\n }\n\n syncThinInstanceGpuData(engine, ti, hasColor);\n const sourceMatrixBuffer = ti._gpuBuffer;\n const sourceColorBuffer = hasColor ? ti._colorGpuBuffer : null;\n if (!sourceMatrixBuffer || (hasColor && !sourceColorBuffer)) {\n return cullFallback(engine, state);\n }\n\n const lod = lodMesh ?? null;\n ensureCullBuffers(engine, state, ti._capacity, hasColor, lod !== null);\n const visibleMatrixBuffer = state._visibleMatrixBuffer!;\n const visibleColorBuffer = hasColor ? state._visibleColorBuffer! : null;\n const argsBuffer = state._argsBuffer!;\n const paramsBuffer = state._paramsBuffer!;\n const pipeline = getCullPipeline(engine, hasColor, lod !== null);\n\n if (state._bindGroup === null || state._srcMatrixBuffer !== sourceMatrixBuffer || state._srcColorBuffer !== sourceColorBuffer || state._hasColor !== hasColor) {\n const entries: GPUBindGroupEntry[] = [\n { binding: 0, resource: { buffer: sourceMatrixBuffer } },\n { binding: 1, resource: { buffer: visibleMatrixBuffer } },\n { binding: 2, resource: { buffer: argsBuffer } },\n { binding: 3, resource: { buffer: paramsBuffer } },\n ];\n if (hasColor) {\n entries.push({ binding: 4, resource: { buffer: sourceColorBuffer! } }, { binding: 5, resource: { buffer: visibleColorBuffer! } });\n }\n if (lod) {\n entries.push({ binding: 6, resource: { buffer: state._lodMatrixBuffer! } }, { binding: 7, resource: { buffer: state._lodArgsBuffer! } });\n if (hasColor) {\n entries.push({ binding: 8, resource: { buffer: state._lodColorBuffer! } });\n }\n }\n state._bindGroup = engine._device.createBindGroup({ layout: pipeline.getBindGroupLayout(0), entries });\n state._srcMatrixBuffer = sourceMatrixBuffer;\n state._srcColorBuffer = sourceColorBuffer;\n state._hasColor = hasColor;\n }\n\n const v = camera.viewport;\n const aspect = (context.targetWidth / context.targetHeight) * (v ? v.width / v.height : 1);\n writeCullParams(engine, state, mesh, gpu.indexCount, ti.count, camera, aspect, lod);\n\n const dispatch = {\n pipeline,\n bindGroup: state._bindGroup,\n workgroupsX: Math.ceil(ti.count / WORKGROUP_SIZE),\n };\n if (dispatchBatch) {\n dispatchBatch.queue(dispatch);\n } else {\n const pass = engine._currentEncoder.beginComputePass();\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, state._bindGroup);\n pass.dispatchWorkgroups(dispatch.workgroupsX);\n pass.end();\n }\n\n state._drawBuffers = { matrixBuffer: visibleMatrixBuffer, colorBuffer: visibleColorBuffer };\n setCullActive(state, true);\n if (lod) {\n return {\n drawBuffers: state._drawBuffers,\n argsBuffer,\n lodDrawBuffers: { matrixBuffer: state._lodMatrixBuffer!, colorBuffer: hasColor ? state._lodColorBuffer : null },\n lodArgsBuffer: state._lodArgsBuffer!,\n };\n }\n return { drawBuffers: state._drawBuffers, argsBuffer };\n}\n\n/** Shared early-out: deactivate culling for this pass. When the mesh has (or had) a LOD partner, the\n * partner's far-bucket args are zeroed so even a stale recorded indirect draw renders zero instances —\n * the full mesh's non-culled fallback then draws ALL instances without ever double-drawing the far set. */\nfunction cullFallback(engine: EngineContext, state: ThinInstanceGpuCullState): null {\n if (state._lodArgsBuffer && !state._lodArgsZeroed) {\n engine._currentEncoder.clearBuffer(state._lodArgsBuffer, 4, 4);\n state._lodArgsZeroed = true;\n }\n setCullActive(state, false);\n state._drawBuffers = null;\n return null;\n}\n\n/** @internal Publish (or withdraw) one pass's far-bucket outputs for the LOD partner's binding. */\nexport function publishTiLodBucket(ti: ThinInstanceData, signature: RenderTargetSignature, result: ThinInstanceGpuCullResult | null): void {\n const lodDrawBuffers = result?.lodDrawBuffers;\n const lodArgsBuffer = result?.lodArgsBuffer;\n const buckets = ti._lodBuckets;\n if (lodDrawBuffers && lodArgsBuffer && buckets) {\n let bucket = buckets.get(signature);\n if (!bucket) {\n bucket = { matrixBuffer: lodDrawBuffers.matrixBuffer, colorBuffer: lodDrawBuffers.colorBuffer, argsBuffer: lodArgsBuffer, active: true };\n buckets.set(signature, bucket);\n return;\n }\n bucket.matrixBuffer = lodDrawBuffers.matrixBuffer;\n bucket.colorBuffer = lodDrawBuffers.colorBuffer;\n bucket.argsBuffer = lodArgsBuffer;\n bucket.active = true;\n return;\n }\n const bucket = ti._lodBuckets?.get(signature);\n if (bucket) {\n bucket.active = false;\n }\n}\n\nfunction ensureCullBuffers(engine: EngineContext, state: ThinInstanceGpuCullState, capacity: number, hasColor: boolean, lod: boolean): void {\n const device = engine._device;\n if (state._lodActive !== lod) {\n // The params uniform size and bind-group layout differ between the single-bucket and\n // two-bucket pipeline variants — rebuild both on a pairing transition.\n state._paramsBuffer?.destroy();\n state._paramsBuffer = null;\n state._bindGroup = null;\n if (!lod) {\n const lodMat = state._lodMatrixBuffer;\n const lodCol = state._lodColorBuffer;\n const lodArgs = state._lodArgsBuffer;\n if (lodArgs && !state._lodArgsZeroed) {\n // A stale partner bundle may still reference these args this frame — make it draw zero instances.\n engine._currentEncoder.clearBuffer(lodArgs, 4, 4);\n }\n if (lodMat || lodArgs) {\n // Retire (not destroy): the partner's binding may hold last frame's handles until it re-records.\n retireGpuResources(engine, () => {\n lodMat?.destroy();\n lodCol?.destroy();\n lodArgs?.destroy();\n });\n }\n state._lodMatrixBuffer = null;\n state._lodColorBuffer = null;\n state._lodArgsBuffer = null;\n state._lodIndexCount = -1;\n state._lodArgsZeroed = false;\n }\n state._lodActive = lod;\n bumpVisibilityEpoch();\n }\n if (state._capacity < capacity) {\n state._visibleMatrixBuffer?.destroy();\n state._visibleColorBuffer?.destroy();\n state._visibleMatrixBuffer = device.createBuffer({\n size: Math.max(capacity * 64, 4),\n usage: BU.VERTEX | BU.STORAGE,\n });\n state._visibleColorBuffer = hasColor\n ? device.createBuffer({\n size: Math.max(capacity * 16, 4),\n usage: BU.VERTEX | BU.STORAGE,\n })\n : null;\n state._capacity = capacity;\n state._bindGroup = null;\n state._drawBuffers = null;\n bumpVisibilityEpoch();\n } else if (hasColor && !state._visibleColorBuffer) {\n state._visibleColorBuffer = device.createBuffer({\n size: Math.max(state._capacity * 16, 4),\n usage: BU.VERTEX | BU.STORAGE,\n });\n state._bindGroup = null;\n state._drawBuffers = null;\n bumpVisibilityEpoch();\n }\n if (lod && (!state._lodMatrixBuffer || state._lodMatrixBuffer.size < state._capacity * 64 || (hasColor && !state._lodColorBuffer))) {\n const oldMat = state._lodMatrixBuffer;\n const oldCol = state._lodColorBuffer;\n if (oldMat) {\n // Retire (not destroy): the partner's binding may hold last frame's handles until it re-records.\n retireGpuResources(engine, () => {\n oldMat.destroy();\n oldCol?.destroy();\n });\n }\n state._lodMatrixBuffer = device.createBuffer({\n size: Math.max(state._capacity * 64, 4),\n usage: BU.VERTEX | BU.STORAGE,\n });\n state._lodColorBuffer = hasColor\n ? device.createBuffer({\n size: Math.max(state._capacity * 16, 4),\n usage: BU.VERTEX | BU.STORAGE,\n })\n : null;\n state._bindGroup = null;\n bumpVisibilityEpoch();\n }\n if (lod && !state._lodArgsBuffer) {\n state._lodArgsBuffer = device.createBuffer({\n size: INDIRECT_ARGS_BYTES,\n usage: BU.INDIRECT | BU.STORAGE | BU.COPY_DST,\n });\n state._lodIndexCount = -1;\n state._lodArgsZeroed = false;\n }\n if (!state._argsBuffer) {\n state._argsBuffer = device.createBuffer({\n size: INDIRECT_ARGS_BYTES,\n usage: BU.INDIRECT | BU.STORAGE | BU.COPY_DST,\n });\n }\n if (!state._paramsBuffer) {\n state._paramsBuffer = device.createBuffer({\n size: lod ? LOD_PARAM_BYTES : PARAM_BYTES,\n usage: BU.UNIFORM | BU.COPY_DST,\n });\n }\n}\n\nfunction getCullPipeline(engine: EngineContext, hasColor: boolean, lod: boolean): GPUComputePipeline {\n const device = engine._device;\n if (_cachedDevice !== device) {\n _cachedDevice = device;\n _pipelineNoColor = null;\n _pipelineColor = null;\n _pipelineLodNoColor = null;\n _pipelineLodColor = null;\n }\n if (lod) {\n if (hasColor) {\n _pipelineLodColor ??= device.createComputePipeline({\n layout: \"auto\",\n compute: { module: device.createShaderModule({ code: CULL_WGSL_LOD_COLOR }), entryPoint: \"mainLodColor\" },\n });\n return _pipelineLodColor;\n }\n _pipelineLodNoColor ??= device.createComputePipeline({\n layout: \"auto\",\n compute: { module: device.createShaderModule({ code: CULL_WGSL_LOD_NO_COLOR }), entryPoint: \"mainLod\" },\n });\n return _pipelineLodNoColor;\n }\n if (hasColor) {\n _pipelineColor ??= device.createComputePipeline({\n layout: \"auto\",\n compute: { module: device.createShaderModule({ code: CULL_WGSL_COLOR }), entryPoint: \"mainColor\" },\n });\n return _pipelineColor;\n }\n _pipelineNoColor ??= device.createComputePipeline({\n layout: \"auto\",\n compute: { module: device.createShaderModule({ code: CULL_WGSL_NO_COLOR }), entryPoint: \"main\" },\n });\n return _pipelineNoColor;\n}\n\nfunction writeCullParams(\n engine: EngineContext,\n state: ThinInstanceGpuCullState,\n mesh: Mesh,\n indexCount: number,\n instanceCount: number,\n camera: Camera,\n aspect: number,\n lodMesh: Mesh | null\n): void {\n const params = state._paramsF32;\n const viewProjection = getViewProjectionMatrix(camera, aspect);\n writeFrustumPlanes(params, viewProjection);\n params.set(mesh.worldMatrix, MESH_WORLD_FLOAT_OFFSET);\n params.set(state._localSphere, LOCAL_SPHERE_FLOAT_OFFSET);\n state._paramsU32[COUNT_U32_OFFSET] = instanceCount;\n params[BOUNDS_PAD_F32_OFFSET] = mesh.thinInstances?._cullBoundsPad ?? 0;\n if (lodMesh) {\n // Distance test uses the culling pass's own camera (same one the frustum planes come from).\n const cw = camera.worldMatrix;\n params[CAM_POS_DIST_F32_OFFSET] = cw[12]!;\n params[CAM_POS_DIST_F32_OFFSET + 1] = cw[13]!;\n params[CAM_POS_DIST_F32_OFFSET + 2] = cw[14]!;\n params[CAM_POS_DIST_F32_OFFSET + 3] = mesh.thinInstances?._lodDistance ?? 0;\n params[LOD_BAND_F32_OFFSET] = mesh.thinInstances?._lodBand ?? 0;\n }\n\n if (state._indexCount !== indexCount) {\n const args = state._argsData;\n args[0] = indexCount;\n args[1] = 0;\n args[2] = 0;\n args[3] = 0;\n args[4] = 0;\n engine._device.queue.writeBuffer(state._argsBuffer!, 0, args.buffer, args.byteOffset, args.byteLength);\n state._indexCount = indexCount;\n } else {\n engine._currentEncoder.clearBuffer(state._argsBuffer!, 4, 4);\n }\n if (lodMesh) {\n // Far-bucket args carry the PARTNER mesh's index count; the compute pass fills its instance count.\n const lodGpu = lodMesh._gpu as MeshGPU | undefined;\n const lodIndexCount = lodGpu ? lodGpu.indexCount : 0;\n if (state._lodIndexCount !== lodIndexCount) {\n const args = state._argsData;\n args[0] = lodIndexCount;\n args[1] = 0;\n args[2] = 0;\n args[3] = 0;\n args[4] = 0;\n engine._device.queue.writeBuffer(state._lodArgsBuffer!, 0, args.buffer, args.byteOffset, args.byteLength);\n state._lodIndexCount = lodIndexCount;\n } else {\n engine._currentEncoder.clearBuffer(state._lodArgsBuffer!, 4, 4);\n }\n state._lodArgsZeroed = false;\n }\n engine._device.queue.writeBuffer(state._paramsBuffer!, 0, state._paramsBytes, 0, lodMesh ? LOD_PARAM_BYTES : PARAM_BYTES);\n}\n\nfunction setCullActive(state: ThinInstanceGpuCullState, active: boolean): void {\n if (state._active !== active) {\n state._active = active;\n bumpVisibilityEpoch();\n }\n}\n\nfunction writeFrustumPlanes(out: Float32Array, m: Mat4): void {\n writePlane(out, 0, m[3]! + m[0]!, m[7]! + m[4]!, m[11]! + m[8]!, m[15]! + m[12]!);\n writePlane(out, 4, m[3]! - m[0]!, m[7]! - m[4]!, m[11]! - m[8]!, m[15]! - m[12]!);\n writePlane(out, 8, m[3]! + m[1]!, m[7]! + m[5]!, m[11]! + m[9]!, m[15]! + m[13]!);\n writePlane(out, 12, m[3]! - m[1]!, m[7]! - m[5]!, m[11]! - m[9]!, m[15]! - m[13]!);\n writePlane(out, 16, m[2]!, m[6]!, m[10]!, m[14]!);\n writePlane(out, 20, m[3]! - m[2]!, m[7]! - m[6]!, m[11]! - m[10]!, m[15]! - m[14]!);\n}\n\nfunction writePlane(out: Float32Array, offset: number, x: number, y: number, z: number, w: number): void {\n const invLen = 1 / Math.hypot(x, y, z);\n out[offset] = x * invLen;\n out[offset + 1] = y * invLen;\n out[offset + 2] = z * invLen;\n out[offset + 3] = w * invLen;\n}\n\nfunction computeLocalSphere(mesh: Mesh, out: Float32Array): boolean {\n const positions = mesh._cpuPositions;\n if (!positions || positions.length < 3) {\n return false;\n }\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (let i = 0; i < positions.length; i += 3) {\n const x = positions[i]!;\n const y = positions[i + 1]!;\n const z = positions[i + 2]!;\n if (x < minX) {\n minX = x;\n }\n if (x > maxX) {\n maxX = x;\n }\n if (y < minY) {\n minY = y;\n }\n if (y > maxY) {\n maxY = y;\n }\n if (z < minZ) {\n minZ = z;\n }\n if (z > maxZ) {\n maxZ = z;\n }\n }\n if (!isFinite(minX)) {\n return false;\n }\n const cx = (minX + maxX) * 0.5;\n const cy = (minY + maxY) * 0.5;\n const cz = (minZ + maxZ) * 0.5;\n const dx = maxX - cx;\n const dy = maxY - cy;\n const dz = maxZ - cz;\n out[0] = cx;\n out[1] = cy;\n out[2] = cz;\n out[3] = Math.hypot(dx, dy, dz);\n return true;\n}\n"],"names":["bucket"],"mappings":"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"}
|