fix(GSplat): Multiple Critical Voxelization and Compound Bugs#18496
fix(GSplat): Multiple Critical Voxelization and Compound Bugs#18496raymondyfei wants to merge 16 commits into
Conversation
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Please make sure to label your PR with "bug", "new feature" or "breaking change" label(s). |
|
Snapshot stored with reference name: Test environment: To test a playground add it to the URL, for example: https://snapshots-cvgtc2eugrd3cgfd.z01.azurefd.net/refs/pull/18496/merge/index.html#WGZLGJ#4600 Links to test your changes to core in the published versions of the Babylon tools (does not contain changes you made to the tools themselves): https://playground.babylonjs.com/?snapshot=refs/pull/18496/merge To test the snapshot in the playground with a playground ID add it after the snapshot query string: https://playground.babylonjs.com/?snapshot=refs/pull/18496/merge#BCU1XR#0 If you made changes to the sandbox or playground in this PR, additional comments will be generated soon containing links to the dev versions of those tools. |
🟢 Memory Leak Test Results13 passed, 0 leaked out of 13 scenarios 🟢 All memory leak tests passed — no leaks detected. Passed Scenarios (13)
|
|
WebGL2 visualization test reporter: |
⚡ Performance Test Results🟢 All performance tests passed — no regressions detected. |
|
Visualization tests for WebGPU |
This PR has fixed a series of critical bugs about Gaussian splat rendering, in particular when voxelization and compound splats are both involved.
1. Compound mesh bounding box was wrong for voxelization
The base
_updateBoundingInfo()computed bounds aslocal AABB × world matrix, which isincorrect for compound meshes where each part has an independent proxy node with its own
transform.
getHierarchyBoundingVectors()also never reached proxy nodes since they aren'tparented to the compound. Fixed by overriding both methods to transform all 8 corners of each
proxy's world-space AABB through the inverse compound world matrix.
2. Invisible parts inflated the voxel grid
Parts with
partVisibility = 0still contributed to scene bounds used to size the IBL shadowvoxel grid, even if they are invisible and should not be rendered. Fixed in two places:
getHierarchyBoundingVectors()now skips invisible parts,and the voxel vertex shader early-exits by pushing invisible splats outside the NDC cube
(
gl_Position = vec4(2,2,2,1)).3. SH buffers initialized to zero instead of neutral
new Uint8Array()zero-fills, but the shader'sdecompose()encodes0.0as byte128— sozero decodes to
-1.0. When merging a low-SH-degree mesh into a higher-SH-degree compound, paddingbytes for missing bands produced wrong colors. Extracted a shared
AllocateShBuffers()helperthat pre-fills with
128, used consistently across all SH allocation sites. In this way, we can correctly merge splats with different SH degrees into a compound.4. Wrong SH texture count in compound merge
The merge path allocated
shDegreetextures (one per band), but the correct count isceil(((degree+1)² − 1) × 3 / texelCapacity). Fixed in both the incremental and full-rebuildmerge paths.
5. G-buffer renderer misread the splat vertex data
GeometryBufferRendererpassed GSplat sub-meshes to the generic geometry shader, whichinterpreted the splat index stored in
position.zas a world-space Z coordinate, producinggarbage positions and normals, causing the IBL shadows to flicker randomly during rendering. Fixed with an early-exit in
shouldRender()forGaussianSplattingMesh(whichGaussianSplattingCompoundMeshreturns by design, covering both) since it does NOT support G-buffer renderer yet.6.
needsRotationScaleTexturesnot forwarded; missing_shDegreeGaussianSplattingCompoundMesh's constructor didn't exposeneedsRotationScaleTextures, andenabling it post-load called
updateData()withoutthis._shDegree, causing the compound mesh to ignore any spherical harmonics when later attached as caster to an IBL shadow (which triggers theupdateData()). Both fixed.7. Proxy view used texture count instead of SH degree
_makeViewForProxyset_shDegreetothis._shData?.length(number of textures) instead ofthis._shDegree(actual degree). These differ because multiple bands share a texture. Fixed.8. IBL shadows
updateSceneBoundsguard orderingThe empty-mesh guard ran after
voxelGridSizewas computed from sentinel values. When allparts were hidden, the bounds stayed at the sentinels and triggered a spurious warning. Fixed:
early-return before touching
voxelGridSizewhen no meshes; silent return preserving the lastvalid scale when bounds are sentinels.
Tests
Three new screenshot tests covering the edge cases that previously failed: