Add equirectangular projection for WebP output and refactor compute shaders into chunks#247
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a native 360°×180° equirectangular projection mode to the WebP image output (
--projection equirect) so users can export a panorama of a Gaussian-splat scene from a single camera position, and reorganizes the GPU rasterizer's eight compute shaders out of one ~1600-LOC file into per-shader source files plus 14 small WGSL chunks undersrc/lib/gpu/shaders/, using PlayCanvas'scincludes/cdefinespreprocessor (seeengine/src/platform/graphics/shader.js) so chunk files are pure WGSL and projection/SH-band variants flip via#ifdef PROJECTION_EQUIRECT/#ifdef SH_BAND_{1,2,3}.The equirect path is implemented inside the existing tile-binning GPU rasterizer rather than as a cube-face stitch: the project shader swaps the perspective screen mapping and EWA Jacobian for spherical (
atan2/asin) equivalents, the CPU depth sort uses radial distance, the tile-bin emit-pairs shader wraps the X tile range across the ±π longitude seam (modular tile indices), and the rasterize-binned shader wraps per-pixeldxinto[-W/2, W/2]so seam-straddling splats pull their footprint from the nearer copy. APOLE_EPSclamp onrxzkeeps the latitude Jacobian bounded near zenith/nadir. The structure follows the PlayCanvas engine's own fisheye-projection compute path incompute-gsplat-common.jsas a precedent.The chunk refactor consolidates the JS↔WGSL uniform layout into a single co-located
uniforms.ts(struct chunk + matchingUniformFormat[]), moves scalar tunables fromrender/config.ts(TILE_SIZE,SIGMA_CUTOFF,JACOBIAN_LIMIT_FACTOR, etc.) into a shared WGSLconstchunk so the shader files contain no${...}template interpolation, and extracts the projection screen-mapping, Jacobian, tile-AABB, SH-band-evaluation, quaternion-to-rotation, and 3D-covariance blocks into named chunks.gpu-splat-rasterizer.tsshrinks from ~1600 to ~800 LOC (orchestrator class only).A small follow-up replaces magic literals in
gpu-dilation.ts(0u/1u/2u/0x9E3779B9u) with namedBLOCK_EMPTY/BLOCK_SOLID/BLOCK_MIXED/FIBONACCI_HASHWGSLconsts for readability in the extract and compact shaders.Test plan
npm run lint && npm run build && npm test— full suite (490 tests) passes.node --import tsx --test test/render-golden.test.mjsproduces byte-exact matches for both committed fixtures (tiny.webp320×240 andmid.webp640×360), confirming the pinhole path is unchanged.splat-transform input.ply --projection equirect --camera 0,1,0 --look-at 0,1,1 out.webp(default 2048×1024), then open in a panorama viewer (e.g. Pannellum) and verify the horizon sits at mid-image, the--look-atdirection maps to image-x = W/2, and the left/right edges of the image are continuous (no visible seam).--fovwith--projection equirecterrors out; non-2:1--resolutionerrors out; default resolution is 2048×1024 when neither width nor height is supplied.splat-transform input.ply --voxel-params 0.5,0.1 --voxel-external-fill 1.6 --seed-pos 100,100,100 out.voxel.jsonproduces a byte-identical.voxel.json+.voxel.binpair to a pre-PR run onmain.