@babylonjs/lite 1.9.0 → 1.10.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 (128) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/index.js +596 -526
  3. package/dist/index.js.map +1 -1
  4. package/index.d.ts +107 -4
  5. package/lib/engine/engine.js +1 -1
  6. package/lib/engine/engine.js.map +1 -1
  7. package/lib/frame-graph/render-task.js +6 -4
  8. package/lib/frame-graph/render-task.js.map +1 -1
  9. package/lib/index.js +4 -1
  10. package/lib/index.js.map +1 -1
  11. package/lib/loader-gltf/gltf-ext-quantization.js +4 -1
  12. package/lib/loader-gltf/gltf-ext-quantization.js.map +1 -1
  13. package/lib/loader-gltf/gltf-feature-registry.js +11 -1
  14. package/lib/loader-gltf/gltf-feature-registry.js.map +1 -1
  15. package/lib/loader-gltf/gltf-feature-variants.js +11 -1
  16. package/lib/loader-gltf/gltf-feature-variants.js.map +1 -1
  17. package/lib/loader-gltf/gltf-json-asset.js +8 -1
  18. package/lib/loader-gltf/gltf-json-asset.js.map +1 -1
  19. package/lib/loader-gltf/gltf-material.js +4 -29
  20. package/lib/loader-gltf/gltf-material.js.map +1 -1
  21. package/lib/loader-gltf/gltf-parser.js +1 -8
  22. package/lib/loader-gltf/gltf-parser.js.map +1 -1
  23. package/lib/loader-gltf/gltf-pbr-builder.js +1 -15
  24. package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
  25. package/lib/loader-gltf/gltf-variants.js +5 -10
  26. package/lib/loader-gltf/gltf-variants.js.map +1 -1
  27. package/lib/loader-gltf/load-gltf.js +19 -29
  28. package/lib/loader-gltf/load-gltf.js.map +1 -1
  29. package/lib/material/pbr/background-dds-skybox.js +35 -93
  30. package/lib/material/pbr/background-dds-skybox.js.map +1 -1
  31. package/lib/material/pbr/background-ground.js +13 -18
  32. package/lib/material/pbr/background-ground.js.map +1 -1
  33. package/lib/material/pbr/background-hdr-skybox.js +35 -93
  34. package/lib/material/pbr/background-hdr-skybox.js.map +1 -1
  35. package/lib/material/pbr/background-solid-skybox.js +35 -93
  36. package/lib/material/pbr/background-solid-skybox.js.map +1 -1
  37. package/lib/material/pbr/fragments/clearcoat-fragment.js +5 -1
  38. package/lib/material/pbr/fragments/clearcoat-fragment.js.map +1 -1
  39. package/lib/material/pbr/fragments/iridescence-fragment.js +4 -1
  40. package/lib/material/pbr/fragments/iridescence-fragment.js.map +1 -1
  41. package/lib/material/pbr/fragments/refraction-rtt-fragment.js +7 -2
  42. package/lib/material/pbr/fragments/refraction-rtt-fragment.js.map +1 -1
  43. package/lib/material/pbr/fragments/sheen-fragment.js +2 -1
  44. package/lib/material/pbr/fragments/sheen-fragment.js.map +1 -1
  45. package/lib/material/pbr/fragments/subsurface-fragment.js +2 -1
  46. package/lib/material/pbr/fragments/subsurface-fragment.js.map +1 -1
  47. package/lib/material/pbr/fragments/unlit-fragment.js +1 -2
  48. package/lib/material/pbr/fragments/unlit-fragment.js.map +1 -1
  49. package/lib/material/pbr/pbr-compose.js +2 -0
  50. package/lib/material/pbr/pbr-compose.js.map +1 -1
  51. package/lib/material/pbr/pbr-flag-bits.js +1 -16
  52. package/lib/material/pbr/pbr-flag-bits.js.map +1 -1
  53. package/lib/material/pbr/pbr-flags.js +1 -1
  54. package/lib/material/pbr/pbr-fog-wgsl.js +1 -1
  55. package/lib/material/pbr/pbr-fog-wgsl.js.map +1 -1
  56. package/lib/material/pbr/pbr-geometry-output-shader.js +2 -1
  57. package/lib/material/pbr/pbr-geometry-output-shader.js.map +1 -1
  58. package/lib/material/pbr/pbr-geometry-view.js +2 -1
  59. package/lib/material/pbr/pbr-geometry-view.js.map +1 -1
  60. package/lib/material/pbr/pbr-renderable.js +4 -0
  61. package/lib/material/pbr/pbr-renderable.js.map +1 -1
  62. package/lib/material/pbr/pbr-template-gamma.js +7 -0
  63. package/lib/material/pbr/pbr-template-gamma.js.map +1 -0
  64. package/lib/material/pbr/pbr-template.js +2 -2
  65. package/lib/material/pbr/pbr-template.js.map +1 -1
  66. package/lib/material/standard/skybox-cubemap.js +1 -1
  67. package/lib/material/standard/skybox-cubemap.js.map +1 -1
  68. package/lib/material/standard/standard-template.js +1 -1
  69. package/lib/material/standard/standard-template.js.map +1 -1
  70. package/lib/mesh/GaussianSplatting/gaussian-splatting-pipeline-sh.js +3 -5
  71. package/lib/mesh/GaussianSplatting/gaussian-splatting-pipeline-sh.js.map +1 -1
  72. package/lib/mesh/GaussianSplatting/gaussian-splatting-pipeline.js +3 -5
  73. package/lib/mesh/GaussianSplatting/gaussian-splatting-pipeline.js.map +1 -1
  74. package/lib/particle/node/blocks/particle-condition-block.js +55 -0
  75. package/lib/particle/node/blocks/particle-condition-block.js.map +1 -0
  76. package/lib/particle/node/blocks/particle-float-to-int-block.js +28 -0
  77. package/lib/particle/node/blocks/particle-float-to-int-block.js.map +1 -0
  78. package/lib/particle/node/blocks/particle-gradient-block.js +32 -0
  79. package/lib/particle/node/blocks/particle-gradient-block.js.map +1 -0
  80. package/lib/particle/node/blocks/particle-gradient-value-block.js +11 -0
  81. package/lib/particle/node/blocks/particle-gradient-value-block.js.map +1 -0
  82. package/lib/particle/node/blocks/particle-lerp-block.js +2 -24
  83. package/lib/particle/node/blocks/particle-lerp-block.js.map +1 -1
  84. package/lib/particle/node/blocks/particle-lerp.js +27 -0
  85. package/lib/particle/node/blocks/particle-lerp.js.map +1 -0
  86. package/lib/particle/node/blocks/particle-vector-length-block.js +30 -0
  87. package/lib/particle/node/blocks/particle-vector-length-block.js.map +1 -0
  88. package/lib/particle/node/blocks/system-block.js +13 -3
  89. package/lib/particle/node/blocks/system-block.js.map +1 -1
  90. package/lib/particle/node/blocks/texture-source-block.js +2 -1
  91. package/lib/particle/node/blocks/texture-source-block.js.map +1 -1
  92. package/lib/particle/node/blocks/update-size-block.js +19 -0
  93. package/lib/particle/node/blocks/update-size-block.js.map +1 -0
  94. package/lib/particle/node/npe-build-state.js +10 -0
  95. package/lib/particle/node/npe-build-state.js.map +1 -1
  96. package/lib/particle/node/npe-registry.js +12 -0
  97. package/lib/particle/node/npe-registry.js.map +1 -1
  98. package/lib/particle/particle-system.js +7 -2
  99. package/lib/particle/particle-system.js.map +1 -1
  100. package/lib/picking/billboard-pick-pipeline.js +269 -0
  101. package/lib/picking/billboard-pick-pipeline.js.map +1 -0
  102. package/lib/picking/gpu-picker.js +37 -37
  103. package/lib/picking/gpu-picker.js.map +1 -1
  104. package/lib/picking/gs-picking-pipeline.js +26 -1
  105. package/lib/picking/gs-picking-pipeline.js.map +1 -1
  106. package/lib/picking/pick-contributor.js +13 -0
  107. package/lib/picking/pick-contributor.js.map +1 -0
  108. package/lib/picking/picking-info.js.map +1 -1
  109. package/lib/scene/scene-core.js +2 -2
  110. package/lib/scene/scene-core.js.map +1 -1
  111. package/lib/shader/wgsl-fog.js +18 -0
  112. package/lib/shader/wgsl-fog.js.map +1 -0
  113. package/lib/shader/wgsl-helpers.js +1 -16
  114. package/lib/shader/wgsl-helpers.js.map +1 -1
  115. package/lib/sprite/billboard-scene.js +2 -0
  116. package/lib/sprite/billboard-scene.js.map +1 -1
  117. package/lib/sprite/picking/pick-billboard.js +16 -0
  118. package/lib/sprite/picking/pick-billboard.js.map +1 -0
  119. package/lib/sprite/picking/pick-sprite-2d.js +41 -0
  120. package/lib/sprite/picking/pick-sprite-2d.js.map +1 -0
  121. package/lib/sprite/shared/sprite-atlas.js +4 -1
  122. package/lib/sprite/shared/sprite-atlas.js.map +1 -1
  123. package/lib/sprite/sprite-2d.js.map +1 -1
  124. package/lib/sprite/sprite-pipeline.js +18 -1
  125. package/lib/sprite/sprite-pipeline.js.map +1 -1
  126. package/lib/sprite/sprite-renderer.js +12 -6
  127. package/lib/sprite/sprite-renderer.js.map +1 -1
  128. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"standard-template.js","sources":["../../../../src/material/standard/standard-template.ts"],"sourcesContent":["/**\n * Standard Base Template\n *\n * Provides the base Standard (Blinn-Phong) shader structure with slot markers.\n * Parameterized by feature configuration (textures, UV, shadow, reflection, fog).\n *\n * The Standard material uses 3 separate UBOs in group 1:\n * binding 0: mesh UBO (world matrix)\n * binding 1: material UBO (colors, levels)\n * Plus optional texture/sampler bindings at fixed slots.\n */\n\nimport type { ShaderTemplate, UboField, VertexAttribute, Varying, BindingDecl } from \"../../shader/fragment-types.js\";\nimport { WGSL_FOG } from \"../../shader/wgsl-helpers.js\";\nimport { MAX_LIGHTS } from \"../../light/types.js\";\nimport { appendMeshLightUboFields, meshLightIndexWGSL } from \"../../render/lights-ubo.js\";\n\nconst STAGE_VERTEX = 0x1;\nconst STAGE_FRAGMENT = 0x2;\n\n// ── Lighting function (always present unless disableLighting) ───\n\nconst LIGHTING_FN = `\nfn computeLighting(viewDir: vec3<f32>, N: vec3<f32>, L: LightEntry, g: f32, P: vec3<f32>) -> array<vec3<f32>, 2> {\nvar lv: vec3<f32>;\nvar a: f32 = 1.0;\nlet t = u32(L.vLightData.w);\nif (t == 3u) {\nlet nl = 0.5 + 0.5 * dot(N, normalize(L.vLightData.xyz));\nlet diff = mix(L.vLightDirection.xyz, L.vLightDiffuse.rgb, nl);\nlet h = normalize(viewDir + normalize(L.vLightData.xyz));\nvar s = pow(max(0.0, dot(N, h)), max(1.0, g));\nreturn array<vec3<f32>, 2>(diff, s * L.vLightSpecular.rgb);\n}\nif (t == 1u) {\nlv = normalize(-L.vLightData.xyz);\n} else {\nlet d = L.vLightData.xyz - P;\na = max(0.0, 1.0 - length(d) / L.vLightDiffuse.a);\nlv = normalize(d);\nif (t == 2u) {\nlet c = max(0.0, dot(L.vLightDirection.xyz, -lv));\nif (c >= L.vLightDirection.w) { a *= max(0.0, pow(c, L.vLightSpecular.a)); } else { a = 0.0; }\n}\n}\nlet nl = max(0.0, dot(N, lv));\nlet diff = nl * L.vLightDiffuse.rgb * a;\nlet h = normalize(viewDir + lv);\nvar s = max(0.0, dot(N, h));\ns = pow(s, max(1.0, g));\nreturn array<vec3<f32>, 2>(diff, s * L.vLightSpecular.rgb * a);\n}\n`;\n\nexport interface StandardTemplateConfig {\n /** @internal */\n readonly _diffuse?: boolean;\n /** @internal UV coordinate channels used */\n readonly _needsUV: boolean;\n /** @internal */\n readonly _needsUV2: boolean;\n /** @internal */\n readonly _diffuseUsesUV2?: boolean;\n /** @internal Disable lighting (unlit material) */\n readonly _disableLighting?: boolean;\n /** @internal Generate a fragment stage that runs discard/alpha-test logic and writes no color. */\n readonly _noColorOutput?: boolean;\n /** @internal Generate a fragment stage that runs discard/alpha-test logic and writes ESM shadow color. */\n readonly _esmShadowOutput?: boolean;\n /** @internal Has morph targets — switches the vertex shader to morphedPos/morphedNorm (defined by the morph fragment's VR slot). */\n readonly _hasMorph?: boolean;\n}\n\n/**\n * Create a Standard material ShaderTemplate from configuration.\n * The template contains slot markers that the composer fills.\n */\nexport function createStandardTemplate(config: StandardTemplateConfig, esmShadowDepthCode = \"\"): ShaderTemplate {\n const { _diffuse, _needsUV, _needsUV2, _diffuseUsesUV2, _disableLighting, _noColorOutput, _esmShadowOutput, _hasMorph } = config;\n\n // ── Base vertex attributes ──────────────────────────────────\n const _baseVertexAttributes: VertexAttribute[] = [\n { _name: \"position\", _type: \"vec3<f32>\", _gpuFormat: \"float32x3\", _arrayStride: 12 },\n { _name: \"normal\", _type: \"vec3<f32>\", _gpuFormat: \"float32x3\", _arrayStride: 12 },\n ];\n if (_needsUV) {\n _baseVertexAttributes.push({ _name: \"uv\", _type: \"vec2<f32>\", _gpuFormat: \"float32x2\", _arrayStride: 8 });\n }\n if (_needsUV2) {\n _baseVertexAttributes.push({ _name: \"uv2\", _type: \"vec2<f32>\", _gpuFormat: \"float32x2\", _arrayStride: 8 });\n }\n\n // ── Base varyings ───────────────────────────────────────────\n const _baseVaryings: Varying[] = [\n { _name: \"vp\", _type: \"vec3<f32>\" },\n { _name: \"vn\", _type: \"vec3<f32>\" },\n { _name: \"vf\", _type: \"vec3<f32>\" },\n ];\n if (_needsUV) {\n _baseVaryings.push({ _name: \"vu\", _type: \"vec2<f32>\" });\n }\n if (_needsUV2) {\n _baseVaryings.push({ _name: \"vv\", _type: \"vec2<f32>\" });\n }\n // shadow varyings (vPositionFromLight, vDepthMetric) are provided by std-shadow-fragment\n\n // ── Base UBO fields (mesh = world matrix + affected light indices) ──────────────\n const _baseMeshUboFields: UboField[] = [{ _name: \"world\", _type: \"mat4x4<f32>\" }];\n appendMeshLightUboFields(_baseMeshUboFields);\n\n // ── Base bindings (group 1, starting after mesh UBO at 0) ───\n // Order: material, diffuse*, shadow/UV*, emissive*, bump*, specular*, ambient*, lightmap*, opacity*, reflection*\n // The shadow/UV UBO is placed AFTER diffuse so its auto-assigned binding index\n // matches the conventional slot 5 when diffuse is present (bindings 3,4).\n const _baseBindings: BindingDecl[] = [{ _name: \"mat\", _type: { _kind: \"uniform-buffer\" }, _visibility: STAGE_FRAGMENT }];\n\n if (_diffuse) {\n _baseBindings.push(\n { _name: \"dT\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"dS\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n // UV params UBO — only when UVs are actually emitted.\n if (_needsUV) {\n _baseBindings.push({ _name: \"up\", _type: { _kind: \"uniform-buffer\" }, _visibility: STAGE_VERTEX });\n }\n if (_esmShadowOutput) {\n _baseBindings.push({ _name: \"shadowParams\", _type: { _kind: \"uniform-buffer\" }, _visibility: STAGE_FRAGMENT });\n }\n // bump bindings are provided by the normal-map fragment (not baseBindings)\n // emissive, specular, ambient, lightmap, opacity, reflection bindings\n // are provided by their respective fragments (not baseBindings)\n\n // Shadow map bindings (group 2) are provided by std-shadow-fragment\n\n // ── Vertex template ─────────────────────────────────────────\n\n const uvPassthrough = _needsUV ? `out.vu = uv * up.u.xy + up.u.zw;` : \"\";\n\n const uv2Passthrough = _needsUV2 ? `out.vv = uv2;` : \"\";\n\n // Vertex UBO struct definitions (must be before binding declarations)\n const vertexUboStructs = _needsUV ? `struct upUniforms { u: vec4<f32>, }` : \"\";\n\n // When morph targets are active, the morph fragment's VR slot defines\n // morphedPos/morphedNorm. The base template uses those in place of the\n // raw vertex attributes; otherwise it falls back to position/normal.\n const posVar = _hasMorph ? \"morphedPos\" : \"position\";\n const normVar = _hasMorph ? \"morphedNorm\" : \"normal\";\n\n const _vertexTemplate = `/*SU*/\n/*MU*/\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\n${vertexUboStructs}\n/*VH*/\n/*VD*/\n/*VO*/\n@vertex fn main(\n/*VP*/\n) -> VertexOutput {\nvar out: VertexOutput;\n/*VR*/\nvar finalWorld = mesh.world;\n/*VW*/\nlet worldPos4 = finalWorld * vec4<f32>(${posVar}, 1.0);\nout.vp = worldPos4.xyz;\nlet normalWorld = mat3x3<f32>(finalWorld[0].xyz, finalWorld[1].xyz, finalWorld[2].xyz);\nout.vn = normalize(normalWorld * ${normVar});\nout.clipPos = scene.viewProjection * worldPos4;\nout.vf = (scene.view * worldPos4).xyz;\n${uvPassthrough}\n${uv2Passthrough}\n/*VB*/\nreturn out;\n}`;\n\n // ── Fragment template ────────────────────────────────────────\n\n const lightsStructs = `\nstruct LightEntry { vLightData: vec4<f32>, vLightDiffuse: vec4<f32>, vLightSpecular: vec4<f32>, vLightDirection: vec4<f32> };\nstruct lightsUniforms { count: u32, _p0: u32, _p1: u32, _p2: u32, lights: array<LightEntry, ${MAX_LIGHTS}> };\n@group(0) @binding(1) var<uniform> lights: lightsUniforms;\n`;\n\n const materialStruct = `\nstruct matUniforms {\ndc: vec4<f32>,\nsc: vec4<f32>,\nec: vec3<f32>,\nbs: f32,\nac: vec3<f32>,\ntl: f32,\nambTexLvl: f32,\nlmLvl: f32,\nopLvl: f32,\naCut: f32,\nrLvl: f32,\nrCm: f32,\n_0: f32,\n_1: f32,\n};\n`;\n\n const helpers = _disableLighting ? WGSL_FOG : WGSL_FOG + LIGHTING_FN;\n // reflection, shadow, bump helpers are provided by their respective fragments\n\n // Main fragment body — mirrors old composeFragmentShader exactly\n const doubleSidedEntry = `@fragment fn main(input: FragmentInput)${_noColorOutput ? \"\" : \" -> @location(0) vec4<f32>\"} {`;\n\n // View direction\n const viewDirCode = !_disableLighting ? `let viewDirectionW = normalize(scene.vEyePosition.xyz - input.vp);` : \"\";\n\n // Normal computation — fragment can override via AC slot\n const normalCode = _disableLighting ? \"\" : `var normalW = normalize(input.vn);`;\n\n // Opacity — default from material alpha, fragment can modify via AT\n const opacityCode = `var alpha = mat.dc.a;`;\n\n // Base color + alpha test. Texture alpha used for discard only (not blended into output alpha),\n // matching BJS ALPHATEST without ALPHAFROMDIFFUSE.\n const baseColorCode = _diffuse\n ? `let _ds = textureSample(dT, dS, ${_diffuseUsesUV2 ? \"input.vv\" : \"input.vu\"});\nif (_ds.a < mat.aCut) { discard; }\nvar baseColor = _ds.rgb * mat.tl;`\n : `var baseColor = vec3<f32>(1.0, 1.0, 1.0);`;\n\n // Diffuse color + emissive + specular — defaults, fragments can override via AT\n const diffuseColorCode = `let diffuseColor = mat.dc.rgb;`;\n const emissiveCode = `var emissiveContrib = mat.ec;`;\n const specularColorCode = !_disableLighting ? `var specularColor = mat.sc.rgb;` : \"\";\n // Lighting block (only when lighting enabled)\n let lightingBlock: string;\n if (!_disableLighting) {\n // Shadow — default to 1.0, fragment overrides via AD slot\n // shadowFactors array is populated by std-shadow-fragment (one per light index)\n lightingBlock = `var glossiness = mat.sc.a;\nvar diffuseBase = vec3<f32>(0.0);\nvar specularBase = vec3<f32>(0.0);\nvar shadowFactors = array<f32, ${MAX_LIGHTS}>(${new Array(MAX_LIGHTS).fill(\"1.0\").join(\", \")});\nvar baseAmbientColor = vec3<f32>(1.0, 1.0, 1.0);\nvar reflectionColor = vec3<f32>(0.0);\nlet lc = min(mesh.lc, ${MAX_LIGHTS}u);\n/*AD*/\nfor (var li = 0u; li < lc; li++) {\nlet lightIndex = mli(li);\nlet r = computeLighting(viewDirectionW, normalW, lights.lights[lightIndex], glossiness, input.vp);\nlet sf = shadowFactors[lightIndex];\ndiffuseBase += r[0] * sf;\nspecularBase += r[1] * sf;\n}\nlet finalDiffuse = clamp(diffuseBase * diffuseColor + emissiveContrib + mat.ac, vec3<f32>(0.0), vec3<f32>(1.0)) * baseColor;\nlet finalSpecular = specularBase * specularColor;\nvar color = vec4<f32>(finalDiffuse * baseAmbientColor + finalSpecular + reflectionColor, alpha);`;\n } else {\n lightingBlock = `var color = vec4<f32>(clamp(emissiveContrib * diffuseColor, vec3<f32>(0.0), vec3<f32>(1.0)) * baseColor, alpha);`;\n }\n\n // For a color-less pass (depth/shadow only) emit only the early `return;` after the alpha-test slot;\n // the lighting + color tail below would be unreachable dead code (WGSL \"code is unreachable\"). The\n // color path is byte-identical to the previous template, so pixel output is unchanged.\n const _fragmentTemplate = `/*SU*/\n${lightsStructs}\n${materialStruct}\n${_esmShadowOutput ? \"struct shadowParamsUniforms { biasAndScale: vec4<f32>, depthValues: vec4<f32>, }\" : \"\"}\n/*MU*/\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\n${!_disableLighting ? meshLightIndexWGSL(\"mesh\") : \"\"}\n${helpers}\n/*HF*/\n/*FB*/\n/*FI*/\n${doubleSidedEntry}\n/*SV*/\n${viewDirCode}\n${normalCode}\n/*AC*/\n${opacityCode}\n${baseColorCode}\n${diffuseColorCode}\n${emissiveCode}\n${specularColorCode}\n/*AT*/\n${\n _noColorOutput\n ? \"return;\"\n : `${_esmShadowOutput ? esmShadowDepthCode : \"\"}\n${lightingBlock}\n/*BC*/\ncolor = vec4<f32>(max(color.rgb, vec3<f32>(0.0)), color.a);\nif (scene.vFogInfos.x > 0.0) {\nlet fog = calcFogFactor(input.vf);\ncolor = vec4<f32>(mix(scene.vFogColor.rgb, color.rgb, fog), color.a);\n}\n/*BA*/\nreturn color;`\n}\n}`;\n\n return {\n _vertexTemplate,\n _fragmentTemplate,\n _baseMeshUboFields,\n _baseVertexAttributes,\n _baseVaryings,\n _baseBindings,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"standard-template.js","sources":["../../../../src/material/standard/standard-template.ts"],"sourcesContent":["/**\n * Standard Base Template\n *\n * Provides the base Standard (Blinn-Phong) shader structure with slot markers.\n * Parameterized by feature configuration (textures, UV, shadow, reflection, fog).\n *\n * The Standard material uses 3 separate UBOs in group 1:\n * binding 0: mesh UBO (world matrix)\n * binding 1: material UBO (colors, levels)\n * Plus optional texture/sampler bindings at fixed slots.\n */\n\nimport type { ShaderTemplate, UboField, VertexAttribute, Varying, BindingDecl } from \"../../shader/fragment-types.js\";\nimport { WGSL_FOG } from \"../../shader/wgsl-fog.js\";\nimport { MAX_LIGHTS } from \"../../light/types.js\";\nimport { appendMeshLightUboFields, meshLightIndexWGSL } from \"../../render/lights-ubo.js\";\n\nconst STAGE_VERTEX = 0x1;\nconst STAGE_FRAGMENT = 0x2;\n\n// ── Lighting function (always present unless disableLighting) ───\n\nconst LIGHTING_FN = `\nfn computeLighting(viewDir: vec3<f32>, N: vec3<f32>, L: LightEntry, g: f32, P: vec3<f32>) -> array<vec3<f32>, 2> {\nvar lv: vec3<f32>;\nvar a: f32 = 1.0;\nlet t = u32(L.vLightData.w);\nif (t == 3u) {\nlet nl = 0.5 + 0.5 * dot(N, normalize(L.vLightData.xyz));\nlet diff = mix(L.vLightDirection.xyz, L.vLightDiffuse.rgb, nl);\nlet h = normalize(viewDir + normalize(L.vLightData.xyz));\nvar s = pow(max(0.0, dot(N, h)), max(1.0, g));\nreturn array<vec3<f32>, 2>(diff, s * L.vLightSpecular.rgb);\n}\nif (t == 1u) {\nlv = normalize(-L.vLightData.xyz);\n} else {\nlet d = L.vLightData.xyz - P;\na = max(0.0, 1.0 - length(d) / L.vLightDiffuse.a);\nlv = normalize(d);\nif (t == 2u) {\nlet c = max(0.0, dot(L.vLightDirection.xyz, -lv));\nif (c >= L.vLightDirection.w) { a *= max(0.0, pow(c, L.vLightSpecular.a)); } else { a = 0.0; }\n}\n}\nlet nl = max(0.0, dot(N, lv));\nlet diff = nl * L.vLightDiffuse.rgb * a;\nlet h = normalize(viewDir + lv);\nvar s = max(0.0, dot(N, h));\ns = pow(s, max(1.0, g));\nreturn array<vec3<f32>, 2>(diff, s * L.vLightSpecular.rgb * a);\n}\n`;\n\nexport interface StandardTemplateConfig {\n /** @internal */\n readonly _diffuse?: boolean;\n /** @internal UV coordinate channels used */\n readonly _needsUV: boolean;\n /** @internal */\n readonly _needsUV2: boolean;\n /** @internal */\n readonly _diffuseUsesUV2?: boolean;\n /** @internal Disable lighting (unlit material) */\n readonly _disableLighting?: boolean;\n /** @internal Generate a fragment stage that runs discard/alpha-test logic and writes no color. */\n readonly _noColorOutput?: boolean;\n /** @internal Generate a fragment stage that runs discard/alpha-test logic and writes ESM shadow color. */\n readonly _esmShadowOutput?: boolean;\n /** @internal Has morph targets — switches the vertex shader to morphedPos/morphedNorm (defined by the morph fragment's VR slot). */\n readonly _hasMorph?: boolean;\n}\n\n/**\n * Create a Standard material ShaderTemplate from configuration.\n * The template contains slot markers that the composer fills.\n */\nexport function createStandardTemplate(config: StandardTemplateConfig, esmShadowDepthCode = \"\"): ShaderTemplate {\n const { _diffuse, _needsUV, _needsUV2, _diffuseUsesUV2, _disableLighting, _noColorOutput, _esmShadowOutput, _hasMorph } = config;\n\n // ── Base vertex attributes ──────────────────────────────────\n const _baseVertexAttributes: VertexAttribute[] = [\n { _name: \"position\", _type: \"vec3<f32>\", _gpuFormat: \"float32x3\", _arrayStride: 12 },\n { _name: \"normal\", _type: \"vec3<f32>\", _gpuFormat: \"float32x3\", _arrayStride: 12 },\n ];\n if (_needsUV) {\n _baseVertexAttributes.push({ _name: \"uv\", _type: \"vec2<f32>\", _gpuFormat: \"float32x2\", _arrayStride: 8 });\n }\n if (_needsUV2) {\n _baseVertexAttributes.push({ _name: \"uv2\", _type: \"vec2<f32>\", _gpuFormat: \"float32x2\", _arrayStride: 8 });\n }\n\n // ── Base varyings ───────────────────────────────────────────\n const _baseVaryings: Varying[] = [\n { _name: \"vp\", _type: \"vec3<f32>\" },\n { _name: \"vn\", _type: \"vec3<f32>\" },\n { _name: \"vf\", _type: \"vec3<f32>\" },\n ];\n if (_needsUV) {\n _baseVaryings.push({ _name: \"vu\", _type: \"vec2<f32>\" });\n }\n if (_needsUV2) {\n _baseVaryings.push({ _name: \"vv\", _type: \"vec2<f32>\" });\n }\n // shadow varyings (vPositionFromLight, vDepthMetric) are provided by std-shadow-fragment\n\n // ── Base UBO fields (mesh = world matrix + affected light indices) ──────────────\n const _baseMeshUboFields: UboField[] = [{ _name: \"world\", _type: \"mat4x4<f32>\" }];\n appendMeshLightUboFields(_baseMeshUboFields);\n\n // ── Base bindings (group 1, starting after mesh UBO at 0) ───\n // Order: material, diffuse*, shadow/UV*, emissive*, bump*, specular*, ambient*, lightmap*, opacity*, reflection*\n // The shadow/UV UBO is placed AFTER diffuse so its auto-assigned binding index\n // matches the conventional slot 5 when diffuse is present (bindings 3,4).\n const _baseBindings: BindingDecl[] = [{ _name: \"mat\", _type: { _kind: \"uniform-buffer\" }, _visibility: STAGE_FRAGMENT }];\n\n if (_diffuse) {\n _baseBindings.push(\n { _name: \"dT\", _type: { _kind: \"texture\", _textureType: \"texture_2d<f32>\" }, _visibility: STAGE_FRAGMENT },\n { _name: \"dS\", _type: { _kind: \"sampler\", _samplerType: \"sampler\" }, _visibility: STAGE_FRAGMENT }\n );\n }\n // UV params UBO — only when UVs are actually emitted.\n if (_needsUV) {\n _baseBindings.push({ _name: \"up\", _type: { _kind: \"uniform-buffer\" }, _visibility: STAGE_VERTEX });\n }\n if (_esmShadowOutput) {\n _baseBindings.push({ _name: \"shadowParams\", _type: { _kind: \"uniform-buffer\" }, _visibility: STAGE_FRAGMENT });\n }\n // bump bindings are provided by the normal-map fragment (not baseBindings)\n // emissive, specular, ambient, lightmap, opacity, reflection bindings\n // are provided by their respective fragments (not baseBindings)\n\n // Shadow map bindings (group 2) are provided by std-shadow-fragment\n\n // ── Vertex template ─────────────────────────────────────────\n\n const uvPassthrough = _needsUV ? `out.vu = uv * up.u.xy + up.u.zw;` : \"\";\n\n const uv2Passthrough = _needsUV2 ? `out.vv = uv2;` : \"\";\n\n // Vertex UBO struct definitions (must be before binding declarations)\n const vertexUboStructs = _needsUV ? `struct upUniforms { u: vec4<f32>, }` : \"\";\n\n // When morph targets are active, the morph fragment's VR slot defines\n // morphedPos/morphedNorm. The base template uses those in place of the\n // raw vertex attributes; otherwise it falls back to position/normal.\n const posVar = _hasMorph ? \"morphedPos\" : \"position\";\n const normVar = _hasMorph ? \"morphedNorm\" : \"normal\";\n\n const _vertexTemplate = `/*SU*/\n/*MU*/\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\n${vertexUboStructs}\n/*VH*/\n/*VD*/\n/*VO*/\n@vertex fn main(\n/*VP*/\n) -> VertexOutput {\nvar out: VertexOutput;\n/*VR*/\nvar finalWorld = mesh.world;\n/*VW*/\nlet worldPos4 = finalWorld * vec4<f32>(${posVar}, 1.0);\nout.vp = worldPos4.xyz;\nlet normalWorld = mat3x3<f32>(finalWorld[0].xyz, finalWorld[1].xyz, finalWorld[2].xyz);\nout.vn = normalize(normalWorld * ${normVar});\nout.clipPos = scene.viewProjection * worldPos4;\nout.vf = (scene.view * worldPos4).xyz;\n${uvPassthrough}\n${uv2Passthrough}\n/*VB*/\nreturn out;\n}`;\n\n // ── Fragment template ────────────────────────────────────────\n\n const lightsStructs = `\nstruct LightEntry { vLightData: vec4<f32>, vLightDiffuse: vec4<f32>, vLightSpecular: vec4<f32>, vLightDirection: vec4<f32> };\nstruct lightsUniforms { count: u32, _p0: u32, _p1: u32, _p2: u32, lights: array<LightEntry, ${MAX_LIGHTS}> };\n@group(0) @binding(1) var<uniform> lights: lightsUniforms;\n`;\n\n const materialStruct = `\nstruct matUniforms {\ndc: vec4<f32>,\nsc: vec4<f32>,\nec: vec3<f32>,\nbs: f32,\nac: vec3<f32>,\ntl: f32,\nambTexLvl: f32,\nlmLvl: f32,\nopLvl: f32,\naCut: f32,\nrLvl: f32,\nrCm: f32,\n_0: f32,\n_1: f32,\n};\n`;\n\n const helpers = _disableLighting ? WGSL_FOG : WGSL_FOG + LIGHTING_FN;\n // reflection, shadow, bump helpers are provided by their respective fragments\n\n // Main fragment body — mirrors old composeFragmentShader exactly\n const doubleSidedEntry = `@fragment fn main(input: FragmentInput)${_noColorOutput ? \"\" : \" -> @location(0) vec4<f32>\"} {`;\n\n // View direction\n const viewDirCode = !_disableLighting ? `let viewDirectionW = normalize(scene.vEyePosition.xyz - input.vp);` : \"\";\n\n // Normal computation — fragment can override via AC slot\n const normalCode = _disableLighting ? \"\" : `var normalW = normalize(input.vn);`;\n\n // Opacity — default from material alpha, fragment can modify via AT\n const opacityCode = `var alpha = mat.dc.a;`;\n\n // Base color + alpha test. Texture alpha used for discard only (not blended into output alpha),\n // matching BJS ALPHATEST without ALPHAFROMDIFFUSE.\n const baseColorCode = _diffuse\n ? `let _ds = textureSample(dT, dS, ${_diffuseUsesUV2 ? \"input.vv\" : \"input.vu\"});\nif (_ds.a < mat.aCut) { discard; }\nvar baseColor = _ds.rgb * mat.tl;`\n : `var baseColor = vec3<f32>(1.0, 1.0, 1.0);`;\n\n // Diffuse color + emissive + specular — defaults, fragments can override via AT\n const diffuseColorCode = `let diffuseColor = mat.dc.rgb;`;\n const emissiveCode = `var emissiveContrib = mat.ec;`;\n const specularColorCode = !_disableLighting ? `var specularColor = mat.sc.rgb;` : \"\";\n // Lighting block (only when lighting enabled)\n let lightingBlock: string;\n if (!_disableLighting) {\n // Shadow — default to 1.0, fragment overrides via AD slot\n // shadowFactors array is populated by std-shadow-fragment (one per light index)\n lightingBlock = `var glossiness = mat.sc.a;\nvar diffuseBase = vec3<f32>(0.0);\nvar specularBase = vec3<f32>(0.0);\nvar shadowFactors = array<f32, ${MAX_LIGHTS}>(${new Array(MAX_LIGHTS).fill(\"1.0\").join(\", \")});\nvar baseAmbientColor = vec3<f32>(1.0, 1.0, 1.0);\nvar reflectionColor = vec3<f32>(0.0);\nlet lc = min(mesh.lc, ${MAX_LIGHTS}u);\n/*AD*/\nfor (var li = 0u; li < lc; li++) {\nlet lightIndex = mli(li);\nlet r = computeLighting(viewDirectionW, normalW, lights.lights[lightIndex], glossiness, input.vp);\nlet sf = shadowFactors[lightIndex];\ndiffuseBase += r[0] * sf;\nspecularBase += r[1] * sf;\n}\nlet finalDiffuse = clamp(diffuseBase * diffuseColor + emissiveContrib + mat.ac, vec3<f32>(0.0), vec3<f32>(1.0)) * baseColor;\nlet finalSpecular = specularBase * specularColor;\nvar color = vec4<f32>(finalDiffuse * baseAmbientColor + finalSpecular + reflectionColor, alpha);`;\n } else {\n lightingBlock = `var color = vec4<f32>(clamp(emissiveContrib * diffuseColor, vec3<f32>(0.0), vec3<f32>(1.0)) * baseColor, alpha);`;\n }\n\n // For a color-less pass (depth/shadow only) emit only the early `return;` after the alpha-test slot;\n // the lighting + color tail below would be unreachable dead code (WGSL \"code is unreachable\"). The\n // color path is byte-identical to the previous template, so pixel output is unchanged.\n const _fragmentTemplate = `/*SU*/\n${lightsStructs}\n${materialStruct}\n${_esmShadowOutput ? \"struct shadowParamsUniforms { biasAndScale: vec4<f32>, depthValues: vec4<f32>, }\" : \"\"}\n/*MU*/\n@group(1) @binding(0) var<uniform> mesh: MeshUniforms;\n${!_disableLighting ? meshLightIndexWGSL(\"mesh\") : \"\"}\n${helpers}\n/*HF*/\n/*FB*/\n/*FI*/\n${doubleSidedEntry}\n/*SV*/\n${viewDirCode}\n${normalCode}\n/*AC*/\n${opacityCode}\n${baseColorCode}\n${diffuseColorCode}\n${emissiveCode}\n${specularColorCode}\n/*AT*/\n${\n _noColorOutput\n ? \"return;\"\n : `${_esmShadowOutput ? esmShadowDepthCode : \"\"}\n${lightingBlock}\n/*BC*/\ncolor = vec4<f32>(max(color.rgb, vec3<f32>(0.0)), color.a);\nif (scene.vFogInfos.x > 0.0) {\nlet fog = calcFogFactor(input.vf);\ncolor = vec4<f32>(mix(scene.vFogColor.rgb, color.rgb, fog), color.a);\n}\n/*BA*/\nreturn color;`\n}\n}`;\n\n return {\n _vertexTemplate,\n _fragmentTemplate,\n _baseMeshUboFields,\n _baseVertexAttributes,\n _baseVaryings,\n _baseBindings,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import { getViewMatrix, getProjectionMatrix, getCameraPosition } from '../../cam
5
5
  import { getSceneBindGroupLayout } from '../../render/scene-helpers.js';
6
6
  import { getRenderTargetSize } from '../../engine/engine.js';
7
7
  import { disposeGaussianSplattingMesh } from './gaussian-splatting-mesh.js';
8
+ import { registerPickSource } from '../../picking/pick-contributor.js';
8
9
  import { applyGsFragments } from './gaussian-splatting-pipeline.js';
9
10
 
10
11
  const SH_TEXTURE_COUNT = [0, 1, 2, 3, 5];
@@ -492,12 +493,9 @@ function attachGaussianSplattingMeshSH(scene, mesh, shFlat, fragments) {
492
493
  mesh._gs._shViews = views;
493
494
  const ctx = scene;
494
495
  ctx._renderables.push(buildGaussianSplattingRenderableSH(scene, mesh, fragments));
495
- ctx._gsMeshes.push(mesh);
496
+ const unregisterPick = registerPickSource(scene, mesh, () => import('../../picking/gs-picking-pipeline.js'));
496
497
  ctx._disposables.push(() => {
497
- const i = ctx._gsMeshes.indexOf(mesh);
498
- if (i >= 0) {
499
- ctx._gsMeshes.splice(i, 1);
500
- }
498
+ unregisterPick();
501
499
  disposeGaussianSplattingMesh(mesh);
502
500
  });
503
501
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gaussian-splatting-pipeline-sh.js","sources":["../../../../src/mesh/GaussianSplatting/gaussian-splatting-pipeline-sh.ts"],"sourcesContent":["/** Gaussian-Splatting SH render pipeline + Renderable.\n *\n * Variant of `gaussian-splatting-pipeline.ts` that adds view-dependent SH\n * shading. Loaded *only* by `loadSplat` (and the SOG / SPZ loaders) via a\n * dynamic `import(...)` when the parsed splat asset includes SH coefficients\n * (`mesh.shDegree > 0`), so plain `.ply` / `.splat` scenes (e.g. scene 120)\n * never pull this module's WGSL or runtime cost into their bundle.\n *\n * WGSL source is generated per-shDegree by `buildShShaderSource`: SH textures,\n * byte-to-vec3 unpacking, and the polynomial evaluation in\n * `computeColorFromSHDegree` all expand to the right size — mirrors the\n * `#if SH_DEGREE > N` blocks in BJS `gaussianSplatting.fx`. Pipeline cache is\n * keyed by `(targetSignatureKey, shDegree)`.\n *\n * The UBO grows by 16 bytes vs the base pipeline to carry `eyePosition`\n * (world-space camera position; see `computeSH(dir)` below).\n *\n * ── Why the Y-flip on the SH direction? ─────────────────────────────────\n * BJS sets `mesh.scaling.y *= -1` to fix coordinate-system handedness; Lite\n * pre-flips Y in `splat-data.ts` at parse time so the runtime mesh transform\n * is identity. World-space splat positions agree across both engines, but\n * the BJS world rotation absorbs an extra `diag(1,-1,1)` factor — i.e.\n * worldRot_bjs = worldRot_user · diag(1,-1,1)\n * which means\n * inverse(worldRot_bjs) · v = diag(1,-1,1) · inverse(worldRot_user) · v\n * so Lite reproduces the BJS SH direction by computing\n * `inverseMat3(worldRot) · (worldPos − eye)` and then negating `.y`. */\n\nimport { F32, U8 } from \"../../engine/typed-arrays.js\";\nimport { TU, BU, SS, CW } from \"../../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene-core.js\";\nimport type { Renderable, DrawBinding } from \"../../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport { getViewMatrix, getProjectionMatrix, getCameraPosition } from \"../../camera/camera.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { getRenderTargetSize } from \"../../engine/engine.js\";\nimport { disposeGaussianSplattingMesh, type GaussianSplattingMesh, type GsShaderFragment } from \"./gaussian-splatting-mesh.js\";\nimport { applyGsFragments } from \"./gaussian-splatting-pipeline.js\";\n\ninterface PipelineEntry {\n pipeline: GPURenderPipeline;\n meshBindGroupLayout: GPUBindGroupLayout;\n shTextureCount: number;\n}\n\n// shDegree → number of rgba32uint SH textures: 1→1, 2→2, 3→3, 4→5.\nconst SH_TEXTURE_COUNT = [0, 1, 2, 3, 5];\n\nlet _cache: { device: GPUDevice; modules: Map<string, GPUShaderModule>; entries: Map<string, PipelineEntry> } | null = null;\n\n/** Build the WGSL source for a given SH degree (1..4). Mirrors the BJS\n * preprocessor-driven shader structure: declares only the SH textures used\n * by the degree, emits exactly the byte-stream unpacking for that degree,\n * and inlines only the SH polynomial terms up to that degree. */\nfunction buildShShaderSource(shDegree: number): string {\n const shVectorCount = (shDegree + 1) * (shDegree + 1) - 1;\n const shCoefficientCount = shVectorCount * 3;\n const textureCount = Math.ceil(shCoefficientCount / 16);\n\n // ── SH texture bindings (6, 7, …) ───────────────────────────────\n let textureBindings = \"\";\n for (let i = 0; i < textureCount; i++) {\n textureBindings += `@group(1) @binding(${6 + i}) var shTexture${i}: texture_2d<u32>;\\n`;\n }\n\n // ── textureLoad calls inside readSplat ──────────────────────────\n let textureLoads = \"\";\n for (let i = 0; i < textureCount; i++) {\n textureLoads += ` let sh${i}_u32 = textureLoad(shTexture${i}, splatUVi32, 0);\\n`;\n }\n\n // ── Unpack the byte stream into sh[1..shVectorCount] vec3 values.\n //\n // Each rgba32uint texel carries 16 bytes (4 u32s × 4 bytes). The bytes\n // are stored in BJS-coefficient order: byte j of splat i is the j-th\n // component of the [R0,G0,B0, R1,G1,B1, …, R(N-1),G(N-1),B(N-1)] sequence.\n // sh[k+1] (k = 0..shVectorCount-1) reads bytes [3k, 3k+1, 3k+2]. `decompose`\n // returns `(byte * 2/255) - 1`, matching BJS exactly.\n let shUnpack = ` var sh: array<vec3<f32>, ${shVectorCount + 1}>;\\n sh[0] = vec3<f32>(0.0);\\n`;\n const byteRef = (j: number): string => {\n // texture index, u32 index within texel (0..3), byte index within u32 (0..3 == x/y/z/w).\n const tex = (j / 16) | 0;\n const u32Idx = ((j % 16) / 4) | 0;\n const byteIdx = j % 4;\n const u32Field = [\"x\", \"y\", \"z\", \"w\"][u32Idx]!;\n const byteField = [\"x\", \"y\", \"z\", \"w\"][byteIdx]!;\n return `decompose(sh${tex}_u32.${u32Field}).${byteField}`;\n };\n for (let k = 0; k < shVectorCount; k++) {\n const j = k * 3;\n shUnpack += ` sh[${k + 1}] = vec3<f32>(${byteRef(j)}, ${byteRef(j + 1)}, ${byteRef(j + 2)});\\n`;\n }\n\n // ── Polynomial evaluation, conditional on shDegree ──────────────\n let shPoly = \" result = sh[0];\\n\";\n if (shDegree >= 1) {\n shPoly += ` result += -SH_C1 * y * sh[1] + SH_C1 * z * sh[2] - SH_C1 * x * sh[3];\\n`;\n }\n if (shDegree >= 2) {\n shPoly += ` result +=\\n SH_C2[0] * xy * sh[4] +\\n SH_C2[1] * yz * sh[5] +\\n SH_C2[2] * (2.0 * zz - xx - yy) * sh[6] +\\n SH_C2[3] * xz * sh[7] +\\n SH_C2[4] * (xx - yy) * sh[8];\\n`;\n }\n if (shDegree >= 3) {\n shPoly += ` result +=\\n SH_C3[0] * y * (3.0 * xx - yy) * sh[9] +\\n SH_C3[1] * xy * z * sh[10] +\\n SH_C3[2] * y * (4.0 * zz - xx - yy) * sh[11] +\\n SH_C3[3] * z * (2.0 * zz - 3.0 * xx - 3.0 * yy) * sh[12] +\\n SH_C3[4] * x * (4.0 * zz - xx - yy) * sh[13] +\\n SH_C3[5] * z * (xx - yy) * sh[14] +\\n SH_C3[6] * x * (xx - 3.0 * yy) * sh[15];\\n`;\n }\n if (shDegree >= 4) {\n shPoly += ` result +=\\n SH_C4[0] * x * y * (xx - yy) * sh[16] +\\n SH_C4[1] * y * z * (3.0 * xx - yy) * sh[17] +\\n SH_C4[2] * x * y * (7.0 * zz - 1.0) * sh[18] +\\n SH_C4[3] * y * z * (7.0 * zz - 3.0) * sh[19] +\\n SH_C4[4] * (zz * (35.0 * zz - 30.0) + 3.0) * sh[20] +\\n SH_C4[5] * x * z * (7.0 * zz - 3.0) * sh[21] +\\n SH_C4[6] * (xx - yy) * (7.0 * zz - 1.0) * sh[22] +\\n SH_C4[7] * x * z * (xx - 3.0 * yy) * sh[23] +\\n SH_C4[8] * (xx * (xx - 3.0 * yy) - yy * (3.0 * xx - yy)) * sh[24];\\n`;\n }\n\n // SH_C2..SH_C4 constants — only declare what's referenced (silences\n // WGSL \"unused array\" warnings on lower degrees).\n let constantsBlock = `const SH_C1: f32 = 0.48860251;\\n`;\n if (shDegree >= 2) {\n constantsBlock += `const SH_C2: array<f32, 5> = array<f32, 5>(1.092548430, -1.09254843, 0.315391565, -1.09254843, 0.546274215);\\n`;\n }\n if (shDegree >= 3) {\n constantsBlock += `const SH_C3: array<f32, 7> = array<f32, 7>(-0.59004358, 2.890611442, -0.45704579, 0.373176332, -0.45704579, 1.445305721, -0.59004358);\\n`;\n }\n if (shDegree >= 4) {\n constantsBlock += `const SH_C4: array<f32, 9> = array<f32, 9>(2.5033429418, -1.7701307698, 0.9461746958, -0.6690465436, 0.1057855469, -0.6690465436, 0.4730873479, -1.7701307698, 0.6258357354);\\n`;\n }\n\n return `// Gaussian Splatting — vertex + fragment WGSL (SH degree ${shDegree}).\n// Generated by buildShShaderSource. Mirrors BJS gaussianSplatting.vertex.fx +\n// gaussianSplatting.fx (SH_DEGREE = ${shDegree}, no compound parts).\nstruct U {\n world: mat4x4<f32>,\n view: mat4x4<f32>,\n projection: mat4x4<f32>,\n viewport: vec2<f32>,\n focal: vec2<f32>,\n dataSize: vec2<f32>,\n alpha: f32,\n _pad0: f32,\n eyePosition: vec3<f32>,\n _pad1: f32,\n};\n@group(1) @binding(0) var<uniform> u: U;\n@group(1) @binding(1) var samp: sampler;\n@group(1) @binding(2) var centersTex: texture_2d<f32>;\n@group(1) @binding(3) var covATex: texture_2d<f32>;\n@group(1) @binding(4) var covBTex: texture_2d<f32>;\n@group(1) @binding(5) var colorsTex: texture_2d<f32>;\n${textureBindings}\n\nstruct VOut {\n @builtin(position) pos: vec4<f32>,\n @location(0) vColor: vec4<f32>,\n @location(1) vPos: vec2<f32>,\n};\n\n${constantsBlock}\n\nfn dataUv(idx: f32) -> vec2<f32> {\n let y = floor(idx / u.dataSize.x);\n let x = idx - y * u.dataSize.x;\n return vec2<f32>((x + 0.5) / u.dataSize.x, (y + 0.5) / u.dataSize.y);\n}\n\nfn dataUvI(idx: f32) -> vec2<i32> {\n let y = floor(idx / u.dataSize.x);\n let x = idx - y * u.dataSize.x;\n return vec2<i32>(i32(x), i32(y));\n}\n\n// Unpack a u32 of 4 packed bytes into (b0 b1 b2 b3) * 2/255 - 1.\nfn decompose(value: u32) -> vec4<f32> {\n let v = vec4<f32>(\n f32((value >> 0u) & 255u),\n f32((value >> 8u) & 255u),\n f32((value >> 16u) & 255u),\n f32((value >> 24u) & 255u));\n return v * vec4<f32>(2.0 / 255.0) - vec4<f32>(1.0);\n}\n\nfn inverseMat3(m: mat3x3<f32>) -> mat3x3<f32> {\n let a00 = m[0][0]; let a01 = m[0][1]; let a02 = m[0][2];\n let a10 = m[1][0]; let a11 = m[1][1]; let a12 = m[1][2];\n let a20 = m[2][0]; let a21 = m[2][1]; let a22 = m[2][2];\n let b01 = a22 * a11 - a12 * a21;\n let b11 = -a22 * a10 + a12 * a20;\n let b21 = a21 * a10 - a11 * a20;\n let det = a00 * b01 + a01 * b11 + a02 * b21;\n return mat3x3<f32>(\n vec3<f32>(b01 / det, (-a22 * a01 + a02 * a21) / det, (a12 * a01 - a02 * a11) / det),\n vec3<f32>(b11 / det, (a22 * a00 - a02 * a20) / det, (-a12 * a00 + a02 * a10) / det),\n vec3<f32>(b21 / det, (-a21 * a00 + a01 * a20) / det, (a11 * a00 - a01 * a10) / det));\n}\n\nfn computeSH(dir: vec3<f32>, splatUVi32: vec2<i32>) -> vec3<f32> {\n${textureLoads}${shUnpack} let x = dir.x;\n let y = dir.y;\n let z = dir.z;\n let xx = x * x; let yy = y * y; let zz = z * z;\n let xy = x * y; let yz = y * z; let xz = x * z;\n var result: vec3<f32>;\n${shPoly} return result;\n}\n\n@vertex\nfn vs(@location(0) corner: vec2<f32>, @location(1) splatIndex: f32) -> VOut {\n var out: VOut;\n let uv = dataUv(splatIndex);\n let splatUVi32 = dataUvI(splatIndex);\n let center = textureSampleLevel(centersTex, samp, uv, 0.0).xyz;\n let color = textureSampleLevel(colorsTex, samp, uv, 0.0);\n let covA = textureSampleLevel(covATex, samp, uv, 0.0).xyz;\n let covB = textureSampleLevel(covBTex, samp, uv, 0.0).xyz;\n\n let worldPos = u.world * vec4<f32>(center, 1.0);\n let modelView = u.view * u.world;\n let camspace = u.view * worldPos;\n let pos2d = u.projection * camspace;\n\n let bounds = 1.2 * pos2d.w;\n if (pos2d.z < 0.0\n || pos2d.x < -bounds || pos2d.x > bounds\n || pos2d.y < -bounds || pos2d.y > bounds) {\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\n out.vColor = vec4<f32>(0.0);\n out.vPos = vec2<f32>(0.0);\n return out;\n }\n\n // ── View-dependent SH evaluation ───────────────────────────────────\n let worldRot = mat3x3<f32>(u.world[0].xyz, u.world[1].xyz, u.world[2].xyz);\n let normWorldRot = inverseMat3(worldRot);\n var dir = normalize(normWorldRot * (worldPos.xyz - u.eyePosition));\n // Lite-side Y-flip: compensates for our data-path Y pre-flip vs BJS's\n // mesh.scaling.y *= -1 (see file header for derivation).\n dir.y = -dir.y;\n let shColor = computeSH(dir, splatUVi32);\n\n let Vrk = mat3x3<f32>(\n vec3<f32>(covA.x, covA.y, covA.z),\n vec3<f32>(covA.y, covB.x, covB.y),\n vec3<f32>(covA.z, covB.y, covB.z));\n\n let invZ = 1.0 / camspace.z;\n let invZ2 = invZ * invZ;\n let J = mat3x3<f32>(\n vec3<f32>(u.focal.x * invZ, 0.0, -u.focal.x * camspace.x * invZ2),\n vec3<f32>(0.0, u.focal.y * invZ, -u.focal.y * camspace.y * invZ2),\n vec3<f32>(0.0, 0.0, 0.0));\n\n let mv3 = mat3x3<f32>(modelView[0].xyz, modelView[1].xyz, modelView[2].xyz);\n let T = transpose(mv3) * J;\n var cov2d = transpose(T) * Vrk * T;\n\n let kernelSize: f32 = 0.3;\n cov2d[0][0] += kernelSize;\n cov2d[1][1] += kernelSize;\n\n let mid = (cov2d[0][0] + cov2d[1][1]) * 0.5;\n let dxy = (cov2d[0][0] - cov2d[1][1]) * 0.5;\n let radius = length(vec2<f32>(dxy, cov2d[0][1]));\n let epsilon: f32 = 0.0001;\n let lambda1 = mid + radius + epsilon;\n let lambda2 = mid - radius + epsilon;\n if (lambda2 < 0.0) {\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\n out.vColor = vec4<f32>(0.0);\n out.vPos = vec2<f32>(0.0);\n return out;\n }\n\n let diag = normalize(vec2<f32>(cov2d[0][1], lambda1 - cov2d[0][0]));\n let majorAxis = min(sqrt(2.0 * lambda1), 1024.0) * diag;\n let minorAxis = min(sqrt(2.0 * lambda2), 1024.0) * vec2<f32>(diag.y, -diag.x);\n\n let vCenter = pos2d.xy;\n out.pos = vec4<f32>(\n vCenter + (corner.x * majorAxis + corner.y * minorAxis) * pos2d.w / u.viewport,\n pos2d.z, pos2d.w);\n out.vColor = vec4<f32>(color.rgb + shColor, color.a * u.alpha);\n out.vPos = corner;\n return out;\n}\n\n/*GS_FRAGMENT_DEFINITIONS*/\n@fragment\nfn fs(in: VOut) -> @location(0) vec4<f32> {\n /*GS_FRAGMENT_MAIN_BEGIN*/\n let A = -dot(in.vPos, in.vPos);\n if (A < -4.0) { discard; }\n let B = exp(A) * in.vColor.a;\n var finalColor = vec4<f32>(in.vColor.rgb, B);\n /*GS_FRAGMENT_BEFORE_FRAGCOLOR*/\n /*GS_FRAGMENT_MAIN_END*/\n return finalColor;\n}\n`;\n}\n\nfunction getOrCreateShPipeline(engine: EngineContext, sig: RenderTargetSignature, shDegree: number, fragments?: readonly GsShaderFragment[]): PipelineEntry {\n const device = engine._device;\n if (!_cache || _cache.device !== device) {\n _cache = { device, modules: new Map(), entries: new Map() };\n }\n const fragKey = fragments && fragments.length > 0 ? \"|\" + fragments.map((f) => f.id).join(\",\") : \"\";\n let module = _cache.modules.get(shDegree + fragKey);\n if (!module) {\n module = device.createShaderModule({\n code: fragments && fragments.length > 0 ? applyGsFragments(buildShShaderSource(shDegree), fragments) : buildShShaderSource(shDegree),\n });\n _cache.modules.set(shDegree + fragKey, module);\n }\n const key = `${targetSignatureKey(sig)}|sh${shDegree}${fragKey}`;\n let entry = _cache.entries.get(key);\n if (entry) {\n return entry;\n }\n const shTextureCount = SH_TEXTURE_COUNT[shDegree]!;\n const layoutEntries: GPUBindGroupLayoutEntry[] = [\n { binding: 0, visibility: SS.VERTEX | SS.FRAGMENT, buffer: { type: \"uniform\" } },\n { binding: 1, visibility: SS.VERTEX, sampler: { type: \"non-filtering\" } },\n { binding: 2, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 3, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 4, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 5, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n ];\n for (let i = 0; i < shTextureCount; i++) {\n layoutEntries.push({ binding: 6 + i, visibility: SS.VERTEX, texture: { sampleType: \"uint\" } });\n }\n const meshBindGroupLayout = device.createBindGroupLayout({ entries: layoutEntries });\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({ bindGroupLayouts: [getSceneBindGroupLayout(engine), meshBindGroupLayout] }),\n vertex: {\n module,\n entryPoint: \"vs\",\n buffers: [\n { arrayStride: 8, stepMode: \"vertex\", attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }] },\n { arrayStride: 4, stepMode: \"instance\", attributes: [{ shaderLocation: 1, offset: 0, format: \"float32\" }] },\n ],\n },\n fragment: {\n module,\n entryPoint: \"fs\",\n targets: [\n {\n format: sig._colorFormat!,\n blend: {\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n },\n writeMask: CW.ALL,\n },\n ],\n },\n primitive: { topology: \"triangle-list\", cullMode: \"none\" },\n depthStencil: {\n format: sig._depthStencilFormat ?? \"depth24plus-stencil8\",\n depthCompare: sig._depthCompare ?? \"greater-equal\",\n depthWriteEnabled: false,\n },\n multisample: { count: sig._sampleCount },\n });\n entry = { pipeline, meshBindGroupLayout, shTextureCount };\n _cache.entries.set(key, entry);\n return entry;\n}\n\n/** Build the Renderable for a GaussianSplattingMesh with SH coefficients.\n * Mirrors `buildGaussianSplattingRenderable` but adds eyePosition to the UBO\n * and binds the SH textures. */\nexport function buildGaussianSplattingRenderableSH(scene: SceneContext, mesh: GaussianSplattingMesh, fragments?: readonly GsShaderFragment[]): Renderable {\n const engine = scene.surface.engine;\n const device = engine._device;\n\n // 3 mat4 + 8 floats (viewport,focal,dataSize,alpha,pad) + 4 floats (eyePosition + pad) = 240 bytes.\n const UBO_BYTES = 16 * 4 * 3 + 8 * 4 + 4 * 4;\n const ubo = device.createBuffer({\n size: UBO_BYTES,\n usage: BU.UNIFORM | BU.COPY_DST,\n });\n const cpu = new F32(UBO_BYTES / 4);\n\n cpu[48 + 4] = mesh.textureWidth;\n cpu[48 + 5] = mesh.textureHeight;\n cpu[48 + 6] = 1; // alpha\n cpu[48 + 7] = 0; // pad\n\n const bindGroups = new Map<GPURenderPipeline, GPUBindGroup>();\n\n const getBindGroup = (entry: PipelineEntry): GPUBindGroup => {\n let bg = bindGroups.get(entry.pipeline);\n if (bg) {\n return bg;\n }\n const shViews = mesh._gs._shViews ?? [];\n const entries: GPUBindGroupEntry[] = [\n { binding: 0, resource: { buffer: ubo } },\n { binding: 1, resource: mesh._gs._sampler },\n { binding: 2, resource: mesh._gs._centersView },\n { binding: 3, resource: mesh._gs._covAView },\n { binding: 4, resource: mesh._gs._covBView },\n { binding: 5, resource: mesh._gs._colorsView },\n ];\n for (let i = 0; i < entry.shTextureCount; i++) {\n entries.push({ binding: 6 + i, resource: shViews[i]! });\n }\n bg = device.createBindGroup({ layout: entry.meshBindGroupLayout, entries });\n bindGroups.set(entry.pipeline, bg);\n return bg;\n };\n\n const SORT_EPS = 1e-4;\n\n const update = (): void => {\n const cam = scene.camera;\n if (!cam) {\n return;\n }\n const size = getRenderTargetSize(engine);\n const aspect = size.width / size.height;\n const view = getViewMatrix(cam) as unknown as Float32Array;\n const proj = getProjectionMatrix(cam, aspect) as unknown as Float32Array;\n const world = mesh.worldMatrix as unknown as Float32Array;\n const camPos = getCameraPosition(cam);\n\n cpu.set(world, 0);\n cpu.set(view, 16);\n cpu.set(proj, 32);\n cpu[48] = size.width;\n cpu[48 + 1] = size.height;\n cpu[48 + 2] = size.width * 0.5 * proj[0]!;\n cpu[48 + 3] = size.height * 0.5 * proj[5]!;\n cpu[56] = camPos.x;\n cpu[57] = camPos.y;\n cpu[58] = camPos.z;\n cpu[59] = 0;\n device.queue.writeBuffer(ubo, 0, cpu.buffer, 0, UBO_BYTES);\n\n if (!mesh._canPostToWorker) {\n return;\n }\n\n const cf0 = view[2]!,\n cf1 = view[6]!,\n cf2 = view[10]!;\n\n let dirty = false;\n const lastW = mesh._sortWorldMatrix;\n for (let i = 0; i < 16; i++) {\n if (Math.abs(lastW[i]! - world[i]!) > SORT_EPS) {\n dirty = true;\n break;\n }\n }\n if (!dirty) {\n const lastCf = mesh._sortCameraForward;\n if (Math.abs(lastCf[0]! - cf0) > SORT_EPS || Math.abs(lastCf[1]! - cf1) > SORT_EPS || Math.abs(lastCf[2]! - cf2) > SORT_EPS) {\n dirty = true;\n }\n }\n if (!dirty) {\n const lastCp = mesh._sortCameraPosition;\n if (Math.abs(lastCp[0]! - camPos.x) > SORT_EPS || Math.abs(lastCp[1]! - camPos.y) > SORT_EPS || Math.abs(lastCp[2]! - camPos.z) > SORT_EPS) {\n dirty = true;\n }\n }\n if (!dirty) {\n return;\n }\n\n mesh._sortWorldMatrix.set(world);\n mesh._sortCameraForward[0] = cf0;\n mesh._sortCameraForward[1] = cf1;\n mesh._sortCameraForward[2] = cf2;\n mesh._sortCameraPosition[0] = camPos.x;\n mesh._sortCameraPosition[1] = camPos.y;\n mesh._sortCameraPosition[2] = camPos.z;\n mesh._canPostToWorker = false;\n mesh._worker.postMessage(\n {\n m: new F32(world),\n f: new F32([cf0, cf1, cf2]),\n c: new F32([camPos.x, camPos.y, camPos.z]),\n d: mesh._depthMix,\n },\n [mesh._depthMix.buffer]\n );\n };\n\n const r: Renderable = {\n order: 200,\n isTransparent: true,\n bind(eng: EngineContext, sig: RenderTargetSignature): DrawBinding {\n const entry = getOrCreateShPipeline(eng as EngineContext, sig, mesh.shDegree, fragments);\n const bindGroup = getBindGroup(entry);\n return {\n renderable: r,\n pipeline: entry.pipeline,\n update,\n draw(pass) {\n pass.setBindGroup(1, bindGroup);\n pass.setVertexBuffer(0, mesh._gs._quadBuffer);\n pass.setVertexBuffer(1, mesh._gs._splatIndexBuffer);\n pass.setIndexBuffer(mesh._gs._indexBuffer, \"uint16\");\n pass.drawIndexed(6, mesh.vertexCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n/** SH-aware variant of `attachGaussianSplattingMesh`. Dynamic-imported by\n * `attachParsedSplat` (in `load-splat.ts`) when the parsed asset carries SH\n * coefficients. Reads `mesh.shDegree` (set at mesh construction), creates\n * the `rgba32uint` SH textures (1..5 depending on degree), patches\n * `mesh._gs` in place, and installs the SH renderable. */\nexport function attachGaussianSplattingMeshSH(scene: SceneContext, mesh: GaussianSplattingMesh, shFlat: Uint8Array, fragments?: readonly GsShaderFragment[]): void {\n const engine = scene.surface.engine;\n const device = engine._device;\n const shDegree = mesh.shDegree;\n const shVectorCount = (shDegree + 1) * (shDegree + 1) - 1;\n const shCoefficientCount = shVectorCount * 3;\n const textureCount = Math.ceil(shCoefficientCount / 16);\n const width = mesh.textureWidth;\n const height = mesh.textureHeight;\n\n // Pack the flat SH byte stream into N textures of 16 bytes per splat each.\n // splat i's bytes [i*shCC .. i*shCC + shCC] are split across textures\n // [t=0..textureCount-1], each carrying up to 16 bytes at offset i*16.\n const textures: GPUTexture[] = [];\n const views: GPUTextureView[] = [];\n const vertexCount = mesh.vertexCount;\n for (let t = 0; t < textureCount; t++) {\n const dst = new U8(width * height * 16);\n const tBase = t * 16;\n const bytesThisTex = Math.min(16, shCoefficientCount - tBase);\n for (let i = 0; i < vertexCount; i++) {\n const srcOff = i * shCoefficientCount + tBase;\n const dstOff = i * 16;\n for (let b = 0; b < bytesThisTex; b++) {\n dst[dstOff + b] = shFlat[srcOff + b]!;\n }\n }\n const tex = device.createTexture({\n size: [width, height],\n format: \"rgba32uint\",\n usage: TU.TEXTURE_BINDING | TU.COPY_DST,\n });\n device.queue.writeTexture({ texture: tex }, dst.buffer, { bytesPerRow: width * 16 }, { width, height });\n textures.push(tex);\n views.push(tex.createView());\n }\n mesh._gs._shTextures = textures;\n mesh._gs._shViews = views;\n\n const ctx = scene as unknown as { _renderables: Renderable[]; _disposables: (() => void)[]; _gsMeshes: GaussianSplattingMesh[] };\n ctx._renderables.push(buildGaussianSplattingRenderableSH(scene, mesh, fragments));\n ctx._gsMeshes.push(mesh);\n ctx._disposables.push(() => {\n const i = ctx._gsMeshes.indexOf(mesh);\n if (i >= 0) {\n ctx._gsMeshes.splice(i, 1);\n }\n disposeGaussianSplattingMesh(mesh);\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gaussian-splatting-pipeline-sh.js","sources":["../../../../src/mesh/GaussianSplatting/gaussian-splatting-pipeline-sh.ts"],"sourcesContent":["/** Gaussian-Splatting SH render pipeline + Renderable.\n *\n * Variant of `gaussian-splatting-pipeline.ts` that adds view-dependent SH\n * shading. Loaded *only* by `loadSplat` (and the SOG / SPZ loaders) via a\n * dynamic `import(...)` when the parsed splat asset includes SH coefficients\n * (`mesh.shDegree > 0`), so plain `.ply` / `.splat` scenes (e.g. scene 120)\n * never pull this module's WGSL or runtime cost into their bundle.\n *\n * WGSL source is generated per-shDegree by `buildShShaderSource`: SH textures,\n * byte-to-vec3 unpacking, and the polynomial evaluation in\n * `computeColorFromSHDegree` all expand to the right size — mirrors the\n * `#if SH_DEGREE > N` blocks in BJS `gaussianSplatting.fx`. Pipeline cache is\n * keyed by `(targetSignatureKey, shDegree)`.\n *\n * The UBO grows by 16 bytes vs the base pipeline to carry `eyePosition`\n * (world-space camera position; see `computeSH(dir)` below).\n *\n * ── Why the Y-flip on the SH direction? ─────────────────────────────────\n * BJS sets `mesh.scaling.y *= -1` to fix coordinate-system handedness; Lite\n * pre-flips Y in `splat-data.ts` at parse time so the runtime mesh transform\n * is identity. World-space splat positions agree across both engines, but\n * the BJS world rotation absorbs an extra `diag(1,-1,1)` factor — i.e.\n * worldRot_bjs = worldRot_user · diag(1,-1,1)\n * which means\n * inverse(worldRot_bjs) · v = diag(1,-1,1) · inverse(worldRot_user) · v\n * so Lite reproduces the BJS SH direction by computing\n * `inverseMat3(worldRot) · (worldPos − eye)` and then negating `.y`. */\n\nimport { F32, U8 } from \"../../engine/typed-arrays.js\";\nimport { TU, BU, SS, CW } from \"../../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene-core.js\";\nimport type { Renderable, DrawBinding } from \"../../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport { getViewMatrix, getProjectionMatrix, getCameraPosition } from \"../../camera/camera.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { getRenderTargetSize } from \"../../engine/engine.js\";\nimport { disposeGaussianSplattingMesh, type GaussianSplattingMesh, type GsShaderFragment } from \"./gaussian-splatting-mesh.js\";\nimport { registerPickSource } from \"../../picking/pick-contributor.js\";\nimport { applyGsFragments } from \"./gaussian-splatting-pipeline.js\";\n\ninterface PipelineEntry {\n pipeline: GPURenderPipeline;\n meshBindGroupLayout: GPUBindGroupLayout;\n shTextureCount: number;\n}\n\n// shDegree → number of rgba32uint SH textures: 1→1, 2→2, 3→3, 4→5.\nconst SH_TEXTURE_COUNT = [0, 1, 2, 3, 5];\n\nlet _cache: { device: GPUDevice; modules: Map<string, GPUShaderModule>; entries: Map<string, PipelineEntry> } | null = null;\n\n/** Build the WGSL source for a given SH degree (1..4). Mirrors the BJS\n * preprocessor-driven shader structure: declares only the SH textures used\n * by the degree, emits exactly the byte-stream unpacking for that degree,\n * and inlines only the SH polynomial terms up to that degree. */\nfunction buildShShaderSource(shDegree: number): string {\n const shVectorCount = (shDegree + 1) * (shDegree + 1) - 1;\n const shCoefficientCount = shVectorCount * 3;\n const textureCount = Math.ceil(shCoefficientCount / 16);\n\n // ── SH texture bindings (6, 7, …) ───────────────────────────────\n let textureBindings = \"\";\n for (let i = 0; i < textureCount; i++) {\n textureBindings += `@group(1) @binding(${6 + i}) var shTexture${i}: texture_2d<u32>;\\n`;\n }\n\n // ── textureLoad calls inside readSplat ──────────────────────────\n let textureLoads = \"\";\n for (let i = 0; i < textureCount; i++) {\n textureLoads += ` let sh${i}_u32 = textureLoad(shTexture${i}, splatUVi32, 0);\\n`;\n }\n\n // ── Unpack the byte stream into sh[1..shVectorCount] vec3 values.\n //\n // Each rgba32uint texel carries 16 bytes (4 u32s × 4 bytes). The bytes\n // are stored in BJS-coefficient order: byte j of splat i is the j-th\n // component of the [R0,G0,B0, R1,G1,B1, …, R(N-1),G(N-1),B(N-1)] sequence.\n // sh[k+1] (k = 0..shVectorCount-1) reads bytes [3k, 3k+1, 3k+2]. `decompose`\n // returns `(byte * 2/255) - 1`, matching BJS exactly.\n let shUnpack = ` var sh: array<vec3<f32>, ${shVectorCount + 1}>;\\n sh[0] = vec3<f32>(0.0);\\n`;\n const byteRef = (j: number): string => {\n // texture index, u32 index within texel (0..3), byte index within u32 (0..3 == x/y/z/w).\n const tex = (j / 16) | 0;\n const u32Idx = ((j % 16) / 4) | 0;\n const byteIdx = j % 4;\n const u32Field = [\"x\", \"y\", \"z\", \"w\"][u32Idx]!;\n const byteField = [\"x\", \"y\", \"z\", \"w\"][byteIdx]!;\n return `decompose(sh${tex}_u32.${u32Field}).${byteField}`;\n };\n for (let k = 0; k < shVectorCount; k++) {\n const j = k * 3;\n shUnpack += ` sh[${k + 1}] = vec3<f32>(${byteRef(j)}, ${byteRef(j + 1)}, ${byteRef(j + 2)});\\n`;\n }\n\n // ── Polynomial evaluation, conditional on shDegree ──────────────\n let shPoly = \" result = sh[0];\\n\";\n if (shDegree >= 1) {\n shPoly += ` result += -SH_C1 * y * sh[1] + SH_C1 * z * sh[2] - SH_C1 * x * sh[3];\\n`;\n }\n if (shDegree >= 2) {\n shPoly += ` result +=\\n SH_C2[0] * xy * sh[4] +\\n SH_C2[1] * yz * sh[5] +\\n SH_C2[2] * (2.0 * zz - xx - yy) * sh[6] +\\n SH_C2[3] * xz * sh[7] +\\n SH_C2[4] * (xx - yy) * sh[8];\\n`;\n }\n if (shDegree >= 3) {\n shPoly += ` result +=\\n SH_C3[0] * y * (3.0 * xx - yy) * sh[9] +\\n SH_C3[1] * xy * z * sh[10] +\\n SH_C3[2] * y * (4.0 * zz - xx - yy) * sh[11] +\\n SH_C3[3] * z * (2.0 * zz - 3.0 * xx - 3.0 * yy) * sh[12] +\\n SH_C3[4] * x * (4.0 * zz - xx - yy) * sh[13] +\\n SH_C3[5] * z * (xx - yy) * sh[14] +\\n SH_C3[6] * x * (xx - 3.0 * yy) * sh[15];\\n`;\n }\n if (shDegree >= 4) {\n shPoly += ` result +=\\n SH_C4[0] * x * y * (xx - yy) * sh[16] +\\n SH_C4[1] * y * z * (3.0 * xx - yy) * sh[17] +\\n SH_C4[2] * x * y * (7.0 * zz - 1.0) * sh[18] +\\n SH_C4[3] * y * z * (7.0 * zz - 3.0) * sh[19] +\\n SH_C4[4] * (zz * (35.0 * zz - 30.0) + 3.0) * sh[20] +\\n SH_C4[5] * x * z * (7.0 * zz - 3.0) * sh[21] +\\n SH_C4[6] * (xx - yy) * (7.0 * zz - 1.0) * sh[22] +\\n SH_C4[7] * x * z * (xx - 3.0 * yy) * sh[23] +\\n SH_C4[8] * (xx * (xx - 3.0 * yy) - yy * (3.0 * xx - yy)) * sh[24];\\n`;\n }\n\n // SH_C2..SH_C4 constants — only declare what's referenced (silences\n // WGSL \"unused array\" warnings on lower degrees).\n let constantsBlock = `const SH_C1: f32 = 0.48860251;\\n`;\n if (shDegree >= 2) {\n constantsBlock += `const SH_C2: array<f32, 5> = array<f32, 5>(1.092548430, -1.09254843, 0.315391565, -1.09254843, 0.546274215);\\n`;\n }\n if (shDegree >= 3) {\n constantsBlock += `const SH_C3: array<f32, 7> = array<f32, 7>(-0.59004358, 2.890611442, -0.45704579, 0.373176332, -0.45704579, 1.445305721, -0.59004358);\\n`;\n }\n if (shDegree >= 4) {\n constantsBlock += `const SH_C4: array<f32, 9> = array<f32, 9>(2.5033429418, -1.7701307698, 0.9461746958, -0.6690465436, 0.1057855469, -0.6690465436, 0.4730873479, -1.7701307698, 0.6258357354);\\n`;\n }\n\n return `// Gaussian Splatting — vertex + fragment WGSL (SH degree ${shDegree}).\n// Generated by buildShShaderSource. Mirrors BJS gaussianSplatting.vertex.fx +\n// gaussianSplatting.fx (SH_DEGREE = ${shDegree}, no compound parts).\nstruct U {\n world: mat4x4<f32>,\n view: mat4x4<f32>,\n projection: mat4x4<f32>,\n viewport: vec2<f32>,\n focal: vec2<f32>,\n dataSize: vec2<f32>,\n alpha: f32,\n _pad0: f32,\n eyePosition: vec3<f32>,\n _pad1: f32,\n};\n@group(1) @binding(0) var<uniform> u: U;\n@group(1) @binding(1) var samp: sampler;\n@group(1) @binding(2) var centersTex: texture_2d<f32>;\n@group(1) @binding(3) var covATex: texture_2d<f32>;\n@group(1) @binding(4) var covBTex: texture_2d<f32>;\n@group(1) @binding(5) var colorsTex: texture_2d<f32>;\n${textureBindings}\n\nstruct VOut {\n @builtin(position) pos: vec4<f32>,\n @location(0) vColor: vec4<f32>,\n @location(1) vPos: vec2<f32>,\n};\n\n${constantsBlock}\n\nfn dataUv(idx: f32) -> vec2<f32> {\n let y = floor(idx / u.dataSize.x);\n let x = idx - y * u.dataSize.x;\n return vec2<f32>((x + 0.5) / u.dataSize.x, (y + 0.5) / u.dataSize.y);\n}\n\nfn dataUvI(idx: f32) -> vec2<i32> {\n let y = floor(idx / u.dataSize.x);\n let x = idx - y * u.dataSize.x;\n return vec2<i32>(i32(x), i32(y));\n}\n\n// Unpack a u32 of 4 packed bytes into (b0 b1 b2 b3) * 2/255 - 1.\nfn decompose(value: u32) -> vec4<f32> {\n let v = vec4<f32>(\n f32((value >> 0u) & 255u),\n f32((value >> 8u) & 255u),\n f32((value >> 16u) & 255u),\n f32((value >> 24u) & 255u));\n return v * vec4<f32>(2.0 / 255.0) - vec4<f32>(1.0);\n}\n\nfn inverseMat3(m: mat3x3<f32>) -> mat3x3<f32> {\n let a00 = m[0][0]; let a01 = m[0][1]; let a02 = m[0][2];\n let a10 = m[1][0]; let a11 = m[1][1]; let a12 = m[1][2];\n let a20 = m[2][0]; let a21 = m[2][1]; let a22 = m[2][2];\n let b01 = a22 * a11 - a12 * a21;\n let b11 = -a22 * a10 + a12 * a20;\n let b21 = a21 * a10 - a11 * a20;\n let det = a00 * b01 + a01 * b11 + a02 * b21;\n return mat3x3<f32>(\n vec3<f32>(b01 / det, (-a22 * a01 + a02 * a21) / det, (a12 * a01 - a02 * a11) / det),\n vec3<f32>(b11 / det, (a22 * a00 - a02 * a20) / det, (-a12 * a00 + a02 * a10) / det),\n vec3<f32>(b21 / det, (-a21 * a00 + a01 * a20) / det, (a11 * a00 - a01 * a10) / det));\n}\n\nfn computeSH(dir: vec3<f32>, splatUVi32: vec2<i32>) -> vec3<f32> {\n${textureLoads}${shUnpack} let x = dir.x;\n let y = dir.y;\n let z = dir.z;\n let xx = x * x; let yy = y * y; let zz = z * z;\n let xy = x * y; let yz = y * z; let xz = x * z;\n var result: vec3<f32>;\n${shPoly} return result;\n}\n\n@vertex\nfn vs(@location(0) corner: vec2<f32>, @location(1) splatIndex: f32) -> VOut {\n var out: VOut;\n let uv = dataUv(splatIndex);\n let splatUVi32 = dataUvI(splatIndex);\n let center = textureSampleLevel(centersTex, samp, uv, 0.0).xyz;\n let color = textureSampleLevel(colorsTex, samp, uv, 0.0);\n let covA = textureSampleLevel(covATex, samp, uv, 0.0).xyz;\n let covB = textureSampleLevel(covBTex, samp, uv, 0.0).xyz;\n\n let worldPos = u.world * vec4<f32>(center, 1.0);\n let modelView = u.view * u.world;\n let camspace = u.view * worldPos;\n let pos2d = u.projection * camspace;\n\n let bounds = 1.2 * pos2d.w;\n if (pos2d.z < 0.0\n || pos2d.x < -bounds || pos2d.x > bounds\n || pos2d.y < -bounds || pos2d.y > bounds) {\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\n out.vColor = vec4<f32>(0.0);\n out.vPos = vec2<f32>(0.0);\n return out;\n }\n\n // ── View-dependent SH evaluation ───────────────────────────────────\n let worldRot = mat3x3<f32>(u.world[0].xyz, u.world[1].xyz, u.world[2].xyz);\n let normWorldRot = inverseMat3(worldRot);\n var dir = normalize(normWorldRot * (worldPos.xyz - u.eyePosition));\n // Lite-side Y-flip: compensates for our data-path Y pre-flip vs BJS's\n // mesh.scaling.y *= -1 (see file header for derivation).\n dir.y = -dir.y;\n let shColor = computeSH(dir, splatUVi32);\n\n let Vrk = mat3x3<f32>(\n vec3<f32>(covA.x, covA.y, covA.z),\n vec3<f32>(covA.y, covB.x, covB.y),\n vec3<f32>(covA.z, covB.y, covB.z));\n\n let invZ = 1.0 / camspace.z;\n let invZ2 = invZ * invZ;\n let J = mat3x3<f32>(\n vec3<f32>(u.focal.x * invZ, 0.0, -u.focal.x * camspace.x * invZ2),\n vec3<f32>(0.0, u.focal.y * invZ, -u.focal.y * camspace.y * invZ2),\n vec3<f32>(0.0, 0.0, 0.0));\n\n let mv3 = mat3x3<f32>(modelView[0].xyz, modelView[1].xyz, modelView[2].xyz);\n let T = transpose(mv3) * J;\n var cov2d = transpose(T) * Vrk * T;\n\n let kernelSize: f32 = 0.3;\n cov2d[0][0] += kernelSize;\n cov2d[1][1] += kernelSize;\n\n let mid = (cov2d[0][0] + cov2d[1][1]) * 0.5;\n let dxy = (cov2d[0][0] - cov2d[1][1]) * 0.5;\n let radius = length(vec2<f32>(dxy, cov2d[0][1]));\n let epsilon: f32 = 0.0001;\n let lambda1 = mid + radius + epsilon;\n let lambda2 = mid - radius + epsilon;\n if (lambda2 < 0.0) {\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\n out.vColor = vec4<f32>(0.0);\n out.vPos = vec2<f32>(0.0);\n return out;\n }\n\n let diag = normalize(vec2<f32>(cov2d[0][1], lambda1 - cov2d[0][0]));\n let majorAxis = min(sqrt(2.0 * lambda1), 1024.0) * diag;\n let minorAxis = min(sqrt(2.0 * lambda2), 1024.0) * vec2<f32>(diag.y, -diag.x);\n\n let vCenter = pos2d.xy;\n out.pos = vec4<f32>(\n vCenter + (corner.x * majorAxis + corner.y * minorAxis) * pos2d.w / u.viewport,\n pos2d.z, pos2d.w);\n out.vColor = vec4<f32>(color.rgb + shColor, color.a * u.alpha);\n out.vPos = corner;\n return out;\n}\n\n/*GS_FRAGMENT_DEFINITIONS*/\n@fragment\nfn fs(in: VOut) -> @location(0) vec4<f32> {\n /*GS_FRAGMENT_MAIN_BEGIN*/\n let A = -dot(in.vPos, in.vPos);\n if (A < -4.0) { discard; }\n let B = exp(A) * in.vColor.a;\n var finalColor = vec4<f32>(in.vColor.rgb, B);\n /*GS_FRAGMENT_BEFORE_FRAGCOLOR*/\n /*GS_FRAGMENT_MAIN_END*/\n return finalColor;\n}\n`;\n}\n\nfunction getOrCreateShPipeline(engine: EngineContext, sig: RenderTargetSignature, shDegree: number, fragments?: readonly GsShaderFragment[]): PipelineEntry {\n const device = engine._device;\n if (!_cache || _cache.device !== device) {\n _cache = { device, modules: new Map(), entries: new Map() };\n }\n const fragKey = fragments && fragments.length > 0 ? \"|\" + fragments.map((f) => f.id).join(\",\") : \"\";\n let module = _cache.modules.get(shDegree + fragKey);\n if (!module) {\n module = device.createShaderModule({\n code: fragments && fragments.length > 0 ? applyGsFragments(buildShShaderSource(shDegree), fragments) : buildShShaderSource(shDegree),\n });\n _cache.modules.set(shDegree + fragKey, module);\n }\n const key = `${targetSignatureKey(sig)}|sh${shDegree}${fragKey}`;\n let entry = _cache.entries.get(key);\n if (entry) {\n return entry;\n }\n const shTextureCount = SH_TEXTURE_COUNT[shDegree]!;\n const layoutEntries: GPUBindGroupLayoutEntry[] = [\n { binding: 0, visibility: SS.VERTEX | SS.FRAGMENT, buffer: { type: \"uniform\" } },\n { binding: 1, visibility: SS.VERTEX, sampler: { type: \"non-filtering\" } },\n { binding: 2, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 3, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 4, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 5, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n ];\n for (let i = 0; i < shTextureCount; i++) {\n layoutEntries.push({ binding: 6 + i, visibility: SS.VERTEX, texture: { sampleType: \"uint\" } });\n }\n const meshBindGroupLayout = device.createBindGroupLayout({ entries: layoutEntries });\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({ bindGroupLayouts: [getSceneBindGroupLayout(engine), meshBindGroupLayout] }),\n vertex: {\n module,\n entryPoint: \"vs\",\n buffers: [\n { arrayStride: 8, stepMode: \"vertex\", attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }] },\n { arrayStride: 4, stepMode: \"instance\", attributes: [{ shaderLocation: 1, offset: 0, format: \"float32\" }] },\n ],\n },\n fragment: {\n module,\n entryPoint: \"fs\",\n targets: [\n {\n format: sig._colorFormat!,\n blend: {\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n },\n writeMask: CW.ALL,\n },\n ],\n },\n primitive: { topology: \"triangle-list\", cullMode: \"none\" },\n depthStencil: {\n format: sig._depthStencilFormat ?? \"depth24plus-stencil8\",\n depthCompare: sig._depthCompare ?? \"greater-equal\",\n depthWriteEnabled: false,\n },\n multisample: { count: sig._sampleCount },\n });\n entry = { pipeline, meshBindGroupLayout, shTextureCount };\n _cache.entries.set(key, entry);\n return entry;\n}\n\n/** Build the Renderable for a GaussianSplattingMesh with SH coefficients.\n * Mirrors `buildGaussianSplattingRenderable` but adds eyePosition to the UBO\n * and binds the SH textures. */\nexport function buildGaussianSplattingRenderableSH(scene: SceneContext, mesh: GaussianSplattingMesh, fragments?: readonly GsShaderFragment[]): Renderable {\n const engine = scene.surface.engine;\n const device = engine._device;\n\n // 3 mat4 + 8 floats (viewport,focal,dataSize,alpha,pad) + 4 floats (eyePosition + pad) = 240 bytes.\n const UBO_BYTES = 16 * 4 * 3 + 8 * 4 + 4 * 4;\n const ubo = device.createBuffer({\n size: UBO_BYTES,\n usage: BU.UNIFORM | BU.COPY_DST,\n });\n const cpu = new F32(UBO_BYTES / 4);\n\n cpu[48 + 4] = mesh.textureWidth;\n cpu[48 + 5] = mesh.textureHeight;\n cpu[48 + 6] = 1; // alpha\n cpu[48 + 7] = 0; // pad\n\n const bindGroups = new Map<GPURenderPipeline, GPUBindGroup>();\n\n const getBindGroup = (entry: PipelineEntry): GPUBindGroup => {\n let bg = bindGroups.get(entry.pipeline);\n if (bg) {\n return bg;\n }\n const shViews = mesh._gs._shViews ?? [];\n const entries: GPUBindGroupEntry[] = [\n { binding: 0, resource: { buffer: ubo } },\n { binding: 1, resource: mesh._gs._sampler },\n { binding: 2, resource: mesh._gs._centersView },\n { binding: 3, resource: mesh._gs._covAView },\n { binding: 4, resource: mesh._gs._covBView },\n { binding: 5, resource: mesh._gs._colorsView },\n ];\n for (let i = 0; i < entry.shTextureCount; i++) {\n entries.push({ binding: 6 + i, resource: shViews[i]! });\n }\n bg = device.createBindGroup({ layout: entry.meshBindGroupLayout, entries });\n bindGroups.set(entry.pipeline, bg);\n return bg;\n };\n\n const SORT_EPS = 1e-4;\n\n const update = (): void => {\n const cam = scene.camera;\n if (!cam) {\n return;\n }\n const size = getRenderTargetSize(engine);\n const aspect = size.width / size.height;\n const view = getViewMatrix(cam) as unknown as Float32Array;\n const proj = getProjectionMatrix(cam, aspect) as unknown as Float32Array;\n const world = mesh.worldMatrix as unknown as Float32Array;\n const camPos = getCameraPosition(cam);\n\n cpu.set(world, 0);\n cpu.set(view, 16);\n cpu.set(proj, 32);\n cpu[48] = size.width;\n cpu[48 + 1] = size.height;\n cpu[48 + 2] = size.width * 0.5 * proj[0]!;\n cpu[48 + 3] = size.height * 0.5 * proj[5]!;\n cpu[56] = camPos.x;\n cpu[57] = camPos.y;\n cpu[58] = camPos.z;\n cpu[59] = 0;\n device.queue.writeBuffer(ubo, 0, cpu.buffer, 0, UBO_BYTES);\n\n if (!mesh._canPostToWorker) {\n return;\n }\n\n const cf0 = view[2]!,\n cf1 = view[6]!,\n cf2 = view[10]!;\n\n let dirty = false;\n const lastW = mesh._sortWorldMatrix;\n for (let i = 0; i < 16; i++) {\n if (Math.abs(lastW[i]! - world[i]!) > SORT_EPS) {\n dirty = true;\n break;\n }\n }\n if (!dirty) {\n const lastCf = mesh._sortCameraForward;\n if (Math.abs(lastCf[0]! - cf0) > SORT_EPS || Math.abs(lastCf[1]! - cf1) > SORT_EPS || Math.abs(lastCf[2]! - cf2) > SORT_EPS) {\n dirty = true;\n }\n }\n if (!dirty) {\n const lastCp = mesh._sortCameraPosition;\n if (Math.abs(lastCp[0]! - camPos.x) > SORT_EPS || Math.abs(lastCp[1]! - camPos.y) > SORT_EPS || Math.abs(lastCp[2]! - camPos.z) > SORT_EPS) {\n dirty = true;\n }\n }\n if (!dirty) {\n return;\n }\n\n mesh._sortWorldMatrix.set(world);\n mesh._sortCameraForward[0] = cf0;\n mesh._sortCameraForward[1] = cf1;\n mesh._sortCameraForward[2] = cf2;\n mesh._sortCameraPosition[0] = camPos.x;\n mesh._sortCameraPosition[1] = camPos.y;\n mesh._sortCameraPosition[2] = camPos.z;\n mesh._canPostToWorker = false;\n mesh._worker.postMessage(\n {\n m: new F32(world),\n f: new F32([cf0, cf1, cf2]),\n c: new F32([camPos.x, camPos.y, camPos.z]),\n d: mesh._depthMix,\n },\n [mesh._depthMix.buffer]\n );\n };\n\n const r: Renderable = {\n order: 200,\n isTransparent: true,\n bind(eng: EngineContext, sig: RenderTargetSignature): DrawBinding {\n const entry = getOrCreateShPipeline(eng as EngineContext, sig, mesh.shDegree, fragments);\n const bindGroup = getBindGroup(entry);\n return {\n renderable: r,\n pipeline: entry.pipeline,\n update,\n draw(pass) {\n pass.setBindGroup(1, bindGroup);\n pass.setVertexBuffer(0, mesh._gs._quadBuffer);\n pass.setVertexBuffer(1, mesh._gs._splatIndexBuffer);\n pass.setIndexBuffer(mesh._gs._indexBuffer, \"uint16\");\n pass.drawIndexed(6, mesh.vertexCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n/** SH-aware variant of `attachGaussianSplattingMesh`. Dynamic-imported by\n * `attachParsedSplat` (in `load-splat.ts`) when the parsed asset carries SH\n * coefficients. Reads `mesh.shDegree` (set at mesh construction), creates\n * the `rgba32uint` SH textures (1..5 depending on degree), patches\n * `mesh._gs` in place, and installs the SH renderable. */\nexport function attachGaussianSplattingMeshSH(scene: SceneContext, mesh: GaussianSplattingMesh, shFlat: Uint8Array, fragments?: readonly GsShaderFragment[]): void {\n const engine = scene.surface.engine;\n const device = engine._device;\n const shDegree = mesh.shDegree;\n const shVectorCount = (shDegree + 1) * (shDegree + 1) - 1;\n const shCoefficientCount = shVectorCount * 3;\n const textureCount = Math.ceil(shCoefficientCount / 16);\n const width = mesh.textureWidth;\n const height = mesh.textureHeight;\n\n // Pack the flat SH byte stream into N textures of 16 bytes per splat each.\n // splat i's bytes [i*shCC .. i*shCC + shCC] are split across textures\n // [t=0..textureCount-1], each carrying up to 16 bytes at offset i*16.\n const textures: GPUTexture[] = [];\n const views: GPUTextureView[] = [];\n const vertexCount = mesh.vertexCount;\n for (let t = 0; t < textureCount; t++) {\n const dst = new U8(width * height * 16);\n const tBase = t * 16;\n const bytesThisTex = Math.min(16, shCoefficientCount - tBase);\n for (let i = 0; i < vertexCount; i++) {\n const srcOff = i * shCoefficientCount + tBase;\n const dstOff = i * 16;\n for (let b = 0; b < bytesThisTex; b++) {\n dst[dstOff + b] = shFlat[srcOff + b]!;\n }\n }\n const tex = device.createTexture({\n size: [width, height],\n format: \"rgba32uint\",\n usage: TU.TEXTURE_BINDING | TU.COPY_DST,\n });\n device.queue.writeTexture({ texture: tex }, dst.buffer, { bytesPerRow: width * 16 }, { width, height });\n textures.push(tex);\n views.push(tex.createView());\n }\n mesh._gs._shTextures = textures;\n mesh._gs._shViews = views;\n\n const ctx = scene as unknown as { _renderables: Renderable[]; _disposables: (() => void)[] };\n ctx._renderables.push(buildGaussianSplattingRenderableSH(scene, mesh, fragments));\n const unregisterPick = registerPickSource(scene, mesh, () => import(\"../../picking/gs-picking-pipeline.js\"));\n ctx._disposables.push(() => {\n unregisterPick();\n disposeGaussianSplattingMesh(mesh);\n });\n}\n"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import { getViewMatrix, getProjectionMatrix, getCameraPosition } from '../../cam
5
5
  import { getSceneBindGroupLayout } from '../../render/scene-helpers.js';
6
6
  import { getRenderTargetSize } from '../../engine/engine.js';
7
7
  import { disposeGaussianSplattingMesh } from './gaussian-splatting-mesh.js';
8
+ import { registerPickSource } from '../../picking/pick-contributor.js';
8
9
 
9
10
  const WGSL = "struct S{w:mat4x4<f32>,v:mat4x4<f32>,p:mat4x4<f32>,vp:vec2<f32>,f:vec2<f32>,ds:vec2<f32>,a:f32,_p:f32}@group(1) @binding(0) var<uniform> u:S;@group(1) @binding(1) var e:sampler;@group(1) @binding(2) var F:texture_2d<f32>;@group(1) @binding(3) var G:texture_2d<f32>;@group(1) @binding(4) var J:texture_2d<f32>;@group(1) @binding(5) var K:texture_2d<f32>;struct A{@builtin(position) pos:vec4<f32>,@location(0) vc:vec4<f32>,@location(1) vq:vec2<f32>}fn B(r:f32)->vec2<f32>{let v=floor(r/u.ds.x);let N=r-v*u.ds.x;return vec2<f32>((N+0.5)/u.ds.x,(v+0.5)/u.ds.y);}@vertex fn vs(@location(0) k:vec2<f32>,@location(1) R:f32)->A{var a:A;let j=B(R);let M=textureSampleLevel(F,e,j,0.0).xyz;let q=textureSampleLevel(K,e,j,0.0);let d=textureSampleLevel(G,e,j,0.0).xyz;let i=textureSampleLevel(J,e,j,0.0).xyz;let C=u.w*vec4<f32>(M,1.0);let m=u.v*u.w;let h=u.v*C;let b=u.p*h;let g=1.2*b.w;if (b.z<0.0||b.x<-g||b.x>g||b.y<-g||b.y>g){a.pos=vec4<f32>(0.0,0.0,2.0,1.0);a.vc=vec4<f32>(0.0);a.vq=vec2<f32>(0.0);return a;}let H=mat3x3<f32>(vec3<f32>(d.x,d.y,d.z),vec3<f32>(d.y,i.x,i.y),vec3<f32>(d.z,i.y,i.z));let f=1.0/h.z;let s=f*f;let E=mat3x3<f32>(vec3<f32>(u.f.x*f,0.0,-u.f.x*h.x*s),vec3<f32>(0.0,u.f.y*f,-u.f.y*h.y*s),vec3<f32>(0.0,0.0,0.0));let P=mat3x3<f32>(m[0].xyz,m[1].xyz,m[2].xyz);let t=transpose(P)*E;var c=transpose(t)*H*t;let w:f32=0.3;c[0][0]+=w;c[1][1]+=w;let z=(c[0][0]+c[1][1])*0.5;let I=(c[0][0]-c[1][1])*0.5;let y=length(vec2<f32>(I,c[0][1]));let x:f32=0.0001;let n=z+y+x;let p=z-y+x;if (p<0.0){a.pos=vec4<f32>(0.0,0.0,2.0,1.0);a.vc=vec4<f32>(0.0);a.vq=vec2<f32>(0.0);return a;}let l=normalize(vec2<f32>(c[0][1],n-c[0][0]));let O=min(sqrt(2.0*n),1024.0)*l;let D=min(sqrt(2.0*p),1024.0)*vec2<f32>(l.y,-l.x);let Q=b.xy;a.pos=vec4<f32>(Q+(k.x*O+k.y*D)*b.w/u.vp,b.z,b.w);a.vc=vec4<f32>(q.rgb,q.a*u.a);a.vq=k;return a;}/*GS_FRAGMENT_DEFINITIONS*/@fragment fn fs(in:A)->@location(0) vec4<f32>{/*GS_FRAGMENT_MAIN_BEGIN*/let o=-dot(in.vq,in.vq);var finalColor:vec4<f32>;if (o>-4.0){let L=exp(o)*in.vc.a;finalColor=vec4<f32>(in.vc.rgb,L);} else{finalColor=vec4<f32>(0.0);}/*GS_FRAGMENT_BEFORE_FRAGCOLOR*//*GS_FRAGMENT_MAIN_END*/return finalColor;}";
10
11
 
@@ -258,12 +259,9 @@ function buildGaussianSplattingRenderable(scene, mesh, fragments) {
258
259
  function attachGaussianSplattingMesh(scene, mesh, fragments) {
259
260
  const ctx = scene;
260
261
  ctx._renderables.push(buildGaussianSplattingRenderable(scene, mesh, fragments));
261
- ctx._gsMeshes.push(mesh);
262
+ const unregisterPick = registerPickSource(scene, mesh, () => import('../../picking/gs-picking-pipeline.js'));
262
263
  ctx._disposables.push(() => {
263
- const i = ctx._gsMeshes.indexOf(mesh);
264
- if (i >= 0) {
265
- ctx._gsMeshes.splice(i, 1);
266
- }
264
+ unregisterPick();
267
265
  disposeGaussianSplattingMesh(mesh);
268
266
  });
269
267
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gaussian-splatting-pipeline.js","sources":["../../../../shaders/gaussian-splatting.wgsl?raw","../../../../src/mesh/GaussianSplatting/gaussian-splatting-pipeline.ts"],"sourcesContent":["export default \"// Gaussian Splatting — vertex + fragment WGSL.\\n// Mirrors the math in BJS gaussianSplatting.vertex.fx / .fragment.fx\\n// (static splat path: no SH, no compound transforms).\\nstruct U {\\n world: mat4x4<f32>,\\n view: mat4x4<f32>,\\n projection: mat4x4<f32>,\\n viewport: vec2<f32>,\\n focal: vec2<f32>,\\n dataSize: vec2<f32>,\\n alpha: f32,\\n _pad: f32,\\n};\\n@group(1) @binding(0) var<uniform> u: U;\\n@group(1) @binding(1) var samp: sampler;\\n@group(1) @binding(2) var centersTex: texture_2d<f32>;\\n@group(1) @binding(3) var covATex: texture_2d<f32>;\\n@group(1) @binding(4) var covBTex: texture_2d<f32>;\\n@group(1) @binding(5) var colorsTex: texture_2d<f32>;\\n\\nstruct VOut {\\n @builtin(position) pos: vec4<f32>,\\n @location(0) vColor: vec4<f32>,\\n @location(1) vPos: vec2<f32>,\\n};\\n\\nfn dataUv(idx: f32) -> vec2<f32> {\\n let y = floor(idx / u.dataSize.x);\\n let x = idx - y * u.dataSize.x;\\n return vec2<f32>((x + 0.5) / u.dataSize.x, (y + 0.5) / u.dataSize.y);\\n}\\n\\n@vertex\\nfn vs(@location(0) corner: vec2<f32>, @location(1) splatIndex: f32) -> VOut {\\n var out: VOut;\\n let uv = dataUv(splatIndex);\\n let center = textureSampleLevel(centersTex, samp, uv, 0.0).xyz;\\n let color = textureSampleLevel(colorsTex, samp, uv, 0.0);\\n let covA = textureSampleLevel(covATex, samp, uv, 0.0).xyz;\\n let covB = textureSampleLevel(covBTex, samp, uv, 0.0).xyz;\\n\\n let worldPos = u.world * vec4<f32>(center, 1.0);\\n let modelView = u.view * u.world;\\n let camspace = u.view * worldPos;\\n let pos2d = u.projection * camspace;\\n\\n let bounds = 1.2 * pos2d.w;\\n if (pos2d.z < 0.0\\n || pos2d.x < -bounds || pos2d.x > bounds\\n || pos2d.y < -bounds || pos2d.y > bounds) {\\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\\n out.vColor = vec4<f32>(0.0);\\n out.vPos = vec2<f32>(0.0);\\n return out;\\n }\\n\\n let Vrk = mat3x3<f32>(\\n vec3<f32>(covA.x, covA.y, covA.z),\\n vec3<f32>(covA.y, covB.x, covB.y),\\n vec3<f32>(covA.z, covB.y, covB.z));\\n\\n let invZ = 1.0 / camspace.z;\\n let invZ2 = invZ * invZ;\\n // J is written in the SAME transposed-storage form BJS uses in\\n // gaussianSplatting.fx — i.e. the perspective-correction terms\\n // -focal·x/z² and -focal·y/z² sit in math row 2 (columns 0,1), not in\\n // math column 2. This is required because the next two lines compute\\n // `T = transpose(mv3) * J` and `cov2d = transpose(T) * Vrk * T`,\\n // which only collapses to the correct EWA projection\\n // cov2d = (J_std · mv3) · Σ · (J_std · mv3)ᵀ\\n // when J here equals J_stdᵀ. Using J in standard form would compute\\n // the wrong product Jᵀ·mv3·Σ·mv3ᵀ·J, agreeing with BJS only for splats\\n // on the optical axis (x=y=0) and producing visible per-splat\\n // orientation differences off-centre.\\n let J = mat3x3<f32>(\\n vec3<f32>(u.focal.x * invZ, 0.0, -u.focal.x * camspace.x * invZ2),\\n vec3<f32>(0.0, u.focal.y * invZ, -u.focal.y * camspace.y * invZ2),\\n vec3<f32>(0.0, 0.0, 0.0));\\n\\n let mv3 = mat3x3<f32>(modelView[0].xyz, modelView[1].xyz, modelView[2].xyz);\\n let T = transpose(mv3) * J;\\n var cov2d = transpose(T) * Vrk * T;\\n\\n // BJS GaussianSplattingMaterial defaults: KernelSize = 0.3 (low-pass dilation\\n // — keeps sub-pixel splats from disappearing, see gaussianSplatting.fx).\\n // The +epsilon in the eigenvalues mirrors the same shader's numerical safety.\\n let kernelSize: f32 = 0.3;\\n cov2d[0][0] += kernelSize;\\n cov2d[1][1] += kernelSize;\\n\\n let mid = (cov2d[0][0] + cov2d[1][1]) * 0.5;\\n let dxy = (cov2d[0][0] - cov2d[1][1]) * 0.5;\\n let radius = length(vec2<f32>(dxy, cov2d[0][1]));\\n let epsilon: f32 = 0.0001;\\n let lambda1 = mid + radius + epsilon;\\n let lambda2 = mid - radius + epsilon;\\n if (lambda2 < 0.0) {\\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\\n out.vColor = vec4<f32>(0.0);\\n out.vPos = vec2<f32>(0.0);\\n return out;\\n }\\n\\n let diag = normalize(vec2<f32>(cov2d[0][1], lambda1 - cov2d[0][0]));\\n let majorAxis = min(sqrt(2.0 * lambda1), 1024.0) * diag;\\n let minorAxis = min(sqrt(2.0 * lambda2), 1024.0) * vec2<f32>(diag.y, -diag.x);\\n\\n let vCenter = pos2d.xy;\\n out.pos = vec4<f32>(\\n vCenter + (corner.x * majorAxis + corner.y * minorAxis) * pos2d.w / u.viewport,\\n pos2d.z, pos2d.w);\\n out.vColor = vec4<f32>(color.rgb, color.a * u.alpha);\\n out.vPos = corner;\\n return out;\\n}\\n\\n/*GS_FRAGMENT_DEFINITIONS*/\\n@fragment\\nfn fs(in: VOut) -> @location(0) vec4<f32> {\\n /*GS_FRAGMENT_MAIN_BEGIN*/\\n let A = -dot(in.vPos, in.vPos);\\n var finalColor: vec4<f32>;\\n if (A > -4.0) {\\n let B = exp(A) * in.vColor.a;\\n finalColor = vec4<f32>(in.vColor.rgb, B);\\n } else {\\n finalColor = vec4<f32>(0.0);\\n }\\n /*GS_FRAGMENT_BEFORE_FRAGCOLOR*/\\n /*GS_FRAGMENT_MAIN_END*/\\n return finalColor;\\n}\\n\"","/** Gaussian-Splatting render pipeline + Renderable.\n *\n * WGSL port of the BJS `gaussianSplatting.vertex.fx` / `.fragment.fx`\n * pair, restricted to the static splat path (no SH, no compound parts).\n * Math is unchanged: the EWA / Vrk projection of the 3D anisotropic\n * Gaussian is computed exactly as in BJS, then the per-fragment\n * density `exp(-r²) * α` is multiplied with the splat colour.\n *\n * Per-frame the binding's `update` hook:\n * 1. refreshes the per-mesh UBO (world / view / projection / focal / viewport),\n * 2. checks whether the world matrix, camera-forward (view[2,6,10]) or\n * camera world position has drifted past `SORT_EPS` since the last sort\n * (mirrors BJS `_isSortStateDirty`) and, if so, posts a fresh sort job,\n * 3. lets the GS-mesh `onmessage` handler upload the freshly-sorted\n * splatIndex buffer back to the GPU.\n *\n * The pipeline is cached per `RenderTargetSignature`. */\n\nimport { F32 } from \"../../engine/typed-arrays.js\";\nimport { BU, SS, CW } from \"../../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene-core.js\";\nimport type { Renderable, DrawBinding } from \"../../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport { getViewMatrix, getProjectionMatrix, getCameraPosition } from \"../../camera/camera.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { getRenderTargetSize } from \"../../engine/engine.js\";\nimport { disposeGaussianSplattingMesh, type GaussianSplattingMesh, type GsShaderFragment } from \"./gaussian-splatting-mesh.js\";\nimport WGSL from \"../../../shaders/gaussian-splatting.wgsl?raw\";\n\ninterface PipelineEntry {\n pipeline: GPURenderPipeline;\n meshBindGroupLayout: GPUBindGroupLayout;\n}\n\n// Per-device pipeline cache keyed by RenderTargetSignature string. Tree-shake-friendly\n// lazy init (no top-level `new Map`) — see GUIDANCE §4.\nlet _cache: { device: GPUDevice; modules: Map<string, GPUShaderModule>; entries: Map<string, PipelineEntry> } | null = null;\n\nexport function applyGsFragments(wgsl: string, fragments: readonly GsShaderFragment[]): string {\n const slotCode: Record<string, string> = {};\n for (const frag of fragments) {\n if (frag.helperFunctions) {\n slotCode[\"GS_FRAGMENT_DEFINITIONS\"] = (slotCode[\"GS_FRAGMENT_DEFINITIONS\"] ?? \"\") + frag.helperFunctions + \"\\n\";\n }\n for (const [slot, code] of Object.entries(frag.fragmentSlots ?? {})) {\n slotCode[slot] = (slotCode[slot] ?? \"\") + code + \"\\n\";\n }\n }\n const spliced = wgsl.replace(/\\/\\*(GS_FRAGMENT_\\w+)\\*\\//g, (_, slot: string) => slotCode[slot] ?? \"\");\n\n // Field-name mangler for the GS shader. Mirrors `mangleGaussianSplattingWgsl`\n // in `scripts/bundle-scenes-core.ts` (build-time mangling of the base WGSL).\n //\n // The build-time mangler renames struct fields like `u.projection → u.p` in\n // the bundled `gaussian-splatting.wgsl`. Fragment-plugin code (e.g.\n // `gsLinearDepthFragment`) lives in TS string constants that reference the\n // un-mangled names (`u.projection`), so without normalisation the spliced\n // WGSL has both `u.projection` (from the fragment) and `u.p` (from the base),\n // causing a WebGPU parse error.\n //\n // Running the same mangler at runtime on the final spliced string makes both\n // parts use the mangled names. The substitution is idempotent (single-letter\n // mangled names don't match the `\\bfullName\\b` regexes) and harmless in dev\n // mode (where the base WGSL is un-mangled, so this just normalises everything\n // to the mangled form — WebGPU accepts both).\n //\n // KEEP IN SYNC with `scripts/bundle-scenes-core.ts:mangleGaussianSplattingWgsl`.\n //\n // Inlined here (rather than a top-level constant) so it tree-shakes out when\n // fragments are never used — scenes that don't use depth/picking fragments\n // (e.g. scenes 120-126) pay zero runtime cost for this mangling table.\n const mangles: [string, string][] = [\n [\"world\", \"w\"],\n [\"view\", \"v\"],\n [\"projection\", \"p\"],\n [\"viewport\", \"vp\"],\n [\"focal\", \"f\"],\n [\"dataSize\", \"ds\"],\n [\"alpha\", \"a\"],\n [\"_pad\", \"_p\"],\n [\"vColor\", \"vc\"],\n [\"vPos\", \"vq\"],\n [\"dataUv\", \"du\"],\n [\"splatIndex\", \"si\"],\n [\"corner\", \"co\"],\n [\"center\", \"ce\"],\n [\"color\", \"cl\"],\n [\"covA\", \"ca\"],\n [\"covB\", \"cb\"],\n [\"worldPos\", \"wp\"],\n [\"modelView\", \"mv\"],\n [\"camspace\", \"cs\"],\n [\"pos2d\", \"p2\"],\n [\"bounds\", \"bd\"],\n [\"Vrk\", \"vr\"],\n [\"invZ2\", \"iz2\"],\n [\"invZ\", \"iz\"],\n [\"cov2d\", \"c2\"],\n [\"kernelSize\", \"ks\"],\n [\"radius\", \"ra\"],\n [\"epsilon\", \"ep\"],\n [\"lambda1\", \"l1\"],\n [\"lambda2\", \"l2\"],\n [\"diag\", \"dg\"],\n [\"majorAxis\", \"ma\"],\n [\"minorAxis\", \"mi\"],\n [\"vCenter\", \"vc2\"],\n ];\n\n let mangled = spliced;\n for (const [from, to] of mangles) {\n mangled = mangled.replace(new RegExp(`\\\\b${from}\\\\b`, \"g\"), to);\n }\n return mangled;\n}\n\nfunction getOrCreatePipeline(engine: EngineContext, sig: RenderTargetSignature, fragments?: readonly GsShaderFragment[]): PipelineEntry {\n const device = engine._device;\n if (!_cache || _cache.device !== device) {\n _cache = { device, modules: new Map(), entries: new Map() };\n }\n const fragKey = fragments && fragments.length > 0 ? \"|\" + fragments.map((f) => f.id).join(\",\") : \"\";\n const key = targetSignatureKey(sig) + fragKey;\n let entry = _cache.entries.get(key);\n if (entry) {\n return entry;\n }\n let module = _cache.modules.get(fragKey);\n if (!module) {\n module = device.createShaderModule({ code: fragments && fragments.length > 0 ? applyGsFragments(WGSL, fragments) : WGSL });\n _cache.modules.set(fragKey, module);\n }\n const meshBindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: SS.VERTEX | SS.FRAGMENT, buffer: { type: \"uniform\" } },\n { binding: 1, visibility: SS.VERTEX, sampler: { type: \"non-filtering\" } },\n { binding: 2, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 3, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 4, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 5, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n ],\n });\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({ bindGroupLayouts: [getSceneBindGroupLayout(engine), meshBindGroupLayout] }),\n vertex: {\n module,\n entryPoint: \"vs\",\n buffers: [\n {\n arrayStride: 8,\n stepMode: \"vertex\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n },\n {\n arrayStride: 4,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 1, offset: 0, format: \"float32\" }],\n },\n ],\n },\n fragment: {\n module,\n entryPoint: \"fs\",\n targets: [\n {\n format: sig._colorFormat!,\n blend: {\n // BJS GS material uses ALPHA_COMBINE: src*srcAlpha + dst*(1-srcAlpha)\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n },\n writeMask: CW.ALL,\n },\n ],\n },\n primitive: { topology: \"triangle-list\", cullMode: \"none\" },\n depthStencil: {\n format: sig._depthStencilFormat ?? \"depth24plus-stencil8\",\n depthCompare: sig._depthCompare ?? \"greater-equal\",\n depthWriteEnabled: false,\n },\n multisample: { count: sig._sampleCount },\n });\n entry = { pipeline, meshBindGroupLayout };\n _cache.entries.set(key, entry);\n return entry;\n}\n\n/** Build the Renderable for a GaussianSplattingMesh. Called from the deferred\n * builder installed by `addToScene`. Owns the per-mesh UBO and a per-signature\n * bind-group cache. */\nexport function buildGaussianSplattingRenderable(scene: SceneContext, mesh: GaussianSplattingMesh, fragments?: readonly GsShaderFragment[]): Renderable {\n const engine = scene.surface.engine;\n const device = engine._device;\n\n const UBO_BYTES = 16 * 4 * 3 + 8 * 4; // 3 mat4 + viewport,focal,dataSize,alpha,pad → 224 bytes\n const ubo = device.createBuffer({\n size: UBO_BYTES,\n usage: BU.UNIFORM | BU.COPY_DST,\n });\n const cpu = new F32(UBO_BYTES / 4);\n\n // dataSize is constant for the lifetime of this mesh; pre-write it.\n cpu[48 + 4] = mesh.textureWidth;\n cpu[48 + 5] = mesh.textureHeight;\n cpu[48 + 6] = 1; // alpha\n cpu[48 + 7] = 0; // pad\n\n // One per-mesh bind group per pipeline (== per RenderTargetSignature).\n const bindGroups = new Map<GPURenderPipeline, GPUBindGroup>();\n\n const getBindGroup = (entry: PipelineEntry): GPUBindGroup => {\n let bg = bindGroups.get(entry.pipeline);\n if (bg) {\n return bg;\n }\n bg = device.createBindGroup({\n layout: entry.meshBindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: ubo } },\n { binding: 1, resource: mesh._gs._sampler },\n { binding: 2, resource: mesh._gs._centersView },\n { binding: 3, resource: mesh._gs._covAView },\n { binding: 4, resource: mesh._gs._covBView },\n { binding: 5, resource: mesh._gs._colorsView },\n ],\n });\n bindGroups.set(entry.pipeline, bg);\n return bg;\n };\n\n // Per-element epsilon used to decide whether the camera/world state has\n // changed enough to warrant a fresh sort. Mirrors BJS `viewUpdateThreshold`\n // default (`_DefaultViewUpdateThreshold = 1e-4`).\n const SORT_EPS = 1e-4;\n\n const update = (): void => {\n const cam = scene.camera;\n if (!cam) {\n return;\n }\n const size = getRenderTargetSize(engine);\n const aspect = size.width / size.height;\n const view = getViewMatrix(cam) as unknown as Float32Array;\n const proj = getProjectionMatrix(cam, aspect) as unknown as Float32Array;\n const world = mesh.worldMatrix as unknown as Float32Array;\n\n cpu.set(world, 0);\n cpu.set(view, 16);\n cpu.set(proj, 32);\n cpu[48] = size.width;\n cpu[48 + 1] = size.height;\n cpu[48 + 2] = size.width * 0.5 * proj[0]!;\n cpu[48 + 3] = size.height * 0.5 * proj[5]!;\n // dataSize / alpha pre-written at construction.\n device.queue.writeBuffer(ubo, 0, cpu.buffer, 0, UBO_BYTES);\n\n // ── Sort gating ────────────────────────────────────────────\n // Mirrors BJS `_isSortStateDirty` (gaussianSplattingMeshBase.ts:849):\n // re-sort when any element of the world matrix changes, or when the\n // camera's world-space forward (view[2,6,10]) or world-space position\n // moves by more than SORT_EPS. The previous Lite gating used a single\n // `|dot - 1| ≥ 0.01` check on the modelView 3rd row, which missed\n // pure-translation moves and non-identity world matrix changes.\n if (!mesh._canPostToWorker) {\n return;\n }\n\n const camPos = getCameraPosition(cam);\n const cf0 = view[2]!,\n cf1 = view[6]!,\n cf2 = view[10]!;\n\n let dirty = false;\n const lastW = mesh._sortWorldMatrix;\n for (let i = 0; i < 16; i++) {\n if (Math.abs(lastW[i]! - world[i]!) > SORT_EPS) {\n dirty = true;\n break;\n }\n }\n if (!dirty) {\n const lastCf = mesh._sortCameraForward;\n if (Math.abs(lastCf[0]! - cf0) > SORT_EPS || Math.abs(lastCf[1]! - cf1) > SORT_EPS || Math.abs(lastCf[2]! - cf2) > SORT_EPS) {\n dirty = true;\n }\n }\n if (!dirty) {\n const lastCp = mesh._sortCameraPosition;\n if (Math.abs(lastCp[0]! - camPos.x) > SORT_EPS || Math.abs(lastCp[1]! - camPos.y) > SORT_EPS || Math.abs(lastCp[2]! - camPos.z) > SORT_EPS) {\n dirty = true;\n }\n }\n if (!dirty) {\n return;\n }\n\n mesh._sortWorldMatrix.set(world);\n mesh._sortCameraForward[0] = cf0;\n mesh._sortCameraForward[1] = cf1;\n mesh._sortCameraForward[2] = cf2;\n mesh._sortCameraPosition[0] = camPos.x;\n mesh._sortCameraPosition[1] = camPos.y;\n mesh._sortCameraPosition[2] = camPos.z;\n mesh._canPostToWorker = false;\n mesh._worker.postMessage(\n {\n m: new F32(world),\n f: new F32([cf0, cf1, cf2]),\n c: new F32([camPos.x, camPos.y, camPos.z]),\n d: mesh._depthMix,\n },\n [mesh._depthMix.buffer]\n );\n };\n\n const r: Renderable = {\n order: 200,\n isTransparent: true,\n bind(eng: EngineContext, sig: RenderTargetSignature): DrawBinding {\n const entry = getOrCreatePipeline(eng, sig, fragments);\n const bindGroup = getBindGroup(entry);\n return {\n renderable: r,\n pipeline: entry.pipeline,\n update,\n draw(pass) {\n pass.setBindGroup(1, bindGroup);\n pass.setVertexBuffer(0, mesh._gs._quadBuffer);\n pass.setVertexBuffer(1, mesh._gs._splatIndexBuffer);\n pass.setIndexBuffer(mesh._gs._indexBuffer, \"uint16\");\n pass.drawIndexed(6, mesh.vertexCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n/** Wire a `GaussianSplattingMesh` into a scene: pushes its renderable +\n * registers a disposer that frees per-mesh GPU buffers and the worker.\n * Called from the deferred builder installed by `addToScene`. */\nexport function attachGaussianSplattingMesh(scene: SceneContext, mesh: GaussianSplattingMesh, fragments?: readonly GsShaderFragment[]): void {\n const ctx = scene as unknown as { _renderables: Renderable[]; _disposables: (() => void)[]; _gsMeshes: GaussianSplattingMesh[] };\n ctx._renderables.push(buildGaussianSplattingRenderable(scene, mesh, fragments));\n ctx._gsMeshes.push(mesh);\n ctx._disposables.push(() => {\n const i = ctx._gsMeshes.indexOf(mesh);\n if (i >= 0) {\n ctx._gsMeshes.splice(i, 1);\n }\n disposeGaussianSplattingMesh(mesh);\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gaussian-splatting-pipeline.js","sources":["../../../../shaders/gaussian-splatting.wgsl?raw","../../../../src/mesh/GaussianSplatting/gaussian-splatting-pipeline.ts"],"sourcesContent":["export default \"// Gaussian Splatting — vertex + fragment WGSL.\\n// Mirrors the math in BJS gaussianSplatting.vertex.fx / .fragment.fx\\n// (static splat path: no SH, no compound transforms).\\nstruct U {\\n world: mat4x4<f32>,\\n view: mat4x4<f32>,\\n projection: mat4x4<f32>,\\n viewport: vec2<f32>,\\n focal: vec2<f32>,\\n dataSize: vec2<f32>,\\n alpha: f32,\\n _pad: f32,\\n};\\n@group(1) @binding(0) var<uniform> u: U;\\n@group(1) @binding(1) var samp: sampler;\\n@group(1) @binding(2) var centersTex: texture_2d<f32>;\\n@group(1) @binding(3) var covATex: texture_2d<f32>;\\n@group(1) @binding(4) var covBTex: texture_2d<f32>;\\n@group(1) @binding(5) var colorsTex: texture_2d<f32>;\\n\\nstruct VOut {\\n @builtin(position) pos: vec4<f32>,\\n @location(0) vColor: vec4<f32>,\\n @location(1) vPos: vec2<f32>,\\n};\\n\\nfn dataUv(idx: f32) -> vec2<f32> {\\n let y = floor(idx / u.dataSize.x);\\n let x = idx - y * u.dataSize.x;\\n return vec2<f32>((x + 0.5) / u.dataSize.x, (y + 0.5) / u.dataSize.y);\\n}\\n\\n@vertex\\nfn vs(@location(0) corner: vec2<f32>, @location(1) splatIndex: f32) -> VOut {\\n var out: VOut;\\n let uv = dataUv(splatIndex);\\n let center = textureSampleLevel(centersTex, samp, uv, 0.0).xyz;\\n let color = textureSampleLevel(colorsTex, samp, uv, 0.0);\\n let covA = textureSampleLevel(covATex, samp, uv, 0.0).xyz;\\n let covB = textureSampleLevel(covBTex, samp, uv, 0.0).xyz;\\n\\n let worldPos = u.world * vec4<f32>(center, 1.0);\\n let modelView = u.view * u.world;\\n let camspace = u.view * worldPos;\\n let pos2d = u.projection * camspace;\\n\\n let bounds = 1.2 * pos2d.w;\\n if (pos2d.z < 0.0\\n || pos2d.x < -bounds || pos2d.x > bounds\\n || pos2d.y < -bounds || pos2d.y > bounds) {\\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\\n out.vColor = vec4<f32>(0.0);\\n out.vPos = vec2<f32>(0.0);\\n return out;\\n }\\n\\n let Vrk = mat3x3<f32>(\\n vec3<f32>(covA.x, covA.y, covA.z),\\n vec3<f32>(covA.y, covB.x, covB.y),\\n vec3<f32>(covA.z, covB.y, covB.z));\\n\\n let invZ = 1.0 / camspace.z;\\n let invZ2 = invZ * invZ;\\n // J is written in the SAME transposed-storage form BJS uses in\\n // gaussianSplatting.fx — i.e. the perspective-correction terms\\n // -focal·x/z² and -focal·y/z² sit in math row 2 (columns 0,1), not in\\n // math column 2. This is required because the next two lines compute\\n // `T = transpose(mv3) * J` and `cov2d = transpose(T) * Vrk * T`,\\n // which only collapses to the correct EWA projection\\n // cov2d = (J_std · mv3) · Σ · (J_std · mv3)ᵀ\\n // when J here equals J_stdᵀ. Using J in standard form would compute\\n // the wrong product Jᵀ·mv3·Σ·mv3ᵀ·J, agreeing with BJS only for splats\\n // on the optical axis (x=y=0) and producing visible per-splat\\n // orientation differences off-centre.\\n let J = mat3x3<f32>(\\n vec3<f32>(u.focal.x * invZ, 0.0, -u.focal.x * camspace.x * invZ2),\\n vec3<f32>(0.0, u.focal.y * invZ, -u.focal.y * camspace.y * invZ2),\\n vec3<f32>(0.0, 0.0, 0.0));\\n\\n let mv3 = mat3x3<f32>(modelView[0].xyz, modelView[1].xyz, modelView[2].xyz);\\n let T = transpose(mv3) * J;\\n var cov2d = transpose(T) * Vrk * T;\\n\\n // BJS GaussianSplattingMaterial defaults: KernelSize = 0.3 (low-pass dilation\\n // — keeps sub-pixel splats from disappearing, see gaussianSplatting.fx).\\n // The +epsilon in the eigenvalues mirrors the same shader's numerical safety.\\n let kernelSize: f32 = 0.3;\\n cov2d[0][0] += kernelSize;\\n cov2d[1][1] += kernelSize;\\n\\n let mid = (cov2d[0][0] + cov2d[1][1]) * 0.5;\\n let dxy = (cov2d[0][0] - cov2d[1][1]) * 0.5;\\n let radius = length(vec2<f32>(dxy, cov2d[0][1]));\\n let epsilon: f32 = 0.0001;\\n let lambda1 = mid + radius + epsilon;\\n let lambda2 = mid - radius + epsilon;\\n if (lambda2 < 0.0) {\\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\\n out.vColor = vec4<f32>(0.0);\\n out.vPos = vec2<f32>(0.0);\\n return out;\\n }\\n\\n let diag = normalize(vec2<f32>(cov2d[0][1], lambda1 - cov2d[0][0]));\\n let majorAxis = min(sqrt(2.0 * lambda1), 1024.0) * diag;\\n let minorAxis = min(sqrt(2.0 * lambda2), 1024.0) * vec2<f32>(diag.y, -diag.x);\\n\\n let vCenter = pos2d.xy;\\n out.pos = vec4<f32>(\\n vCenter + (corner.x * majorAxis + corner.y * minorAxis) * pos2d.w / u.viewport,\\n pos2d.z, pos2d.w);\\n out.vColor = vec4<f32>(color.rgb, color.a * u.alpha);\\n out.vPos = corner;\\n return out;\\n}\\n\\n/*GS_FRAGMENT_DEFINITIONS*/\\n@fragment\\nfn fs(in: VOut) -> @location(0) vec4<f32> {\\n /*GS_FRAGMENT_MAIN_BEGIN*/\\n let A = -dot(in.vPos, in.vPos);\\n var finalColor: vec4<f32>;\\n if (A > -4.0) {\\n let B = exp(A) * in.vColor.a;\\n finalColor = vec4<f32>(in.vColor.rgb, B);\\n } else {\\n finalColor = vec4<f32>(0.0);\\n }\\n /*GS_FRAGMENT_BEFORE_FRAGCOLOR*/\\n /*GS_FRAGMENT_MAIN_END*/\\n return finalColor;\\n}\\n\"","/** Gaussian-Splatting render pipeline + Renderable.\n *\n * WGSL port of the BJS `gaussianSplatting.vertex.fx` / `.fragment.fx`\n * pair, restricted to the static splat path (no SH, no compound parts).\n * Math is unchanged: the EWA / Vrk projection of the 3D anisotropic\n * Gaussian is computed exactly as in BJS, then the per-fragment\n * density `exp(-r²) * α` is multiplied with the splat colour.\n *\n * Per-frame the binding's `update` hook:\n * 1. refreshes the per-mesh UBO (world / view / projection / focal / viewport),\n * 2. checks whether the world matrix, camera-forward (view[2,6,10]) or\n * camera world position has drifted past `SORT_EPS` since the last sort\n * (mirrors BJS `_isSortStateDirty`) and, if so, posts a fresh sort job,\n * 3. lets the GS-mesh `onmessage` handler upload the freshly-sorted\n * splatIndex buffer back to the GPU.\n *\n * The pipeline is cached per `RenderTargetSignature`. */\n\nimport { F32 } from \"../../engine/typed-arrays.js\";\nimport { BU, SS, CW } from \"../../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { SceneContext } from \"../../scene/scene-core.js\";\nimport type { Renderable, DrawBinding } from \"../../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport { getViewMatrix, getProjectionMatrix, getCameraPosition } from \"../../camera/camera.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { getRenderTargetSize } from \"../../engine/engine.js\";\nimport { disposeGaussianSplattingMesh, type GaussianSplattingMesh, type GsShaderFragment } from \"./gaussian-splatting-mesh.js\";\nimport { registerPickSource } from \"../../picking/pick-contributor.js\";\nimport WGSL from \"../../../shaders/gaussian-splatting.wgsl?raw\";\n\ninterface PipelineEntry {\n pipeline: GPURenderPipeline;\n meshBindGroupLayout: GPUBindGroupLayout;\n}\n\n// Per-device pipeline cache keyed by RenderTargetSignature string. Tree-shake-friendly\n// lazy init (no top-level `new Map`) — see GUIDANCE §4.\nlet _cache: { device: GPUDevice; modules: Map<string, GPUShaderModule>; entries: Map<string, PipelineEntry> } | null = null;\n\nexport function applyGsFragments(wgsl: string, fragments: readonly GsShaderFragment[]): string {\n const slotCode: Record<string, string> = {};\n for (const frag of fragments) {\n if (frag.helperFunctions) {\n slotCode[\"GS_FRAGMENT_DEFINITIONS\"] = (slotCode[\"GS_FRAGMENT_DEFINITIONS\"] ?? \"\") + frag.helperFunctions + \"\\n\";\n }\n for (const [slot, code] of Object.entries(frag.fragmentSlots ?? {})) {\n slotCode[slot] = (slotCode[slot] ?? \"\") + code + \"\\n\";\n }\n }\n const spliced = wgsl.replace(/\\/\\*(GS_FRAGMENT_\\w+)\\*\\//g, (_, slot: string) => slotCode[slot] ?? \"\");\n\n // Field-name mangler for the GS shader. Mirrors `mangleGaussianSplattingWgsl`\n // in `scripts/bundle-scenes-core.ts` (build-time mangling of the base WGSL).\n //\n // The build-time mangler renames struct fields like `u.projection → u.p` in\n // the bundled `gaussian-splatting.wgsl`. Fragment-plugin code (e.g.\n // `gsLinearDepthFragment`) lives in TS string constants that reference the\n // un-mangled names (`u.projection`), so without normalisation the spliced\n // WGSL has both `u.projection` (from the fragment) and `u.p` (from the base),\n // causing a WebGPU parse error.\n //\n // Running the same mangler at runtime on the final spliced string makes both\n // parts use the mangled names. The substitution is idempotent (single-letter\n // mangled names don't match the `\\bfullName\\b` regexes) and harmless in dev\n // mode (where the base WGSL is un-mangled, so this just normalises everything\n // to the mangled form — WebGPU accepts both).\n //\n // KEEP IN SYNC with `scripts/bundle-scenes-core.ts:mangleGaussianSplattingWgsl`.\n //\n // Inlined here (rather than a top-level constant) so it tree-shakes out when\n // fragments are never used — scenes that don't use depth/picking fragments\n // (e.g. scenes 120-126) pay zero runtime cost for this mangling table.\n const mangles: [string, string][] = [\n [\"world\", \"w\"],\n [\"view\", \"v\"],\n [\"projection\", \"p\"],\n [\"viewport\", \"vp\"],\n [\"focal\", \"f\"],\n [\"dataSize\", \"ds\"],\n [\"alpha\", \"a\"],\n [\"_pad\", \"_p\"],\n [\"vColor\", \"vc\"],\n [\"vPos\", \"vq\"],\n [\"dataUv\", \"du\"],\n [\"splatIndex\", \"si\"],\n [\"corner\", \"co\"],\n [\"center\", \"ce\"],\n [\"color\", \"cl\"],\n [\"covA\", \"ca\"],\n [\"covB\", \"cb\"],\n [\"worldPos\", \"wp\"],\n [\"modelView\", \"mv\"],\n [\"camspace\", \"cs\"],\n [\"pos2d\", \"p2\"],\n [\"bounds\", \"bd\"],\n [\"Vrk\", \"vr\"],\n [\"invZ2\", \"iz2\"],\n [\"invZ\", \"iz\"],\n [\"cov2d\", \"c2\"],\n [\"kernelSize\", \"ks\"],\n [\"radius\", \"ra\"],\n [\"epsilon\", \"ep\"],\n [\"lambda1\", \"l1\"],\n [\"lambda2\", \"l2\"],\n [\"diag\", \"dg\"],\n [\"majorAxis\", \"ma\"],\n [\"minorAxis\", \"mi\"],\n [\"vCenter\", \"vc2\"],\n ];\n\n let mangled = spliced;\n for (const [from, to] of mangles) {\n mangled = mangled.replace(new RegExp(`\\\\b${from}\\\\b`, \"g\"), to);\n }\n return mangled;\n}\n\nfunction getOrCreatePipeline(engine: EngineContext, sig: RenderTargetSignature, fragments?: readonly GsShaderFragment[]): PipelineEntry {\n const device = engine._device;\n if (!_cache || _cache.device !== device) {\n _cache = { device, modules: new Map(), entries: new Map() };\n }\n const fragKey = fragments && fragments.length > 0 ? \"|\" + fragments.map((f) => f.id).join(\",\") : \"\";\n const key = targetSignatureKey(sig) + fragKey;\n let entry = _cache.entries.get(key);\n if (entry) {\n return entry;\n }\n let module = _cache.modules.get(fragKey);\n if (!module) {\n module = device.createShaderModule({ code: fragments && fragments.length > 0 ? applyGsFragments(WGSL, fragments) : WGSL });\n _cache.modules.set(fragKey, module);\n }\n const meshBindGroupLayout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: SS.VERTEX | SS.FRAGMENT, buffer: { type: \"uniform\" } },\n { binding: 1, visibility: SS.VERTEX, sampler: { type: \"non-filtering\" } },\n { binding: 2, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 3, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 4, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n { binding: 5, visibility: SS.VERTEX, texture: { sampleType: \"unfilterable-float\" } },\n ],\n });\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({ bindGroupLayouts: [getSceneBindGroupLayout(engine), meshBindGroupLayout] }),\n vertex: {\n module,\n entryPoint: \"vs\",\n buffers: [\n {\n arrayStride: 8,\n stepMode: \"vertex\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n },\n {\n arrayStride: 4,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 1, offset: 0, format: \"float32\" }],\n },\n ],\n },\n fragment: {\n module,\n entryPoint: \"fs\",\n targets: [\n {\n format: sig._colorFormat!,\n blend: {\n // BJS GS material uses ALPHA_COMBINE: src*srcAlpha + dst*(1-srcAlpha)\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n },\n writeMask: CW.ALL,\n },\n ],\n },\n primitive: { topology: \"triangle-list\", cullMode: \"none\" },\n depthStencil: {\n format: sig._depthStencilFormat ?? \"depth24plus-stencil8\",\n depthCompare: sig._depthCompare ?? \"greater-equal\",\n depthWriteEnabled: false,\n },\n multisample: { count: sig._sampleCount },\n });\n entry = { pipeline, meshBindGroupLayout };\n _cache.entries.set(key, entry);\n return entry;\n}\n\n/** Build the Renderable for a GaussianSplattingMesh. Called from the deferred\n * builder installed by `addToScene`. Owns the per-mesh UBO and a per-signature\n * bind-group cache. */\nexport function buildGaussianSplattingRenderable(scene: SceneContext, mesh: GaussianSplattingMesh, fragments?: readonly GsShaderFragment[]): Renderable {\n const engine = scene.surface.engine;\n const device = engine._device;\n\n const UBO_BYTES = 16 * 4 * 3 + 8 * 4; // 3 mat4 + viewport,focal,dataSize,alpha,pad → 224 bytes\n const ubo = device.createBuffer({\n size: UBO_BYTES,\n usage: BU.UNIFORM | BU.COPY_DST,\n });\n const cpu = new F32(UBO_BYTES / 4);\n\n // dataSize is constant for the lifetime of this mesh; pre-write it.\n cpu[48 + 4] = mesh.textureWidth;\n cpu[48 + 5] = mesh.textureHeight;\n cpu[48 + 6] = 1; // alpha\n cpu[48 + 7] = 0; // pad\n\n // One per-mesh bind group per pipeline (== per RenderTargetSignature).\n const bindGroups = new Map<GPURenderPipeline, GPUBindGroup>();\n\n const getBindGroup = (entry: PipelineEntry): GPUBindGroup => {\n let bg = bindGroups.get(entry.pipeline);\n if (bg) {\n return bg;\n }\n bg = device.createBindGroup({\n layout: entry.meshBindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: ubo } },\n { binding: 1, resource: mesh._gs._sampler },\n { binding: 2, resource: mesh._gs._centersView },\n { binding: 3, resource: mesh._gs._covAView },\n { binding: 4, resource: mesh._gs._covBView },\n { binding: 5, resource: mesh._gs._colorsView },\n ],\n });\n bindGroups.set(entry.pipeline, bg);\n return bg;\n };\n\n // Per-element epsilon used to decide whether the camera/world state has\n // changed enough to warrant a fresh sort. Mirrors BJS `viewUpdateThreshold`\n // default (`_DefaultViewUpdateThreshold = 1e-4`).\n const SORT_EPS = 1e-4;\n\n const update = (): void => {\n const cam = scene.camera;\n if (!cam) {\n return;\n }\n const size = getRenderTargetSize(engine);\n const aspect = size.width / size.height;\n const view = getViewMatrix(cam) as unknown as Float32Array;\n const proj = getProjectionMatrix(cam, aspect) as unknown as Float32Array;\n const world = mesh.worldMatrix as unknown as Float32Array;\n\n cpu.set(world, 0);\n cpu.set(view, 16);\n cpu.set(proj, 32);\n cpu[48] = size.width;\n cpu[48 + 1] = size.height;\n cpu[48 + 2] = size.width * 0.5 * proj[0]!;\n cpu[48 + 3] = size.height * 0.5 * proj[5]!;\n // dataSize / alpha pre-written at construction.\n device.queue.writeBuffer(ubo, 0, cpu.buffer, 0, UBO_BYTES);\n\n // ── Sort gating ────────────────────────────────────────────\n // Mirrors BJS `_isSortStateDirty` (gaussianSplattingMeshBase.ts:849):\n // re-sort when any element of the world matrix changes, or when the\n // camera's world-space forward (view[2,6,10]) or world-space position\n // moves by more than SORT_EPS. The previous Lite gating used a single\n // `|dot - 1| ≥ 0.01` check on the modelView 3rd row, which missed\n // pure-translation moves and non-identity world matrix changes.\n if (!mesh._canPostToWorker) {\n return;\n }\n\n const camPos = getCameraPosition(cam);\n const cf0 = view[2]!,\n cf1 = view[6]!,\n cf2 = view[10]!;\n\n let dirty = false;\n const lastW = mesh._sortWorldMatrix;\n for (let i = 0; i < 16; i++) {\n if (Math.abs(lastW[i]! - world[i]!) > SORT_EPS) {\n dirty = true;\n break;\n }\n }\n if (!dirty) {\n const lastCf = mesh._sortCameraForward;\n if (Math.abs(lastCf[0]! - cf0) > SORT_EPS || Math.abs(lastCf[1]! - cf1) > SORT_EPS || Math.abs(lastCf[2]! - cf2) > SORT_EPS) {\n dirty = true;\n }\n }\n if (!dirty) {\n const lastCp = mesh._sortCameraPosition;\n if (Math.abs(lastCp[0]! - camPos.x) > SORT_EPS || Math.abs(lastCp[1]! - camPos.y) > SORT_EPS || Math.abs(lastCp[2]! - camPos.z) > SORT_EPS) {\n dirty = true;\n }\n }\n if (!dirty) {\n return;\n }\n\n mesh._sortWorldMatrix.set(world);\n mesh._sortCameraForward[0] = cf0;\n mesh._sortCameraForward[1] = cf1;\n mesh._sortCameraForward[2] = cf2;\n mesh._sortCameraPosition[0] = camPos.x;\n mesh._sortCameraPosition[1] = camPos.y;\n mesh._sortCameraPosition[2] = camPos.z;\n mesh._canPostToWorker = false;\n mesh._worker.postMessage(\n {\n m: new F32(world),\n f: new F32([cf0, cf1, cf2]),\n c: new F32([camPos.x, camPos.y, camPos.z]),\n d: mesh._depthMix,\n },\n [mesh._depthMix.buffer]\n );\n };\n\n const r: Renderable = {\n order: 200,\n isTransparent: true,\n bind(eng: EngineContext, sig: RenderTargetSignature): DrawBinding {\n const entry = getOrCreatePipeline(eng, sig, fragments);\n const bindGroup = getBindGroup(entry);\n return {\n renderable: r,\n pipeline: entry.pipeline,\n update,\n draw(pass) {\n pass.setBindGroup(1, bindGroup);\n pass.setVertexBuffer(0, mesh._gs._quadBuffer);\n pass.setVertexBuffer(1, mesh._gs._splatIndexBuffer);\n pass.setIndexBuffer(mesh._gs._indexBuffer, \"uint16\");\n pass.drawIndexed(6, mesh.vertexCount);\n return 1;\n },\n };\n },\n };\n return r;\n}\n\n/** Wire a `GaussianSplattingMesh` into a scene: pushes its renderable +\n * registers a disposer that frees per-mesh GPU buffers and the worker.\n * Called from the deferred builder installed by `addToScene`. */\nexport function attachGaussianSplattingMesh(scene: SceneContext, mesh: GaussianSplattingMesh, fragments?: readonly GsShaderFragment[]): void {\n const ctx = scene as unknown as { _renderables: Renderable[]; _disposables: (() => void)[] };\n ctx._renderables.push(buildGaussianSplattingRenderable(scene, mesh, fragments));\n const unregisterPick = registerPickSource(scene, mesh, () => import(\"../../picking/gs-picking-pipeline.js\"));\n ctx._disposables.push(() => {\n unregisterPick();\n disposeGaussianSplattingMesh(mesh);\n });\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ const TEST_EQUAL = 0;
2
+ const TEST_NOT_EQUAL = 1;
3
+ const TEST_LESS_THAN = 2;
4
+ const TEST_GREATER_THAN = 3;
5
+ const TEST_LESS_OR_EQUAL = 4;
6
+ const TEST_GREATER_OR_EQUAL = 5;
7
+ const TEST_XOR = 6;
8
+ const TEST_OR = 7;
9
+ const TEST_AND = 8;
10
+ function withinEpsilon(a, b, epsilon) {
11
+ return Math.abs(a - b) <= epsilon;
12
+ }
13
+ function evaluate(test, left, right, epsilon) {
14
+ switch (test) {
15
+ case TEST_EQUAL:
16
+ return withinEpsilon(left, right, epsilon);
17
+ case TEST_NOT_EQUAL:
18
+ return !withinEpsilon(left, right, epsilon);
19
+ case TEST_LESS_THAN:
20
+ return left < right + epsilon;
21
+ case TEST_GREATER_THAN:
22
+ return left > right - epsilon;
23
+ case TEST_LESS_OR_EQUAL:
24
+ return left <= right + epsilon;
25
+ case TEST_GREATER_OR_EQUAL:
26
+ return left >= right - epsilon;
27
+ case TEST_XOR:
28
+ return !!left && !right || !left && !!right;
29
+ case TEST_OR:
30
+ return !!left || !!right;
31
+ case TEST_AND:
32
+ return !!left && !!right;
33
+ default:
34
+ return false;
35
+ }
36
+ }
37
+ const particleConditionBlock = {
38
+ build(block, ctx) {
39
+ const test = typeof block.serialized.test === "number" ? block.serialized.test : TEST_EQUAL;
40
+ const epsilon = typeof block.serialized.epsilon === "number" ? block.serialized.epsilon : 0;
41
+ const leftGetter = ctx.input(block, "left", () => 0);
42
+ const rightGetter = ctx.input(block, "right", () => 0);
43
+ const ifTrueGetter = ctx.input(block, "ifTrue", () => 1);
44
+ const ifFalseGetter = ctx.input(block, "ifFalse", () => 0);
45
+ const getter = (state) => {
46
+ const left = leftGetter(state);
47
+ const right = rightGetter(state);
48
+ return evaluate(test, left, right, epsilon) ? ifTrueGetter(state) : ifFalseGetter(state);
49
+ };
50
+ ctx.setOutput(block.id, "output", getter);
51
+ }
52
+ };
53
+
54
+ export { particleConditionBlock };
55
+ //# sourceMappingURL=particle-condition-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"particle-condition-block.js","sources":["../../../../../src/particle/node/blocks/particle-condition-block.ts"],"sourcesContent":["import type { ParticleBlockEvaluator, NpeGetter } from \"../npe-types.js\";\n\n// Comparison tests, matching the BJS `ParticleConditionBlockTests` enum order.\nconst TEST_EQUAL = 0;\nconst TEST_NOT_EQUAL = 1;\nconst TEST_LESS_THAN = 2;\nconst TEST_GREATER_THAN = 3;\nconst TEST_LESS_OR_EQUAL = 4;\nconst TEST_GREATER_OR_EQUAL = 5;\nconst TEST_XOR = 6;\nconst TEST_OR = 7;\nconst TEST_AND = 8;\n\n/** Mirrors BJS `WithinEpsilon`: true when the absolute difference of a and b is within epsilon. */\nfunction withinEpsilon(a: number, b: number, epsilon: number): boolean {\n return Math.abs(a - b) <= epsilon;\n}\n\nfunction evaluate(test: number, left: number, right: number, epsilon: number): boolean {\n switch (test) {\n case TEST_EQUAL:\n return withinEpsilon(left, right, epsilon);\n case TEST_NOT_EQUAL:\n return !withinEpsilon(left, right, epsilon);\n case TEST_LESS_THAN:\n return left < right + epsilon;\n case TEST_GREATER_THAN:\n return left > right - epsilon;\n case TEST_LESS_OR_EQUAL:\n return left <= right + epsilon;\n case TEST_GREATER_OR_EQUAL:\n return left >= right - epsilon;\n case TEST_XOR:\n return (!!left && !right) || (!left && !!right);\n case TEST_OR:\n return !!left || !!right;\n case TEST_AND:\n return !!left && !!right;\n default:\n return false;\n }\n}\n\n/**\n * `ParticleConditionBlock` — compares `left` against `right` with a selectable test (`test` property) and a\n * tolerance (`epsilon`), outputting `ifTrue` when the test passes and `ifFalse` otherwise. Mirrors BJS\n * `ParticleConditionBlock`; used, e.g., to brake a particle's velocity once its speed exceeds the\n * velocity-limit gradient. Unconnected inputs default to BJS values (right 0, ifTrue 1, ifFalse 0).\n */\nexport const particleConditionBlock: ParticleBlockEvaluator = {\n build(block, ctx) {\n const test = typeof block.serialized.test === \"number\" ? block.serialized.test : TEST_EQUAL;\n const epsilon = typeof block.serialized.epsilon === \"number\" ? block.serialized.epsilon : 0;\n const leftGetter = ctx.input(block, \"left\", () => 0);\n const rightGetter = ctx.input(block, \"right\", () => 0);\n const ifTrueGetter = ctx.input(block, \"ifTrue\", () => 1);\n const ifFalseGetter = ctx.input(block, \"ifFalse\", () => 0);\n\n const getter: NpeGetter = (state) => {\n const left = leftGetter(state) as number;\n const right = rightGetter(state) as number;\n return evaluate(test, left, right, epsilon) ? ifTrueGetter(state) : ifFalseGetter(state);\n };\n ctx.setOutput(block.id, \"output\", getter);\n },\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ const OP_ROUND = 0;
2
+ const OP_CEIL = 1;
3
+ const OP_FLOOR = 2;
4
+ const OP_TRUNCATE = 3;
5
+ function toInt(operation, value) {
6
+ switch (operation) {
7
+ case OP_CEIL:
8
+ return Math.ceil(value);
9
+ case OP_FLOOR:
10
+ return Math.floor(value);
11
+ case OP_TRUNCATE:
12
+ return Math.trunc(value);
13
+ case OP_ROUND:
14
+ default:
15
+ return Math.round(value);
16
+ }
17
+ }
18
+ const particleFloatToIntBlock = {
19
+ build(block, ctx) {
20
+ const operation = typeof block.serialized.operation === "number" ? block.serialized.operation : OP_ROUND;
21
+ const inputGetter = ctx.input(block, "input", () => 0);
22
+ const getter = (state) => toInt(operation, inputGetter(state));
23
+ ctx.setOutput(block.id, "output", getter);
24
+ }
25
+ };
26
+
27
+ export { particleFloatToIntBlock };
28
+ //# sourceMappingURL=particle-float-to-int-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"particle-float-to-int-block.js","sources":["../../../../../src/particle/node/blocks/particle-float-to-int-block.ts"],"sourcesContent":["import type { ParticleBlockEvaluator, NpeGetter } from \"../npe-types.js\";\n\n// Operations, matching the BJS `ParticleFloatToIntBlockOperations` enum order.\nconst OP_ROUND = 0;\nconst OP_CEIL = 1;\nconst OP_FLOOR = 2;\nconst OP_TRUNCATE = 3;\n\nfunction toInt(operation: number, value: number): number {\n switch (operation) {\n case OP_CEIL:\n return Math.ceil(value);\n case OP_FLOOR:\n return Math.floor(value);\n case OP_TRUNCATE:\n return Math.trunc(value);\n case OP_ROUND:\n default:\n return Math.round(value);\n }\n}\n\n/**\n * `ParticleFloatToIntBlock` — converts a float input to an int via round/ceil/floor/truncate (selected by\n * the `operation` property). Mirrors BJS `ParticleFloatToIntBlock`; used, e.g., to turn a per-frame emit-rate\n * gradient value into an integer particle count.\n */\nexport const particleFloatToIntBlock: ParticleBlockEvaluator = {\n build(block, ctx) {\n const operation = typeof block.serialized.operation === \"number\" ? block.serialized.operation : OP_ROUND;\n const inputGetter = ctx.input(block, \"input\", () => 0);\n const getter: NpeGetter = (state) => toInt(operation, inputGetter(state) as number);\n ctx.setOutput(block.id, \"output\", getter);\n },\n};\n"],"names":[],"mappings":"AAGA,MAAM,QAAA,GAAW,CAAA;AACjB,MAAM,OAAA,GAAU,CAAA;AAChB,MAAM,QAAA,GAAW,CAAA;AACjB,MAAM,WAAA,GAAc,CAAA;AAEpB,SAAS,KAAA,CAAM,WAAmB,KAAA,EAAuB;AACrD,EAAA,QAAQ,SAAA;AAAW,IACf,KAAK,OAAA;AACD,MAAA,OAAO,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,IAC1B,KAAK,QAAA;AACD,MAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAAA,IAC3B,KAAK,WAAA;AACD,MAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAAA,IAC3B,KAAK,QAAA;AAAA,IACL;AACI,MAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAAA;AAEnC;AAOO,MAAM,uBAAA,GAAkD;AAAA,EAC3D,KAAA,CAAM,OAAO,GAAA,EAAK;AACd,IAAA,MAAM,SAAA,GAAY,OAAO,KAAA,CAAM,UAAA,CAAW,cAAc,QAAA,GAAW,KAAA,CAAM,WAAW,SAAA,GAAY,QAAA;AAChG,IAAA,MAAM,cAAc,GAAA,CAAI,KAAA,CAAM,KAAA,EAAO,OAAA,EAAS,MAAM,CAAC,CAAA;AACrD,IAAA,MAAM,SAAoB,CAAC,KAAA,KAAU,MAAM,SAAA,EAAW,WAAA,CAAY,KAAK,CAAW,CAAA;AAClF,IAAA,GAAA,CAAI,SAAA,CAAU,KAAA,CAAM,EAAA,EAAI,QAAA,EAAU,MAAM,CAAA;AAAA,EAC5C;AACJ;;;;"}