@babylonjs/lite 1.11.0 → 1.12.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 +22 -0
- package/dist/index.js +444 -368
- package/dist/index.js.map +1 -1
- package/index.d.ts +191 -4
- 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 +5 -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-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/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 +3 -0
- 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/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
package/lib/mesh/mesh-dispose.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { release } from '../resource/ref-count.js';
|
|
2
|
+
import { _detachThinInstanceLodMesh } from './thin-instance.js';
|
|
2
3
|
|
|
3
4
|
function disposeMeshGpu(mesh) {
|
|
4
5
|
const g = mesh._gpu;
|
|
@@ -13,6 +14,7 @@ function disposeMeshGpu(mesh) {
|
|
|
13
14
|
}
|
|
14
15
|
const ti = mesh.thinInstances;
|
|
15
16
|
if (ti && release(ti)) {
|
|
17
|
+
_detachThinInstanceLodMesh(mesh);
|
|
16
18
|
ti._gpuBuffer?.destroy();
|
|
17
19
|
ti._colorGpuBuffer?.destroy();
|
|
18
20
|
ti._drawArgsBuffer?.destroy();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh-dispose.js","sources":["../../../src/mesh/mesh-dispose.ts"],"sourcesContent":["import type { Mesh } from \"./mesh.js\";\nimport { release } from \"../resource/ref-count.js\";\n\n/** Destroy all GPU resources owned by a mesh (vertex buffers, skeleton, morph targets).\n * `_gpu`/`skeleton`/`morphTargets`/`thinInstances` may be SHARED with a clone made via\n * `cloneTransformNode` (see resource/ref-count.ts) — each resource is only actually\n * destroyed once its last owning mesh releases it, so a clone's still-in-use buffers\n * are never freed out from under it (and never double-freed once both are disposed). */\nexport function disposeMeshGpu(mesh: Mesh): void {\n const g = mesh._gpu;\n if (release(g)) {\n g.positionBuffer.destroy();\n g.normalBuffer.destroy();\n g.uvBuffer.destroy();\n g.indexBuffer.destroy();\n g.tangentBuffer?.destroy();\n g.uv2Buffer?.destroy();\n g.colorBuffer?.destroy();\n }\n const ti = mesh.thinInstances;\n if (ti && release(ti)) {\n ti._gpuBuffer?.destroy();\n ti._colorGpuBuffer?.destroy();\n ti._drawArgsBuffer?.destroy();\n }\n const sk = mesh.skeleton;\n if (sk && release(sk)) {\n sk.boneTexture.destroy();\n if (release(sk._skinBuffers)) {\n sk.jointsBuffer.destroy();\n sk.weightsBuffer.destroy();\n sk.joints1Buffer?.destroy();\n sk.weights1Buffer?.destroy();\n }\n }\n const vat = mesh.vat;\n if (vat && release(vat)) {\n vat.settingsBuffer.destroy();\n vat.instanceTexture?.destroy();\n if (release(vat._textureResource)) {\n vat._textureResource.texture.destroy();\n }\n if (release(vat._skinBuffers)) {\n vat.jointsBuffer.destroy();\n vat.weightsBuffer.destroy();\n vat.joints1Buffer?.destroy();\n vat.weights1Buffer?.destroy();\n }\n }\n const mt = mesh.morphTargets;\n if (mt && release(mt)) {\n mt.deltasBuffer.destroy();\n mt.weightsBuffer.destroy();\n }\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mesh-dispose.js","sources":["../../../src/mesh/mesh-dispose.ts"],"sourcesContent":["import type { Mesh } from \"./mesh.js\";\nimport { release } from \"../resource/ref-count.js\";\nimport { _detachThinInstanceLodMesh } from \"./thin-instance.js\";\n\n/** Destroy all GPU resources owned by a mesh (vertex buffers, skeleton, morph targets).\n * `_gpu`/`skeleton`/`morphTargets`/`thinInstances` may be SHARED with a clone made via\n * `cloneTransformNode` (see resource/ref-count.ts) — each resource is only actually\n * destroyed once its last owning mesh releases it, so a clone's still-in-use buffers\n * are never freed out from under it (and never double-freed once both are disposed). */\nexport function disposeMeshGpu(mesh: Mesh): void {\n const g = mesh._gpu;\n if (release(g)) {\n g.positionBuffer.destroy();\n g.normalBuffer.destroy();\n g.uvBuffer.destroy();\n g.indexBuffer.destroy();\n g.tangentBuffer?.destroy();\n g.uv2Buffer?.destroy();\n g.colorBuffer?.destroy();\n }\n const ti = mesh.thinInstances;\n if (ti && release(ti)) {\n _detachThinInstanceLodMesh(mesh);\n ti._gpuBuffer?.destroy();\n ti._colorGpuBuffer?.destroy();\n ti._drawArgsBuffer?.destroy();\n }\n const sk = mesh.skeleton;\n if (sk && release(sk)) {\n sk.boneTexture.destroy();\n if (release(sk._skinBuffers)) {\n sk.jointsBuffer.destroy();\n sk.weightsBuffer.destroy();\n sk.joints1Buffer?.destroy();\n sk.weights1Buffer?.destroy();\n }\n }\n const vat = mesh.vat;\n if (vat && release(vat)) {\n vat.settingsBuffer.destroy();\n vat.instanceTexture?.destroy();\n if (release(vat._textureResource)) {\n vat._textureResource.texture.destroy();\n }\n if (release(vat._skinBuffers)) {\n vat.jointsBuffer.destroy();\n vat.weightsBuffer.destroy();\n vat.joints1Buffer?.destroy();\n vat.weights1Buffer?.destroy();\n }\n }\n const mt = mesh.morphTargets;\n if (mt && release(mt)) {\n mt.deltasBuffer.destroy();\n mt.weightsBuffer.destroy();\n }\n}\n"],"names":[],"mappings":";;;AASO,SAAS,eAAe,IAAA,EAAkB;AAC7C,EAAA,MAAM,IAAI,IAAA,CAAK,IAAA;AACf,EAAA,IAAI,OAAA,CAAQ,CAAC,CAAA,EAAG;AACZ,IAAA,CAAA,CAAE,eAAe,OAAA,EAAQ;AACzB,IAAA,CAAA,CAAE,aAAa,OAAA,EAAQ;AACvB,IAAA,CAAA,CAAE,SAAS,OAAA,EAAQ;AACnB,IAAA,CAAA,CAAE,YAAY,OAAA,EAAQ;AACtB,IAAA,CAAA,CAAE,eAAe,OAAA,EAAQ;AACzB,IAAA,CAAA,CAAE,WAAW,OAAA,EAAQ;AACrB,IAAA,CAAA,CAAE,aAAa,OAAA,EAAQ;AAAA,EAC3B;AACA,EAAA,MAAM,KAAK,IAAA,CAAK,aAAA;AAChB,EAAA,IAAI,EAAA,IAAM,OAAA,CAAQ,EAAE,CAAA,EAAG;AACnB,IAAA,0BAAA,CAA2B,IAAI,CAAA;AAC/B,IAAA,EAAA,CAAG,YAAY,OAAA,EAAQ;AACvB,IAAA,EAAA,CAAG,iBAAiB,OAAA,EAAQ;AAC5B,IAAA,EAAA,CAAG,iBAAiB,OAAA,EAAQ;AAAA,EAChC;AACA,EAAA,MAAM,KAAK,IAAA,CAAK,QAAA;AAChB,EAAA,IAAI,EAAA,IAAM,OAAA,CAAQ,EAAE,CAAA,EAAG;AACnB,IAAA,EAAA,CAAG,YAAY,OAAA,EAAQ;AACvB,IAAA,IAAI,OAAA,CAAQ,EAAA,CAAG,YAAY,CAAA,EAAG;AAC1B,MAAA,EAAA,CAAG,aAAa,OAAA,EAAQ;AACxB,MAAA,EAAA,CAAG,cAAc,OAAA,EAAQ;AACzB,MAAA,EAAA,CAAG,eAAe,OAAA,EAAQ;AAC1B,MAAA,EAAA,CAAG,gBAAgB,OAAA,EAAQ;AAAA,IAC/B;AAAA,EACJ;AACA,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA;AACjB,EAAA,IAAI,GAAA,IAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AACrB,IAAA,GAAA,CAAI,eAAe,OAAA,EAAQ;AAC3B,IAAA,GAAA,CAAI,iBAAiB,OAAA,EAAQ;AAC7B,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAA,EAAG;AAC/B,MAAA,GAAA,CAAI,gBAAA,CAAiB,QAAQ,OAAA,EAAQ;AAAA,IACzC;AACA,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA,EAAG;AAC3B,MAAA,GAAA,CAAI,aAAa,OAAA,EAAQ;AACzB,MAAA,GAAA,CAAI,cAAc,OAAA,EAAQ;AAC1B,MAAA,GAAA,CAAI,eAAe,OAAA,EAAQ;AAC3B,MAAA,GAAA,CAAI,gBAAgB,OAAA,EAAQ;AAAA,IAChC;AAAA,EACJ;AACA,EAAA,MAAM,KAAK,IAAA,CAAK,YAAA;AAChB,EAAA,IAAI,EAAA,IAAM,OAAA,CAAQ,EAAE,CAAA,EAAG;AACnB,IAAA,EAAA,CAAG,aAAa,OAAA,EAAQ;AACxB,IAAA,EAAA,CAAG,cAAc,OAAA,EAAQ;AAAA,EAC7B;AACJ;;;;"}
|
package/lib/mesh/mesh.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import { BU } from '../engine/gpu-flags.js';
|
|
2
2
|
import { createMappedBuffer } from '../resource/gpu-buffers.js';
|
|
3
|
-
import { mat4Compose } from '../math/mat4-compose.js';
|
|
4
|
-
import { mat4Identity } from '../math/mat4-identity.js';
|
|
5
3
|
import { ObservableVec3 } from '../math/observable-vec3.js';
|
|
6
4
|
import { ObservableQuat } from '../math/observable-quat.js';
|
|
7
|
-
import { createWorldMatrixState, attachWorldMatrixState } from '../scene/world-matrix-state.js';
|
|
5
|
+
import { createWorldMatrixState, attachWorldMatrixState, composeTrsLocalMatrix } from '../scene/world-matrix-state.js';
|
|
8
6
|
import { eulerToQuat, createEulerProxy } from '../scene/scene-node.js';
|
|
9
7
|
|
|
10
8
|
function initMeshTransform(mesh, px = 0, py = 0, pz = 0, rx = 0, ry = 0, rz = 0, sx = 1, sy = 1, sz = 1) {
|
|
11
|
-
const wm = createWorldMatrixState(() =>
|
|
12
|
-
const p = mesh.position, rq2 = mesh.rotationQuaternion, s = mesh.scaling;
|
|
13
|
-
const isIdentity = p.x === 0 && p.y === 0 && p.z === 0 && rq2.x === 0 && rq2.y === 0 && rq2.z === 0 && rq2.w === 1 && s.x === 1 && s.y === 1 && s.z === 1;
|
|
14
|
-
return isIdentity ? mat4Identity() : mat4Compose(p.x, p.y, p.z, rq2.x, rq2.y, rq2.z, rq2.w, s.x, s.y, s.z);
|
|
15
|
-
});
|
|
9
|
+
const wm = createWorldMatrixState(() => composeTrsLocalMatrix(mesh.position, mesh.rotationQuaternion, mesh.scaling));
|
|
16
10
|
const onWmDirty = () => wm.markLocalDirty();
|
|
17
11
|
const [iqx, iqy, iqz, iqw] = eulerToQuat(rx, ry, rz);
|
|
18
12
|
const rq = new ObservableQuat(iqx, iqy, iqz, iqw, onWmDirty);
|
package/lib/mesh/mesh.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh.js","sources":["../../../src/mesh/mesh.ts"],"sourcesContent":["/** High-level Mesh — position/rotation/scaling + material + GPU geometry.\n * Plain data (no scene reference). The scene collects meshes via addToScene(). */\n\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport { createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport { mat4Compose } from \"../math/mat4-compose.js\";\nimport { mat4Identity } from \"../math/mat4-identity.js\";\nimport type { Material } from \"../material/material.js\";\nimport type { SkeletonData, MorphTargetData, VatData } from \"../animation/types.js\";\nimport { ObservableVec3 } from \"../math/observable-vec3.js\";\nimport { ObservableQuat } from \"../math/observable-quat.js\";\nimport type { ThinInstanceData } from \"./thin-instance.js\";\nimport { createWorldMatrixState, attachWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport { eulerToQuat, createEulerProxy } from \"../scene/scene-node.js\";\n\n// ─── Mesh GPU Geometry ───────────────────────────────────────────────\n\n/** Per-attribute interleave override. When present, the attribute's GPU buffer\n * is a shared interleaved slice: the pipeline uses `_stride` as the vertex\n * buffer arrayStride and `_offset` as the layout `attributes[].offset`, while the\n * draw binds the buffer at offset 0 (mirrors Babylon.js WebGPU; a non-zero\n * setVertexBuffer bind offset corrupts vertex fetch on some AMD/Dawn paths).\n * Absent attributes use the canonical tight layout (own buffer, default stride,\n * offset 0) — byte-identical to non-interleaved meshes. */\nexport interface MeshVbAttr {\n /** @internal Vertex buffer arrayStride for this attribute's pipeline layout entry. */\n readonly _stride: number;\n /** @internal Byte offset within the shared buffer, encoded in the pipeline vertex\n * layout `attributes[].offset` (the buffer is bound at offset 0). */\n readonly _offset: number;\n}\n\n/** Optional per-attribute interleave layout. Only set for meshes that source one\n * or more attributes from a strided (interleaved) glTF bufferView. */\nexport interface MeshVbLayout {\n /** @internal */\n readonly _p?: MeshVbAttr;\n /** @internal */\n readonly _n?: MeshVbAttr;\n /** @internal */\n readonly _t?: MeshVbAttr;\n /** @internal */\n readonly _u?: MeshVbAttr;\n /** @internal */\n readonly _u2?: MeshVbAttr;\n /** @internal */\n readonly _c?: MeshVbAttr;\n}\n\n/** Opaque GPU geometry handle (user never touches these). */\nexport interface MeshGPU {\n readonly positionBuffer: GPUBuffer;\n readonly normalBuffer: GPUBuffer;\n readonly tangentBuffer?: GPUBuffer | null;\n readonly uvBuffer: GPUBuffer;\n readonly uv2Buffer?: GPUBuffer | null;\n readonly colorBuffer?: GPUBuffer | null;\n readonly hasUv?: boolean;\n readonly hasUv2?: boolean;\n readonly hasTangent?: boolean;\n readonly hasColor?: boolean;\n readonly indexBuffer: GPUBuffer;\n readonly indexCount: number;\n readonly indexFormat: GPUIndexFormat;\n /** @internal Reserved vertex capacity for grow-only procedural geometry. */\n _vertexCapacity?: number;\n /** @internal Reserved index capacity for grow-only procedural geometry. */\n _indexCapacity?: number;\n /** @internal Reused padded indices whose inactive tail is degenerate. */\n _indexScratch?: Uint32Array;\n /** @internal Per-attribute interleave layout. Undefined → all attributes tight (default). */\n readonly _vbLayout?: MeshVbLayout;\n /** @internal Precomputed pipeline cache-key suffix for this mesh's interleave layout.\n * Built once by the interleave module so the hot render path never assembles\n * it. Undefined → tight mesh (empty suffix, byte-identical pipeline key). */\n readonly _vbKey?: string;\n /** @internal Extra-owner count when shared with a clone via `cloneTransformNode` — see\n * resource/ref-count.ts. Absent/undefined means exactly one (implicit) owner. */\n _refCount?: number;\n}\n\n// ─── Mesh ────────────────────────────────────────────────────────────\n\n/** A renderable mesh — plain data with transform, material, and GPU geometry.\n * Works with both standard and PBR pipelines; routing is based on material type.\n * Extends SceneNode for the full TRS + parent + children hierarchy. */\nexport interface Mesh extends SceneNode {\n /** Unique ID from source file (e.g. .babylon). Used for light include/exclude filtering. */\n id?: string;\n material: Material;\n receiveShadows: boolean;\n /** World-space bounding box (set by loaders for camera framing). */\n boundMin?: [number, number, number];\n boundMax?: [number, number, number];\n /** Skeleton GPU data (skeletal animation). Type-only — no module dependency. */\n skeleton?: SkeletonData | null;\n /** Baked vertex-animation (VAT) GPU data — replaces live skinning so the mesh thin-instances.\n * Mutually exclusive with live `skeleton` skinning. Type-only — no module dependency. */\n vat?: VatData | null;\n /** Morph target GPU data. Type-only — no module dependency. */\n morphTargets?: MorphTargetData | null;\n /** User-controlled render order. Lower = drawn first within phase.\n * Only affects ordering within the opaque or transparent phase. */\n renderOrder?: number;\n /** On a transmission-enabled render task, draw this transparent mesh LAST — after the transmissive\n * surface and after the scene-colour grab — so it sits on top of the water/glass AND is excluded from\n * what that surface refracts (e.g. lily pads resting on water should not appear in the refraction).\n * Enable transmission on the task with `enableRenderTaskTransmission`; only transparent surfaces\n * (`needAlphaBlending`) are deferred. No effect on tasks without transmission. */\n renderOnTop?: boolean;\n /** Thin instance data (CPU-side). GPU buffer managed by render system. */\n thinInstances?: ThinInstanceData | null;\n /** When `false`, the GPU picker skips this mesh. Defaults to `true`\n * (undefined behaves as pickable). Mirrors BJS `AbstractMesh.isPickable`. */\n pickable?: boolean;\n // name, children, position, rotation, rotationQuaternion, scaling,\n // parent, worldMatrix, worldMatrixVersion — all inherited from SceneNode\n\n /** @internal */\n _gpu: MeshGPU;\n /** @internal */\n _cpuPositions?: Float32Array;\n /** @internal */\n _cpuNormals?: Float32Array;\n /** @internal */\n _cpuUvs?: Float32Array;\n /** @internal */\n _cpuUv2s?: Float32Array | null;\n /** @internal */\n _cpuTangents?: Float32Array | null;\n /** @internal */\n _cpuColors?: Float32Array | null;\n /** @internal */\n _cpuIndices?: Uint32Array;\n /** @internal */\n _cpuGpuIndices?: Uint16Array | Uint32Array;\n /** @internal */\n _cpuIndexFormat?: GPUIndexFormat;\n}\n\n/** Wire ObservableVec3/ObservableQuat TRS and children onto a partially-built mesh object.\n * Used by all mesh creation paths (factories, loaders). */\nexport function initMeshTransform(mesh: Mesh, px = 0, py = 0, pz = 0, rx = 0, ry = 0, rz = 0, sx = 1, sy = 1, sz = 1): void {\n const wm = createWorldMatrixState(() => {\n const p = mesh.position,\n rq = mesh.rotationQuaternion,\n s = mesh.scaling;\n const isIdentity = p.x === 0 && p.y === 0 && p.z === 0 && rq.x === 0 && rq.y === 0 && rq.z === 0 && rq.w === 1 && s.x === 1 && s.y === 1 && s.z === 1;\n return isIdentity ? mat4Identity() : mat4Compose(p.x, p.y, p.z, rq.x, rq.y, rq.z, rq.w, s.x, s.y, s.z);\n });\n const onWmDirty = () => wm.markLocalDirty();\n\n const [iqx, iqy, iqz, iqw] = eulerToQuat(rx, ry, rz);\n const rq = new ObservableQuat(iqx, iqy, iqz, iqw, onWmDirty);\n mesh.rotationQuaternion = rq;\n mesh.rotation = createEulerProxy(rq);\n mesh.position = new ObservableVec3(px, py, pz, onWmDirty);\n mesh.scaling = new ObservableVec3(sx, sy, sz, onWmDirty);\n\n if (!(mesh as unknown as Record<string, unknown>).children) {\n (mesh as unknown as Record<string, unknown>).children = [];\n }\n\n Object.defineProperty(mesh, \"parent\", {\n get() {\n return wm.parent;\n },\n set(v) {\n wm.parent = v;\n },\n configurable: true,\n enumerable: true,\n });\n Object.defineProperty(mesh, \"worldMatrix\", {\n get() {\n return wm.getWorldMatrix();\n },\n configurable: true,\n enumerable: false,\n });\n Object.defineProperty(mesh, \"worldMatrixVersion\", {\n get() {\n return wm.getWorldMatrixVersion();\n },\n configurable: true,\n enumerable: false,\n });\n attachWorldMatrixState(mesh, wm);\n}\n\n// ─── GPU Geometry Upload ─────────────────────────────────────────────\n\n/** Upload typed arrays to GPU buffers and return a MeshGPU handle. */\nexport function uploadMeshToGPU(\n engine: EngineContext,\n positions: Float32Array,\n normals: Float32Array,\n indices: Uint32Array,\n uvs?: Float32Array,\n uvs2?: Float32Array,\n tangents?: Float32Array,\n colors?: Float32Array\n): MeshGPU {\n const device = engine._device;\n const positionBuffer = createMappedBuffer(engine, positions, BU.VERTEX);\n const normalBuffer = createMappedBuffer(engine, normals, BU.VERTEX);\n const indexBuffer = createMappedBuffer(engine, indices, BU.INDEX);\n\n // UVs: use provided or create zero-filled buffer\n let uvBuffer: GPUBuffer;\n if (uvs && uvs.length > 0) {\n uvBuffer = createMappedBuffer(engine, uvs, BU.VERTEX);\n } else {\n uvBuffer = device.createBuffer({\n size: (positions.length / 3) * 8,\n usage: BU.VERTEX,\n mappedAtCreation: true,\n });\n uvBuffer.unmap();\n }\n\n // UV2: only create if provided\n let uv2Buffer: GPUBuffer | null = null;\n if (uvs2 && uvs2.length > 0) {\n uv2Buffer = createMappedBuffer(engine, uvs2, BU.VERTEX);\n }\n\n const tangentBuffer = tangents && tangents.length > 0 ? createMappedBuffer(engine, tangents, BU.VERTEX) : null;\n const colorBuffer = colors && colors.length > 0 ? createMappedBuffer(engine, colors, BU.VERTEX) : null;\n\n return {\n positionBuffer,\n normalBuffer,\n uvBuffer,\n uv2Buffer,\n tangentBuffer,\n colorBuffer,\n hasUv: !!uvs && uvs.length > 0,\n hasUv2: !!uvs2 && uvs2.length > 0,\n hasTangent: !!tangents && tangents.length > 0,\n hasColor: !!colors && colors.length > 0,\n indexBuffer,\n indexCount: indices.length,\n indexFormat: \"uint32\",\n };\n}\n"],"names":["rq"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mesh.js","sources":["../../../src/mesh/mesh.ts"],"sourcesContent":["/** High-level Mesh — position/rotation/scaling + material + GPU geometry.\n * Plain data (no scene reference). The scene collects meshes via addToScene(). */\n\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport { createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport type { Material } from \"../material/material.js\";\nimport type { SkeletonData, MorphTargetData, VatData } from \"../animation/types.js\";\nimport { ObservableVec3 } from \"../math/observable-vec3.js\";\nimport { ObservableQuat } from \"../math/observable-quat.js\";\nimport type { ThinInstanceData } from \"./thin-instance.js\";\nimport { createWorldMatrixState, attachWorldMatrixState, composeTrsLocalMatrix } from \"../scene/world-matrix-state.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport { eulerToQuat, createEulerProxy } from \"../scene/scene-node.js\";\n\n// ─── Mesh GPU Geometry ───────────────────────────────────────────────\n\n/** Per-attribute interleave override. When present, the attribute's GPU buffer\n * is a shared interleaved slice: the pipeline uses `_stride` as the vertex\n * buffer arrayStride and `_offset` as the layout `attributes[].offset`, while the\n * draw binds the buffer at offset 0 (mirrors Babylon.js WebGPU; a non-zero\n * setVertexBuffer bind offset corrupts vertex fetch on some AMD/Dawn paths).\n * Absent attributes use the canonical tight layout (own buffer, default stride,\n * offset 0) — byte-identical to non-interleaved meshes. */\nexport interface MeshVbAttr {\n /** @internal Vertex buffer arrayStride for this attribute's pipeline layout entry. */\n readonly _stride: number;\n /** @internal Byte offset within the shared buffer, encoded in the pipeline vertex\n * layout `attributes[].offset` (the buffer is bound at offset 0). */\n readonly _offset: number;\n}\n\n/** Optional per-attribute interleave layout. Only set for meshes that source one\n * or more attributes from a strided (interleaved) glTF bufferView. */\nexport interface MeshVbLayout {\n /** @internal */\n readonly _p?: MeshVbAttr;\n /** @internal */\n readonly _n?: MeshVbAttr;\n /** @internal */\n readonly _t?: MeshVbAttr;\n /** @internal */\n readonly _u?: MeshVbAttr;\n /** @internal */\n readonly _u2?: MeshVbAttr;\n /** @internal */\n readonly _c?: MeshVbAttr;\n}\n\n/** Opaque GPU geometry handle (user never touches these). */\nexport interface MeshGPU {\n readonly positionBuffer: GPUBuffer;\n readonly normalBuffer: GPUBuffer;\n readonly tangentBuffer?: GPUBuffer | null;\n readonly uvBuffer: GPUBuffer;\n readonly uv2Buffer?: GPUBuffer | null;\n readonly colorBuffer?: GPUBuffer | null;\n readonly hasUv?: boolean;\n readonly hasUv2?: boolean;\n readonly hasTangent?: boolean;\n readonly hasColor?: boolean;\n readonly indexBuffer: GPUBuffer;\n readonly indexCount: number;\n readonly indexFormat: GPUIndexFormat;\n /** @internal Reserved vertex capacity for grow-only procedural geometry. */\n _vertexCapacity?: number;\n /** @internal Reserved index capacity for grow-only procedural geometry. */\n _indexCapacity?: number;\n /** @internal Reused padded indices whose inactive tail is degenerate. */\n _indexScratch?: Uint32Array;\n /** @internal Per-attribute interleave layout. Undefined → all attributes tight (default). */\n readonly _vbLayout?: MeshVbLayout;\n /** @internal Precomputed pipeline cache-key suffix for this mesh's interleave layout.\n * Built once by the interleave module so the hot render path never assembles\n * it. Undefined → tight mesh (empty suffix, byte-identical pipeline key). */\n readonly _vbKey?: string;\n /** @internal Extra-owner count when shared with a clone via `cloneTransformNode` — see\n * resource/ref-count.ts. Absent/undefined means exactly one (implicit) owner. */\n _refCount?: number;\n}\n\n// ─── Mesh ────────────────────────────────────────────────────────────\n\n/** A renderable mesh — plain data with transform, material, and GPU geometry.\n * Works with both standard and PBR pipelines; routing is based on material type.\n * Extends SceneNode for the full TRS + parent + children hierarchy. */\nexport interface Mesh extends SceneNode {\n /** Unique ID from source file (e.g. .babylon). Used for light include/exclude filtering. */\n id?: string;\n material: Material;\n receiveShadows: boolean;\n /** World-space bounding box (set by loaders for camera framing). */\n boundMin?: [number, number, number];\n boundMax?: [number, number, number];\n /** Skeleton GPU data (skeletal animation). Type-only — no module dependency. */\n skeleton?: SkeletonData | null;\n /** Baked vertex-animation (VAT) GPU data — replaces live skinning so the mesh thin-instances.\n * Mutually exclusive with live `skeleton` skinning. Type-only — no module dependency. */\n vat?: VatData | null;\n /** Morph target GPU data. Type-only — no module dependency. */\n morphTargets?: MorphTargetData | null;\n /** User-controlled render order. Lower = drawn first within phase.\n * Only affects ordering within the opaque or transparent phase. */\n renderOrder?: number;\n /** On a transmission-enabled render task, draw this transparent mesh LAST — after the transmissive\n * surface and after the scene-colour grab — so it sits on top of the water/glass AND is excluded from\n * what that surface refracts (e.g. lily pads resting on water should not appear in the refraction).\n * Enable transmission on the task with `enableRenderTaskTransmission`; only transparent surfaces\n * (`needAlphaBlending`) are deferred. No effect on tasks without transmission. */\n renderOnTop?: boolean;\n /** Thin instance data (CPU-side). GPU buffer managed by render system. */\n thinInstances?: ThinInstanceData | null;\n /** When `false`, the GPU picker skips this mesh. Defaults to `true`\n * (undefined behaves as pickable). Mirrors BJS `AbstractMesh.isPickable`. */\n pickable?: boolean;\n // name, children, position, rotation, rotationQuaternion, scaling,\n // parent, worldMatrix, worldMatrixVersion — all inherited from SceneNode\n\n /** @internal */\n _gpu: MeshGPU;\n /** @internal Reason cloning this mesh is currently forbidden. */\n _clone?: string;\n /** @internal Highest CSM cascade this mesh casts into; undefined means all cascades. */\n _shadowMaxCascade?: number;\n /** @internal */\n _cpuPositions?: Float32Array;\n /** @internal */\n _cpuNormals?: Float32Array;\n /** @internal */\n _cpuUvs?: Float32Array;\n /** @internal */\n _cpuUv2s?: Float32Array | null;\n /** @internal */\n _cpuTangents?: Float32Array | null;\n /** @internal */\n _cpuColors?: Float32Array | null;\n /** @internal */\n _cpuIndices?: Uint32Array;\n /** @internal */\n _cpuGpuIndices?: Uint16Array | Uint32Array;\n /** @internal */\n _cpuIndexFormat?: GPUIndexFormat;\n}\n\n/** Wire ObservableVec3/ObservableQuat TRS and children onto a partially-built mesh object.\n * Used by all mesh creation paths (factories, loaders). */\nexport function initMeshTransform(mesh: Mesh, px = 0, py = 0, pz = 0, rx = 0, ry = 0, rz = 0, sx = 1, sy = 1, sz = 1): void {\n const wm = createWorldMatrixState(() => composeTrsLocalMatrix(mesh.position, mesh.rotationQuaternion, mesh.scaling));\n const onWmDirty = () => wm.markLocalDirty();\n\n const [iqx, iqy, iqz, iqw] = eulerToQuat(rx, ry, rz);\n const rq = new ObservableQuat(iqx, iqy, iqz, iqw, onWmDirty);\n mesh.rotationQuaternion = rq;\n mesh.rotation = createEulerProxy(rq);\n mesh.position = new ObservableVec3(px, py, pz, onWmDirty);\n mesh.scaling = new ObservableVec3(sx, sy, sz, onWmDirty);\n\n if (!(mesh as unknown as Record<string, unknown>).children) {\n (mesh as unknown as Record<string, unknown>).children = [];\n }\n\n Object.defineProperty(mesh, \"parent\", {\n get() {\n return wm.parent;\n },\n set(v) {\n wm.parent = v;\n },\n configurable: true,\n enumerable: true,\n });\n Object.defineProperty(mesh, \"worldMatrix\", {\n get() {\n return wm.getWorldMatrix();\n },\n configurable: true,\n enumerable: false,\n });\n Object.defineProperty(mesh, \"worldMatrixVersion\", {\n get() {\n return wm.getWorldMatrixVersion();\n },\n configurable: true,\n enumerable: false,\n });\n attachWorldMatrixState(mesh, wm);\n}\n\n// ─── GPU Geometry Upload ─────────────────────────────────────────────\n\n/** Upload typed arrays to GPU buffers and return a MeshGPU handle. */\nexport function uploadMeshToGPU(\n engine: EngineContext,\n positions: Float32Array,\n normals: Float32Array,\n indices: Uint32Array,\n uvs?: Float32Array,\n uvs2?: Float32Array,\n tangents?: Float32Array,\n colors?: Float32Array\n): MeshGPU {\n const device = engine._device;\n const positionBuffer = createMappedBuffer(engine, positions, BU.VERTEX);\n const normalBuffer = createMappedBuffer(engine, normals, BU.VERTEX);\n const indexBuffer = createMappedBuffer(engine, indices, BU.INDEX);\n\n // UVs: use provided or create zero-filled buffer\n let uvBuffer: GPUBuffer;\n if (uvs && uvs.length > 0) {\n uvBuffer = createMappedBuffer(engine, uvs, BU.VERTEX);\n } else {\n uvBuffer = device.createBuffer({\n size: (positions.length / 3) * 8,\n usage: BU.VERTEX,\n mappedAtCreation: true,\n });\n uvBuffer.unmap();\n }\n\n // UV2: only create if provided\n let uv2Buffer: GPUBuffer | null = null;\n if (uvs2 && uvs2.length > 0) {\n uv2Buffer = createMappedBuffer(engine, uvs2, BU.VERTEX);\n }\n\n const tangentBuffer = tangents && tangents.length > 0 ? createMappedBuffer(engine, tangents, BU.VERTEX) : null;\n const colorBuffer = colors && colors.length > 0 ? createMappedBuffer(engine, colors, BU.VERTEX) : null;\n\n return {\n positionBuffer,\n normalBuffer,\n uvBuffer,\n uv2Buffer,\n tangentBuffer,\n colorBuffer,\n hasUv: !!uvs && uvs.length > 0,\n hasUv2: !!uvs2 && uvs2.length > 0,\n hasTangent: !!tangents && tangents.length > 0,\n hasColor: !!colors && colors.length > 0,\n indexBuffer,\n indexCount: indices.length,\n indexFormat: \"uint32\",\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import { createTiCullState, destroyTiCullState, getComputeDispatchBatch, prepareTiCull } from './thin-instance-gpu-culling.js';
|
|
1
|
+
import { createTiCullState, destroyTiCullState, getComputeDispatchBatch, prepareTiCull, publishTiLodBucket } from './thin-instance-gpu-culling.js';
|
|
2
2
|
|
|
3
3
|
function tryBind(renderable, scene, mesh, engine, hasColor, excluded, baseUpdate, signature) {
|
|
4
4
|
const ti = mesh.thinInstances;
|
|
5
|
-
if (
|
|
5
|
+
if (!ti) {
|
|
6
|
+
return void 0;
|
|
7
|
+
}
|
|
8
|
+
if (ti._lodSource) {
|
|
9
|
+
if (excluded) {
|
|
10
|
+
throw new Error("Thin-instance LOD partners require an opaque, non-transmissive material");
|
|
11
|
+
}
|
|
12
|
+
renderable._direct = true;
|
|
13
|
+
return bindLodPartner(ti, signature, hasColor, baseUpdate);
|
|
14
|
+
}
|
|
15
|
+
if (excluded || !ti._gpuCullingEnabled) {
|
|
6
16
|
return void 0;
|
|
7
17
|
}
|
|
8
18
|
const holder = renderable;
|
|
@@ -25,9 +35,13 @@ function tryBind(renderable, scene, mesh, engine, hasColor, excluded, baseUpdate
|
|
|
25
35
|
_updateBatch: updateBatch,
|
|
26
36
|
update(context) {
|
|
27
37
|
baseUpdate?.(context);
|
|
28
|
-
const
|
|
38
|
+
const partner = ti._lodPartner ?? null;
|
|
39
|
+
const res = prepareTiCull(engine, state, mesh, mesh._gpu, ti, hasColor, context, updateBatch, partner);
|
|
29
40
|
binding.cullDrawBufs = res?.drawBuffers ?? null;
|
|
30
41
|
binding._args = res?.argsBuffer ?? null;
|
|
42
|
+
if (ti._lodBuckets) {
|
|
43
|
+
publishTiLodBucket(ti, signature, res);
|
|
44
|
+
}
|
|
31
45
|
},
|
|
32
46
|
draw(pass, indexCount, instanceCount) {
|
|
33
47
|
if (binding._args) {
|
|
@@ -41,6 +55,43 @@ function tryBind(renderable, scene, mesh, engine, hasColor, excluded, baseUpdate
|
|
|
41
55
|
};
|
|
42
56
|
return binding;
|
|
43
57
|
}
|
|
58
|
+
function bindLodPartner(ti, signature, hasColor, baseUpdate) {
|
|
59
|
+
const currentBucket = () => {
|
|
60
|
+
const bucket = ti._lodBuckets?.get(signature);
|
|
61
|
+
if (!bucket?.active) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (hasColor && !bucket.colorBuffer) {
|
|
65
|
+
throw new Error("Thin-instance LOD partner requires the source draw to provide instance colors");
|
|
66
|
+
}
|
|
67
|
+
return bucket;
|
|
68
|
+
};
|
|
69
|
+
const binding = {
|
|
70
|
+
get cullDrawBufs() {
|
|
71
|
+
return currentBucket();
|
|
72
|
+
},
|
|
73
|
+
get _args() {
|
|
74
|
+
return currentBucket()?.argsBuffer ?? null;
|
|
75
|
+
},
|
|
76
|
+
_updateBatch: getComputeDispatchBatch(signature),
|
|
77
|
+
update(context) {
|
|
78
|
+
baseUpdate?.(context);
|
|
79
|
+
},
|
|
80
|
+
draw(pass, indexCount, instanceCount) {
|
|
81
|
+
const bucket = currentBucket();
|
|
82
|
+
if (bucket) {
|
|
83
|
+
pass.drawIndexedIndirect(bucket.argsBuffer, 0);
|
|
84
|
+
} else if (!ti._lodSource) {
|
|
85
|
+
if (ti._drawArgsBuffer) {
|
|
86
|
+
pass.drawIndexedIndirect(ti._drawArgsBuffer, 0);
|
|
87
|
+
} else {
|
|
88
|
+
pass.drawIndexed(indexCount, instanceCount);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
return binding;
|
|
94
|
+
}
|
|
44
95
|
|
|
45
96
|
export { tryBind };
|
|
46
97
|
//# sourceMappingURL=thin-instance-cull-binding.js.map
|
|
@@ -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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"}
|