@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.
Files changed (105) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/index.js +444 -368
  3. package/dist/index.js.map +1 -1
  4. package/index.d.ts +208 -6
  5. package/lib/asset-container.js.map +1 -1
  6. package/lib/audio/index.js +1 -0
  7. package/lib/audio/index.js.map +1 -1
  8. package/lib/audio/media-stream-output.js +44 -0
  9. package/lib/audio/media-stream-output.js.map +1 -0
  10. package/lib/engine/engine.js +1 -1
  11. package/lib/frame-graph/render-task.js +1 -1
  12. package/lib/frame-graph/render-task.js.map +1 -1
  13. package/lib/frame-graph/shadow-inputs.js +10 -1
  14. package/lib/frame-graph/shadow-inputs.js.map +1 -1
  15. package/lib/frame-graph/transmission.js +1 -16
  16. package/lib/frame-graph/transmission.js.map +1 -1
  17. package/lib/index.js +6 -3
  18. package/lib/index.js.map +1 -1
  19. package/lib/loader-gltf/gltf-json-asset.js +1 -1
  20. package/lib/loader-gltf/gltf-json-asset.js.map +1 -1
  21. package/lib/loader-gltf/gltf-multi-buffer.js +2 -10
  22. package/lib/loader-gltf/gltf-multi-buffer.js.map +1 -1
  23. package/lib/loader-gltf/gltf-pbr-builder-ext.js +4 -18
  24. package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
  25. package/lib/loader-gltf/gltf-pbr-builder.js +17 -14
  26. package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
  27. package/lib/loader-gltf/gltf-sampler-desc.js +3 -16
  28. package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
  29. package/lib/material/node/blocks/ambient-occlusion-block.js +1 -4
  30. package/lib/material/node/blocks/ambient-occlusion-block.js.map +1 -1
  31. package/lib/material/node/blocks/biplanar-block.js +3 -6
  32. package/lib/material/node/blocks/biplanar-block.js.map +1 -1
  33. package/lib/material/node/blocks/image-source.js +2 -5
  34. package/lib/material/node/blocks/image-source.js.map +1 -1
  35. package/lib/material/node/blocks/input-block.js +5 -26
  36. package/lib/material/node/blocks/input-block.js.map +1 -1
  37. package/lib/material/node/blocks/pbr-mr-helper-full.js +5 -8
  38. package/lib/material/node/blocks/pbr-mr-helper-full.js.map +1 -1
  39. package/lib/material/node/blocks/reflection-texture-block.js +1 -4
  40. package/lib/material/node/blocks/reflection-texture-block.js.map +1 -1
  41. package/lib/material/node/blocks/texture-block.js +2 -5
  42. package/lib/material/node/blocks/texture-block.js.map +1 -1
  43. package/lib/material/node/blocks/triplanar-block.js +3 -6
  44. package/lib/material/node/blocks/triplanar-block.js.map +1 -1
  45. package/lib/material/node/node-emitter.js +24 -1
  46. package/lib/material/node/node-emitter.js.map +1 -1
  47. package/lib/material/node/node-geometry-renderable.js +2 -2
  48. package/lib/material/node/node-material.js +1 -22
  49. package/lib/material/node/node-material.js.map +1 -1
  50. package/lib/material/node/node-types.js.map +1 -1
  51. package/lib/material/pbr/fragments/shadow-only-fragment.js +68 -0
  52. package/lib/material/pbr/fragments/shadow-only-fragment.js.map +1 -0
  53. package/lib/material/pbr/pbr-flag-bits.js.map +1 -1
  54. package/lib/material/pbr/pbr-material.js.map +1 -1
  55. package/lib/material/pbr/pbr-primitive-resolver.js +2 -2
  56. package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -1
  57. package/lib/material/pbr/pbr-renderable.js +3 -0
  58. package/lib/material/pbr/pbr-renderable.js.map +1 -1
  59. package/lib/material/pbr/pbr-template.js +1 -0
  60. package/lib/material/pbr/pbr-template.js.map +1 -1
  61. package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js +2 -8
  62. package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js.map +1 -1
  63. package/lib/mesh/get-mesh-geometry.js +24 -0
  64. package/lib/mesh/get-mesh-geometry.js.map +1 -0
  65. package/lib/mesh/mesh-dispose.js +2 -0
  66. package/lib/mesh/mesh-dispose.js.map +1 -1
  67. package/lib/mesh/mesh.js +2 -8
  68. package/lib/mesh/mesh.js.map +1 -1
  69. package/lib/mesh/thin-instance-cull-binding.js +54 -3
  70. package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
  71. package/lib/mesh/thin-instance-gpu-culling.js +241 -24
  72. package/lib/mesh/thin-instance-gpu-culling.js.map +1 -1
  73. package/lib/mesh/thin-instance.js +112 -1
  74. package/lib/mesh/thin-instance.js.map +1 -1
  75. package/lib/picking/gpu-picker.js +4 -2
  76. package/lib/picking/gpu-picker.js.map +1 -1
  77. package/lib/picking/picking-pipeline.js +1 -1
  78. package/lib/picking/picking-pipeline.js.map +1 -1
  79. package/lib/picking/picking-shader.js +38 -16
  80. package/lib/picking/picking-shader.js.map +1 -1
  81. package/lib/scene/scene-core.js +7 -2
  82. package/lib/scene/scene-core.js.map +1 -1
  83. package/lib/scene/scene-node.js +2 -6
  84. package/lib/scene/scene-node.js.map +1 -1
  85. package/lib/scene/scene-remove.js +70 -1
  86. package/lib/scene/scene-remove.js.map +1 -1
  87. package/lib/scene/transform-node.js +3 -0
  88. package/lib/scene/transform-node.js.map +1 -1
  89. package/lib/scene/world-matrix-state.js +7 -1
  90. package/lib/scene/world-matrix-state.js.map +1 -1
  91. package/lib/shadow/csm-directional-shadow-generator.js +22 -1
  92. package/lib/shadow/csm-directional-shadow-generator.js.map +1 -1
  93. package/lib/shadow/csm-shadow-task-hooks.js +19 -11
  94. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  95. package/lib/shadow/esm-directional-shadow-generator.js +2 -51
  96. package/lib/shadow/esm-directional-shadow-generator.js.map +1 -1
  97. package/lib/shadow/pcf-directional-shadow-generator.js +2 -48
  98. package/lib/shadow/pcf-directional-shadow-generator.js.map +1 -1
  99. package/lib/shadow/shadow-base.js +48 -1
  100. package/lib/shadow/shadow-base.js.map +1 -1
  101. package/lib/text/text-renderable.js +2 -10
  102. package/lib/text/text-renderable.js.map +1 -1
  103. package/lib/texture/texture-array.js +96 -0
  104. package/lib/texture/texture-array.js.map +1 -0
  105. 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(PARAM_BYTES);
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
- setCullActive(state, false);
141
- state._drawBuffers = null;
142
- return null;
223
+ return cullFallback(engine, state);
143
224
  }
144
225
  if (hasColor && !ti.colors) {
145
- setCullActive(state, false);
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
- setCullActive(state, false);
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
- setCullActive(state, false);
166
- state._drawBuffers = null;
167
- return null;
242
+ return cullFallback(engine, state);
168
243
  }
169
- ensureCullBuffers(engine, state, ti._capacity, hasColor);
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 ensureCullBuffers(engine, state, capacity, hasColor) {
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
- engine._device.queue.writeBuffer(state._paramsBuffer, 0, state._paramsBytes);
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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"}