gaussian-splat-lite 1.1.4 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -1
- package/dist/gaussian-splat-lite.cjs +49 -77
- package/dist/gaussian-splat-lite.cjs.map +1 -1
- package/dist/gaussian-splat-lite.min.cjs +33 -49
- package/dist/gaussian-splat-lite.min.cjs.map +1 -1
- package/dist/gaussian-splat-lite.module.js +49 -77
- package/dist/gaussian-splat-lite.module.js.map +1 -1
- package/dist/gaussian-splat-lite.module.min.js +1437 -1475
- package/dist/gaussian-splat-lite.module.min.js.map +1 -1
- package/dist/types/rendering/GaussianSplatRenderer.d.cts +3 -23
- package/dist/types/rendering/GaussianSplatRenderer.d.ts +3 -23
- package/dist/types/rendering/SplatGeometry.d.cts +2 -3
- package/dist/types/rendering/SplatGeometry.d.ts +2 -3
- package/dist/types/rendering/backend.d.cts +0 -2
- package/dist/types/rendering/backend.d.ts +0 -2
- package/dist/types/rendering/uniforms.d.cts +3 -6
- package/dist/types/rendering/uniforms.d.ts +3 -6
- package/docs/GaussianSplatRenderer.md +0 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.1.5] - 2026-09-23
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- WebGL and WebGL2 fallback now draw 128 Splats per instance, matching native WebGPU's quad batching.
|
|
15
|
+
|
|
16
|
+
### Removed
|
|
17
|
+
|
|
18
|
+
- Removed the `vertexShader`, `fragmentShader`, and `extraUniforms` options from `GaussianSplatRenderer`. All backends use the built-in Splat shaders.
|
|
19
|
+
|
|
10
20
|
## [1.1.4] - 2026-09-23
|
|
11
21
|
|
|
12
22
|
### Changed
|
|
@@ -402,7 +412,8 @@ and this project follows [Semantic Versioning](https://semver.org/).
|
|
|
402
412
|
|
|
403
413
|
- Initial public release of the Three.js Gaussian Splatting renderer.
|
|
404
414
|
|
|
405
|
-
[Unreleased]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.1.
|
|
415
|
+
[Unreleased]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.1.5...HEAD
|
|
416
|
+
[1.1.5]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.1.4...v1.1.5
|
|
406
417
|
[1.1.4]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.1.3...v1.1.4
|
|
407
418
|
[1.1.3]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.1.2...v1.1.3
|
|
408
419
|
[1.1.2]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v1.1.1...v1.1.2
|
|
@@ -24352,6 +24352,8 @@ function makeSplatUniforms() {
|
|
|
24352
24352
|
encodeLinear: { value: false },
|
|
24353
24353
|
// Mirrors the material flag for WebGPU's output premultiplication.
|
|
24354
24354
|
premultipliedAlpha: { value: true },
|
|
24355
|
+
// Exact draw count; the final instance may contain unused quads.
|
|
24356
|
+
splatCount: { value: 0 },
|
|
24355
24357
|
// Back-to-front sort ordering of splat indices
|
|
24356
24358
|
ordering: { type: "t", value: emptyOrdering },
|
|
24357
24359
|
// Gsplat collection to render
|
|
@@ -24359,10 +24361,6 @@ function makeSplatUniforms() {
|
|
|
24359
24361
|
splats2: { type: "t", value: emptySplats },
|
|
24360
24362
|
stochasticSeeds: { type: "t", value: emptySplats },
|
|
24361
24363
|
stochasticNoise: { value: createBlueNoiseTexture() },
|
|
24362
|
-
// Time in seconds for time-based effects
|
|
24363
|
-
time: { value: 0 },
|
|
24364
|
-
// Delta time in seconds since last frame
|
|
24365
|
-
deltaTime: { value: 0 },
|
|
24366
24364
|
// Sorting-free stochastic transparency for automatic or forced frames
|
|
24367
24365
|
stochastic: { value: false },
|
|
24368
24366
|
// NDC jitter (xy) and blue-noise offset (zw), owned by StochasticTAAPass.
|
|
@@ -24456,8 +24454,8 @@ class FullScreenQuad {
|
|
|
24456
24454
|
}
|
|
24457
24455
|
}
|
|
24458
24456
|
var splatDefines_default = "const uint SPLAT_TEX_WIDTH_BITS = 11u;\nconst uint SPLAT_TEX_HEIGHT_BITS = 11u;\nconst uint SPLAT_TEX_LAYER_BITS = SPLAT_TEX_WIDTH_BITS + SPLAT_TEX_HEIGHT_BITS;\n\nconst uint SPLAT_TEX_WIDTH = 1u << SPLAT_TEX_WIDTH_BITS;\nconst uint SPLAT_TEX_HEIGHT = 1u << SPLAT_TEX_HEIGHT_BITS;\n\nconst uint SPLAT_TEX_WIDTH_MASK = SPLAT_TEX_WIDTH - 1u;\nconst uint SPLAT_TEX_HEIGHT_MASK = SPLAT_TEX_HEIGHT - 1u;\n\nconst float PI = 3.1415926535897932384626433832795;\n\nvec3 srgbToLinear(vec3 rgb) {\n \n return mix(\n pow(rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)),\n rgb * 0.0773993808, lessThanEqual(rgb, vec3(0.04045)));\n}\n\nuint encodeQuatOctXy1010R12(vec4 q) {\n \n if (q.w < 0.0) {\n q = -q;\n }\n \n float theta = 2.0 * acos(clamp(q.w, 0.0, 1.0));\n\n \n \n \n float sum = abs(q.x) + abs(q.y) + abs(q.z);\n \n vec2 p = (sum < 1e-6) ? vec2(1.0, 0.0) : q.xy / sum;\n \n if (q.z < 0.0) {\n float oldPx = p.x;\n p.x = (1.0 - abs(p.y)) * (p.x >= 0.0 ? 1.0 : -1.0);\n p.y = (1.0 - abs(oldPx)) * (p.y >= 0.0 ? 1.0 : -1.0);\n }\n \n float u_f = p.x * 0.5 + 0.5;\n float v_f = p.y * 0.5 + 0.5;\n \n uint quantU = uint(clamp(round(u_f * 1023.0), 0.0, 1023.0));\n uint quantV = uint(clamp(round(v_f * 1023.0), 0.0, 1023.0));\n \n \n \n uint angleInt = uint(clamp(round((theta / PI) * 4095.0), 0.0, 4095.0));\n \n \n return (angleInt << 20u) | (quantV << 10u) | quantU;\n}\n\nvec4 decodeQuatOctXy1010R12(uint encoded) {\n \n uint quantU = encoded & uint(0x3FFu); \n uint quantV = (encoded >> 10u) & uint(0x3FFu); \n uint angleInt = encoded >> 20u; \n\n \n float u_f = float(quantU) / 1023.0;\n float v_f = float(quantV) / 1023.0;\n vec2 f = vec2(u_f * 2.0 - 1.0, v_f * 2.0 - 1.0);\n\n vec3 axis = vec3(f.xy, 1.0 - abs(f.x) - abs(f.y));\n float t = max(-axis.z, 0.0);\n axis.x += (axis.x >= 0.0) ? -t : t;\n axis.y += (axis.y >= 0.0) ? -t : t;\n axis = normalize(axis);\n \n \n float theta = (float(angleInt) / 4095.0) * PI;\n float halfTheta = theta * 0.5;\n float s = sin(halfTheta);\n float w = cos(halfTheta);\n \n return vec4(axis * s, w);\n}\n\nvec3 decodeSplatCenter(uvec4 splatData) {\n return vec3(\n uintBitsToFloat(splatData.x),\n uintBitsToFloat(splatData.y),\n uintBitsToFloat(splatData.z)\n );\n}\n\nvoid encodeSplatLnScale(\n out uvec4 splatData, out uvec4 splatData2,\n vec3 center, vec3 lnScales, vec4 quaternion, vec4 rgba, float shapeAmount\n) {\n splatData.x = floatBitsToUint(center.x);\n splatData.y = floatBitsToUint(center.y);\n splatData.z = floatBitsToUint(center.z);\n splatData.w = packHalf2x16(clamp(vec2(rgba.a, shapeAmount), 0.0, 1.0));\n\n splatData2.x = packHalf2x16(rgba.rg);\n splatData2.y = packHalf2x16(vec2(rgba.b, lnScales.x));\n splatData2.z = packHalf2x16(lnScales.yz);\n splatData2.w = encodeQuatOctXy1010R12(quaternion);\n}\n\nvec2 decodeSplatAlphaShapeAmount(uvec4 splatData) {\n return unpackHalf2x16(splatData.w);\n}\n\nvoid decodeSplatAttributesLnScale(\n uvec4 splatData2,\n float alpha,\n out vec3 lnScales, out vec4 quaternion, out vec4 rgba\n) {\n rgba.a = alpha;\n\n rgba.rg = unpackHalf2x16(splatData2.x);\n vec2 split = unpackHalf2x16(splatData2.y);\n rgba.b = split.x;\n lnScales.x = split.y;\n lnScales.yz = unpackHalf2x16(splatData2.z);\n quaternion = decodeQuatOctXy1010R12(splatData2.w);\n}\n\nvec3 decodeSplatShRgb(uint encoded) {\n uint biasedBase = (encoded >> 27u) & 0x1fu;\n \n \n float divisor = uintBitsToFloat((biasedBase + 112u) << 23u) / 255.0;\n\n vec3 rgb = vec3(uvec3(encoded & 0xffu, (encoded >> 8u) & 0xffu, (encoded >> 16u) & 0xffu));\n rgb *= divisor;\n\n return vec3(\n ((encoded & 0x1000000u) != 0u) ? -rgb.r : rgb.r,\n ((encoded & 0x2000000u) != 0u) ? -rgb.g : rgb.g,\n ((encoded & 0x4000000u) != 0u) ? -rgb.b : rgb.b\n );\n}\n\nvec3 quatVec(vec4 q, vec3 v) {\n \n vec3 t = 2.0 * cross(q.xyz, v);\n return v + q.w * t + cross(q.xyz, t);\n}\n\nvec4 quatQuat(vec4 q1, vec4 q2) {\n return vec4(\n q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,\n q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x,\n q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w,\n q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z\n );\n}\n\nmat3 scaleQuaternionToMatrix(vec3 s, vec4 q) {\n \n return mat3(\n s.x * (1.0 - 2.0 * (q.y * q.y + q.z * q.z)),\n s.x * (2.0 * (q.x * q.y + q.w * q.z)),\n s.x * (2.0 * (q.x * q.z - q.w * q.y)),\n s.y * (2.0 * (q.x * q.y - q.w * q.z)),\n s.y * (1.0 - 2.0 * (q.x * q.x + q.z * q.z)),\n s.y * (2.0 * (q.y * q.z + q.w * q.x)),\n s.z * (2.0 * (q.x * q.z + q.w * q.y)),\n s.z * (2.0 * (q.y * q.z - q.w * q.x)),\n s.z * (1.0 - 2.0 * (q.x * q.x + q.y * q.y))\n );\n}\n\nivec3 splatTexCoord(int index) {\n uint x = uint(index) & SPLAT_TEX_WIDTH_MASK;\n uint y = (uint(index) >> SPLAT_TEX_WIDTH_BITS) & SPLAT_TEX_HEIGHT_MASK;\n uint z = uint(index) >> SPLAT_TEX_LAYER_BITS;\n return ivec3(x, y, z);\n}";
|
|
24459
|
-
var splatFragment_default = "precision highp float;\nprecision highp int;\n\
|
|
24460
|
-
var splatVertex_default = "precision highp float;\nprecision highp int;\nprecision highp usampler2DArray;\n\n#include <splatDefines>\n\nout vec4 vRgba;\nout vec2 vSplatUv;\nflat out uint vStochasticHash;\nflat out float vSupportRadiusSquared;\nflat out float vKernelPower;\n\nuniform vec2 renderSize;\nuniform vec4 renderToViewQuat;\nuniform vec3 renderToViewPos;\n\nuniform float renderToViewScale;\nuniform float maxStdDev;\nuniform float minPixelRadius;\nuniform float maxPixelRadius;\nuniform float
|
|
24457
|
+
var splatFragment_default = "precision highp float;\nprecision highp int;\n\nuniform float minAlpha;\nuniform bool stochastic;\nuniform vec4 stochasticTemporalSample;\nuniform bool stochasticResolve;\nuniform bool depthOnly;\nuniform highp usampler2D stochasticNoise;\nuniform vec2 viewportOrigin;\n\nout vec4 fragColor;\n\nin vec4 vRgba;\nin vec2 vSplatUv;\nflat in uint vStochasticHash;\nflat in float vSupportRadiusSquared;\nflat in float vKernelPower;\n\n#include <logdepthbuf_pars_fragment>\n\nvoid main() {\n vec4 rgba = vRgba;\n\n float z2 = dot(vSplatUv, vSplatUv);\n if (z2 > vSupportRadiusSquared) {\n discard;\n }\n\n float kernelAlpha = exp(-0.5 * z2);\n if (vKernelPower != 0.0) {\n kernelAlpha = 1.0 - pow(1.0 - kernelAlpha, vKernelPower);\n }\n rgba.a *= kernelAlpha;\n\n if (rgba.a < minAlpha) {\n discard;\n }\n #if !GSL_SORTED_FRAGMENT\n if (stochastic || depthOnly) {\n \n uvec2 pixel = uvec2(gl_FragCoord.xy - viewportOrigin);\n uvec2 offset = uvec2(vStochasticHash, vStochasticHash >> 5u);\n if (stochastic && !depthOnly) offset += uvec2(stochasticTemporalSample.zw);\n ivec2 coord = ivec2((pixel + offset) & uvec2(31u));\n float randomValue = (float(texelFetch(stochasticNoise, coord, 0).r) + 0.5) / 1024.0;\n if (randomValue >= rgba.a) {\n discard;\n }\n\n if (depthOnly) {\n fragColor = vec4(0.0);\n #include <logdepthbuf_fragment>\n return;\n }\n }\n if (stochastic) {\n \n \n fragColor = vec4(rgba.rgb, stochasticResolve ? 2.0 : 1.0);\n #include <logdepthbuf_fragment>\n return;\n }\n #endif\n\n #ifdef PREMULTIPLIED_ALPHA\n fragColor = vec4(rgba.rgb * rgba.a, rgba.a);\n #else\n fragColor = rgba;\n #endif\n\n #include <logdepthbuf_fragment>\n}";
|
|
24458
|
+
var splatVertex_default = "precision highp float;\nprecision highp int;\nprecision highp usampler2DArray;\n\n#include <splatDefines>\n\nout vec4 vRgba;\nout vec2 vSplatUv;\nflat out uint vStochasticHash;\nflat out float vSupportRadiusSquared;\nflat out float vKernelPower;\n\nuniform vec2 renderSize;\nuniform vec4 renderToViewQuat;\nuniform vec3 renderToViewPos;\n\nuniform float renderToViewScale;\nuniform float maxStdDev;\nuniform float minPixelRadius;\nuniform float maxPixelRadius;\nuniform float minAlpha;\nuniform float blurAmount;\nuniform float preBlurAmount;\nuniform float clipXY;\nuniform float focalAdjustment;\nuniform bool stochastic;\nuniform vec4 stochasticTemporalSample;\nuniform bool encodeLinear;\nuniform bool depthOnly;\nuniform uint splatCount;\n\nuniform usampler2D ordering;\nuniform usampler2DArray splats;\nuniform usampler2DArray splats2;\nuniform usampler2DArray stochasticSeeds;\n\nbool isPerspectiveMatrix( mat4 m ) {\n return m[ 2 ][ 3 ] == -1.0;\n}\n\n#include <logdepthbuf_pars_vertex>\n\nuint hashU32(uint value) {\n value ^= value >> 16u;\n value *= 0x7feb352du;\n value ^= value >> 15u;\n value *= 0x846ca68bu;\n value ^= value >> 16u;\n return value;\n}\n\nfloat gaussianSupportRadius(float alpha, float maximumRadius) {\n if (minAlpha <= 0.0) return maximumRadius;\n float radiusSquared = 2.0 * log(alpha / minAlpha);\n return min(maximumRadius, sqrt(max(0.0, radiusSquared)));\n}\n\nfloat wideSupportRadius(float alpha, float power, float maximumRadius) {\n if (minAlpha <= 0.0) return maximumRadius;\n \n \n float radiusSquared = 2.0 * log(alpha * power / minAlpha);\n return min(maximumRadius, sqrt(max(0.0, radiusSquared)));\n}\n\nvoid main() {\n \n gl_Position = vec4(0.0, 0.0, 2.0, 1.0);\n\n uint index = uint(gl_InstanceID) * uint(SPLATS_PER_INSTANCE) + uint(position.z);\n if (index >= splatCount) return;\n\n uint splatIndex;\n if (stochastic || depthOnly) {\n \n splatIndex = index;\n } else {\n ivec2 orderingCoord = ivec2(int((index >> 2u) & 4095u), int(index >> 14u));\n splatIndex = texelFetch(ordering, orderingCoord, 0)[index & 3u];\n }\n if (splatIndex == 0xffffffffu) {\n \n return;\n }\n\n ivec3 texCoord = splatTexCoord(int(splatIndex));\n uvec4 splat1 = texelFetch(splats, texCoord, 0);\n vec2 alphaShapeAmount = decodeSplatAlphaShapeAmount(splat1);\n float alpha = alphaShapeAmount.x;\n if ((alpha == 0.0) || (alpha < minAlpha)) {\n return;\n }\n vec3 center = decodeSplatCenter(splat1);\n \n vec3 viewCenter = renderToViewScale * quatVec(renderToViewQuat, center) + renderToViewPos;\n\n \n if (viewCenter.z >= 0.0) {\n return;\n }\n\n \n vec4 clipCenter = projectionMatrix * vec4(viewCenter, 1.0);\n\n \n if (abs(clipCenter.z) >= clipCenter.w) {\n return;\n }\n\n \n float clip = clipXY * clipCenter.w;\n if (abs(clipCenter.x) > clip || abs(clipCenter.y) > clip) {\n return;\n }\n\n \n \n vec3 lnScales;\n vec4 quaternion, rgba;\n uvec4 splat2 = texelFetch(splats2, texCoord, 0);\n decodeSplatAttributesLnScale(splat2, alpha, lnScales, quaternion, rgba);\n vec3 scales = exp(lnScales);\n if (all(equal(scales, vec3(0.0)))) {\n return;\n }\n\n \n rgba.rgb = max(rgba.rgb, vec3(0.0));\n\n \n \n float kernelShape = 1.0 + 4.0 * min(alphaShapeAmount.y, 1.0);\n \n \n float kernelPower = 0.0;\n if (kernelShape > 1.0) {\n kernelPower = exp(\n (kernelShape * kernelShape - 1.0) / 2.718281828459045\n );\n }\n vKernelPower = kernelPower;\n\n \n float maximumSupportRadius = maxStdDev\n + 0.7 * max(kernelShape - 1.0, 0.0);\n float supportRadius = maximumSupportRadius;\n\n scales *= renderToViewScale;\n\n vRgba = vec4(rgba.rgb, alpha);\n\n \n vec4 viewQuaternion = quatQuat(renderToViewQuat, quaternion);\n\n \n mat3 RS = scaleQuaternionToMatrix(scales, viewQuaternion);\n\n \n vec2 scaledRenderSize = renderSize * focalAdjustment;\n vec2 focal = 0.5 * scaledRenderSize * vec2(projectionMatrix[0][0], projectionMatrix[1][1]);\n\n vec3 j0;\n vec3 j1;\n if (isOrthographic) {\n j0 = vec3(focal.x, 0.0, 0.0);\n j1 = vec3(0.0, focal.y, 0.0);\n } else {\n float invZ = 1.0 / viewCenter.z;\n vec2 J1 = focal * invZ;\n vec2 J2 = -(J1 * viewCenter.xy) * invZ;\n j0 = vec3(J1.x, 0.0, J2.x);\n j1 = vec3(0.0, J1.y, J2.y);\n }\n\n \n \n vec3 p0 = transpose(RS) * j0;\n vec3 p1 = transpose(RS) * j1;\n float a = dot(p0, p0);\n float b = dot(p0, p1);\n float d = dot(p1, p1);\n\n \n a += preBlurAmount;\n d += preBlurAmount;\n\n float detOrig = a * d - b * b;\n \n a += blurAmount;\n d += blurAmount;\n float det = a * d - b * b;\n if (det <= 0.0) return;\n\n \n float blurAdjust = sqrt(max(0.0, detOrig / det));\n alpha *= blurAdjust;\n if (!(alpha > 0.0) || alpha < minAlpha) {\n return;\n }\n vRgba.a = alpha;\n\n \n if (kernelPower == 0.0) {\n supportRadius = gaussianSupportRadius(alpha, supportRadius);\n } else {\n supportRadius = wideSupportRadius(alpha, kernelPower, supportRadius);\n }\n vSupportRadiusSquared = supportRadius * supportRadius;\n vSplatUv = position.xy * supportRadius;\n\n \n float eigenAvg = 0.5 * (a + d);\n float eigenDelta = length(vec2(0.5 * (a - d), b));\n float eigen1 = eigenAvg + eigenDelta;\n \n float eigen2 = max(eigenAvg - eigenDelta, 1e-4);\n\n vec2 eigenVec1 = (abs(b) > 0.001)\n ? normalize(vec2(b, eigen1 - a))\n : ((a >= d) ? vec2(1.0, 0.0) : vec2(0.0, 1.0));\n vec2 eigenVec2 = vec2(eigenVec1.y, -eigenVec1.x);\n\n \n \n float maxProjectedRadius = maxPixelRadius * focalAdjustment;\n float scale1 = min(maxProjectedRadius, maximumSupportRadius * sqrt(eigen1));\n float scale2 = min(maxProjectedRadius, maximumSupportRadius * sqrt(eigen2));\n float supportScale = (maximumSupportRadius > 0.0)\n ? supportRadius / maximumSupportRadius\n : 0.0;\n \n \n float cullScale = (kernelPower == 0.0) ? supportScale : 1.0;\n \n float minProjectedRadius = minPixelRadius * focalAdjustment;\n if (scale1 * cullScale < minProjectedRadius && scale2 * cullScale < minProjectedRadius) {\n return;\n }\n scale1 *= supportScale;\n scale2 *= supportScale;\n\n \n \n vStochasticHash = 0u;\n if (stochastic || depthOnly) {\n vStochasticHash = hashU32(texelFetch(stochasticSeeds, texCoord, 0).r);\n }\n\n \n if (encodeLinear && !depthOnly) {\n vRgba.rgb = srgbToLinear(vRgba.rgb);\n }\n\n \n vec2 pixelOffset = position.x * eigenVec1 * scale1 + position.y * eigenVec2 * scale2;\n vec2 ndcOffset = (2.0 / scaledRenderSize) * pixelOffset;\n\n \n vec3 ndcCenter = clipCenter.xyz / clipCenter.w;\n vec3 ndc = vec3(ndcCenter.xy + ndcOffset, ndcCenter.z);\n\n gl_Position = vec4(ndc.xy * clipCenter.w, clipCenter.zw);\n if (stochastic && !depthOnly) {\n gl_Position.xy += stochasticTemporalSample.xy * gl_Position.w;\n }\n\n #include <logdepthbuf_vertex>\n}";
|
|
24461
24459
|
let shaders = null;
|
|
24462
24460
|
function getShaders() {
|
|
24463
24461
|
if (!shaders) {
|
|
@@ -25185,7 +25183,8 @@ class SplatDepthPass {
|
|
|
25185
25183
|
...host.uniforms,
|
|
25186
25184
|
stochastic: { value: false },
|
|
25187
25185
|
stochasticResolve: { value: false },
|
|
25188
|
-
depthOnly: { value: true }
|
|
25186
|
+
depthOnly: { value: true },
|
|
25187
|
+
splatCount: { value: 0 }
|
|
25189
25188
|
};
|
|
25190
25189
|
const material = backend.createDepthMaterial(uniforms);
|
|
25191
25190
|
material.blending = THREE__namespace.NoBlending;
|
|
@@ -25199,9 +25198,9 @@ class SplatDepthPass {
|
|
|
25199
25198
|
mesh.onBeforeRender = () => {
|
|
25200
25199
|
const activeRenderer = this.getActiveRenderer();
|
|
25201
25200
|
const compiling = backend.kind === "webgpu" && backend.precompile !== null;
|
|
25202
|
-
|
|
25203
|
-
|
|
25204
|
-
|
|
25201
|
+
const splatCount = compiling || activeRenderer.stochasticActive || activeRenderer.activeSplats === 0 ? 0 : activeRenderer.display.numSplats;
|
|
25202
|
+
mesh.geometry.setSplatCount(splatCount);
|
|
25203
|
+
uniforms.splatCount.value = splatCount;
|
|
25205
25204
|
};
|
|
25206
25205
|
if (backend.kind === "webgl-fallback") {
|
|
25207
25206
|
const glBackend = backend.renderer.backend;
|
|
@@ -25223,14 +25222,13 @@ class SplatDepthPass {
|
|
|
25223
25222
|
this.disposed = true;
|
|
25224
25223
|
}
|
|
25225
25224
|
}
|
|
25226
|
-
const
|
|
25225
|
+
const SPLATS_PER_INSTANCE = 128;
|
|
25227
25226
|
class SplatGeometry extends THREE__namespace.InstancedBufferGeometry {
|
|
25228
|
-
constructor(
|
|
25227
|
+
constructor() {
|
|
25229
25228
|
super();
|
|
25230
|
-
|
|
25231
|
-
const
|
|
25232
|
-
|
|
25233
|
-
for (let splat = 0; splat < splatsPerInstance; splat++) {
|
|
25229
|
+
const vertices = new Float32Array(SPLATS_PER_INSTANCE * 12);
|
|
25230
|
+
const indices = new Uint16Array(SPLATS_PER_INSTANCE * 6);
|
|
25231
|
+
for (let splat = 0; splat < SPLATS_PER_INSTANCE; splat++) {
|
|
25234
25232
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
25235
25233
|
const offset = splat * 12 + vertex * 3;
|
|
25236
25234
|
vertices[offset] = QUAD_VERTICES[vertex * 3];
|
|
@@ -25244,7 +25242,7 @@ class SplatGeometry extends THREE__namespace.InstancedBufferGeometry {
|
|
|
25244
25242
|
this.setIndex(new THREE__namespace.BufferAttribute(indices, 1));
|
|
25245
25243
|
}
|
|
25246
25244
|
setSplatCount(count) {
|
|
25247
|
-
this.instanceCount = Math.ceil(count /
|
|
25245
|
+
this.instanceCount = Math.ceil(count / SPLATS_PER_INSTANCE);
|
|
25248
25246
|
}
|
|
25249
25247
|
}
|
|
25250
25248
|
const QUAD_VERTICES = new Float32Array([
|
|
@@ -25758,21 +25756,25 @@ function createSplatNodeMaterial({
|
|
|
25758
25756
|
...view,
|
|
25759
25757
|
projectionMatrix: N.cameraProjectionMatrix
|
|
25760
25758
|
});
|
|
25761
|
-
const
|
|
25762
|
-
N.
|
|
25763
|
-
|
|
25764
|
-
|
|
25765
|
-
|
|
25766
|
-
|
|
25767
|
-
|
|
25768
|
-
texel.
|
|
25769
|
-
|
|
25770
|
-
|
|
25771
|
-
|
|
25772
|
-
|
|
25773
|
-
|
|
25774
|
-
|
|
25775
|
-
|
|
25759
|
+
const index2 = N.uint(N.instanceIndex).mul(SPLATS_PER_INSTANCE).add(N.uint(N.positionGeometry.z)).toVar();
|
|
25760
|
+
const splatIndex = N.uint(4294967295).toVar();
|
|
25761
|
+
const splatCount = uniformBinding(uniforms, "splatCount", "uint");
|
|
25762
|
+
N.If(index2.lessThan(splatCount), () => {
|
|
25763
|
+
splatIndex.assign(index2);
|
|
25764
|
+
N.If(stochastic.or(depthOnly).not(), () => {
|
|
25765
|
+
if ("isTextureNode" in orderingNode) {
|
|
25766
|
+
const texel = index2.shiftRight(2);
|
|
25767
|
+
const coord = N.ivec2(
|
|
25768
|
+
texel.mod(ORDERING_TEXTURE_WIDTH),
|
|
25769
|
+
texel.div(N.uint(ORDERING_TEXTURE_WIDTH))
|
|
25770
|
+
);
|
|
25771
|
+
splatIndex.assign(
|
|
25772
|
+
load2D(orderingNode, coord).element(index2.bitAnd(3))
|
|
25773
|
+
);
|
|
25774
|
+
} else {
|
|
25775
|
+
splatIndex.assign(orderingNode.element(index2));
|
|
25776
|
+
}
|
|
25777
|
+
});
|
|
25776
25778
|
});
|
|
25777
25779
|
N.If(splatIndex.notEqual(N.uint(4294967295)), () => {
|
|
25778
25780
|
const texCoord = splatTexCoord(splatIndex);
|
|
@@ -25967,17 +25969,15 @@ class WebGLFallbackSplatBackend extends NodeSplatBackend {
|
|
|
25967
25969
|
}
|
|
25968
25970
|
function createWebGLSplatMaterial(uniforms, options) {
|
|
25969
25971
|
const shaders2 = getShaders();
|
|
25970
|
-
const defines2 = {};
|
|
25971
|
-
if (options.vertexShader === void 0 && options.fragmentShader === void 0) {
|
|
25972
|
-
defines2.GSL_COLOR_IN_VERTEX = 1;
|
|
25973
|
-
defines2.GSL_SORTED_FRAGMENT = 0;
|
|
25974
|
-
}
|
|
25975
25972
|
return new THREE__namespace.ShaderMaterial({
|
|
25976
25973
|
...options,
|
|
25977
|
-
defines:
|
|
25974
|
+
defines: {
|
|
25975
|
+
SPLATS_PER_INSTANCE,
|
|
25976
|
+
GSL_SORTED_FRAGMENT: 0
|
|
25977
|
+
},
|
|
25978
25978
|
glslVersion: THREE__namespace.GLSL3,
|
|
25979
|
-
vertexShader:
|
|
25980
|
-
fragmentShader:
|
|
25979
|
+
vertexShader: shaders2.splatVertex,
|
|
25980
|
+
fragmentShader: shaders2.splatFragment,
|
|
25981
25981
|
uniforms,
|
|
25982
25982
|
side: THREE__namespace.FrontSide,
|
|
25983
25983
|
allowOverride: false
|
|
@@ -25994,9 +25994,8 @@ class WebGLSplatBackend {
|
|
|
25994
25994
|
}
|
|
25995
25995
|
selectMaterial(useUniform) {
|
|
25996
25996
|
const { material } = this;
|
|
25997
|
-
const currentSorted = material.defines.GSL_SORTED_FRAGMENT;
|
|
25998
25997
|
const sorted = Number(!useUniform);
|
|
25999
|
-
if (
|
|
25998
|
+
if (material.defines.GSL_SORTED_FRAGMENT !== sorted) {
|
|
26000
25999
|
material.defines.GSL_SORTED_FRAGMENT = sorted;
|
|
26001
26000
|
material.needsUpdate = true;
|
|
26002
26001
|
}
|
|
@@ -26707,7 +26706,7 @@ class ProjectedSplats {
|
|
|
26707
26706
|
this.renderer = renderer;
|
|
26708
26707
|
this.uniforms = uniforms;
|
|
26709
26708
|
this.indirect = new IndirectStorageBufferAttribute(
|
|
26710
|
-
new Uint32Array([
|
|
26709
|
+
new Uint32Array([SPLATS_PER_INSTANCE * 6, 0, 0, 0, 0]),
|
|
26711
26710
|
1
|
|
26712
26711
|
);
|
|
26713
26712
|
this.error = null;
|
|
@@ -26782,7 +26781,7 @@ class ProjectedSplats {
|
|
|
26782
26781
|
const index2 = N.uint(N.instanceIndex);
|
|
26783
26782
|
N.If(index2.equal(0), () => {
|
|
26784
26783
|
counts.element(viewIndex).assign(count);
|
|
26785
|
-
const instances = count.add(
|
|
26784
|
+
const instances = count.add(SPLATS_PER_INSTANCE - 1).div(N.uint(SPLATS_PER_INSTANCE));
|
|
26786
26785
|
drawCount.assign(
|
|
26787
26786
|
N.select(viewIndex.equal(0), instances, drawCount.max(instances))
|
|
26788
26787
|
);
|
|
@@ -26896,7 +26895,7 @@ class ProjectedSplats {
|
|
|
26896
26895
|
const eye = multiView ? N.cameraIndex : N.uint(0);
|
|
26897
26896
|
const stride = uniformBinding(this.state, "viewStride", "uint");
|
|
26898
26897
|
const base = eye.mul(stride).toVar();
|
|
26899
|
-
const i = N.uint(N.instanceIndex).mul(
|
|
26898
|
+
const i = N.uint(N.instanceIndex).mul(SPLATS_PER_INSTANCE).add(N.uint(N.positionGeometry.z));
|
|
26900
26899
|
const counts = bindBuffer(this.counts).toReadOnly();
|
|
26901
26900
|
const clipPosition = N.vec4(0, 0, 2, 1).toVar();
|
|
26902
26901
|
const rgba = N.vec4(0).toVar();
|
|
@@ -27142,9 +27141,6 @@ function createSplatBackend(renderer, uniforms, options) {
|
|
|
27142
27141
|
if (!isWebGPURenderer(renderer)) {
|
|
27143
27142
|
return new WebGLSplatBackend(renderer, uniforms, options);
|
|
27144
27143
|
}
|
|
27145
|
-
if (options.vertexShader || options.fragmentShader) {
|
|
27146
|
-
throw new Error("Custom GLSL shaders are only supported by WebGLRenderer");
|
|
27147
|
-
}
|
|
27148
27144
|
return usesNativeWebGPU(renderer) ? new WebGPUSplatBackend(renderer, uniforms, options) : new WebGLFallbackSplatBackend(renderer, uniforms, options);
|
|
27149
27145
|
}
|
|
27150
27146
|
function configureSplatOutput(renderer, target, uniforms, markerUsers) {
|
|
@@ -27224,29 +27220,18 @@ class GaussianSplatRenderer extends THREE__namespace.Mesh {
|
|
|
27224
27220
|
}
|
|
27225
27221
|
assertSupportedRenderer(options.renderer);
|
|
27226
27222
|
const uniforms = GaussianSplatRenderer.makeUniforms();
|
|
27227
|
-
Object.assign(uniforms, options.extraUniforms);
|
|
27228
27223
|
const premultipliedAlpha = options.premultipliedAlpha ?? true;
|
|
27229
27224
|
uniforms.premultipliedAlpha.value = premultipliedAlpha;
|
|
27230
27225
|
const autoStochastic = options.autoStochastic ?? false;
|
|
27231
27226
|
const stochastic = options.stochastic ?? false;
|
|
27232
27227
|
const renderDepth = options.renderDepth ?? false;
|
|
27233
|
-
const supportsStochasticShaders = options.vertexShader === void 0 && options.fragmentShader === void 0;
|
|
27234
|
-
if ((autoStochastic || stochastic || renderDepth) && !supportsStochasticShaders) {
|
|
27235
|
-
throw new Error(
|
|
27236
|
-
"Stochastic and renderDepth modes require the built-in Splat shaders"
|
|
27237
|
-
);
|
|
27238
|
-
}
|
|
27239
27228
|
const backend = createSplatBackend(options.renderer, uniforms, {
|
|
27240
27229
|
premultipliedAlpha,
|
|
27241
27230
|
transparent: options.transparent ?? true,
|
|
27242
27231
|
depthTest: options.depthTest ?? true,
|
|
27243
|
-
depthWrite: options.depthWrite ?? false
|
|
27244
|
-
vertexShader: options.vertexShader,
|
|
27245
|
-
fragmentShader: options.fragmentShader
|
|
27232
|
+
depthWrite: options.depthWrite ?? false
|
|
27246
27233
|
});
|
|
27247
|
-
const geometry = new SplatGeometry(
|
|
27248
|
-
backend.kind === "webgpu" ? WEBGPU_SPLATS_PER_INSTANCE : 1
|
|
27249
|
-
);
|
|
27234
|
+
const geometry = new SplatGeometry();
|
|
27250
27235
|
const material = backend.selectMaterial(autoStochastic || stochastic);
|
|
27251
27236
|
super(geometry, material);
|
|
27252
27237
|
this.renderSize = new THREE__namespace.Vector2();
|
|
@@ -27287,7 +27272,6 @@ class GaussianSplatRenderer extends THREE__namespace.Mesh {
|
|
|
27287
27272
|
backend,
|
|
27288
27273
|
() => GaussianSplatRenderer.gaussianSplatOverride ?? this
|
|
27289
27274
|
);
|
|
27290
|
-
this.supportsStochasticShaders = supportsStochasticShaders;
|
|
27291
27275
|
this.sortedBlending = material.blending;
|
|
27292
27276
|
this._depthTest = options.depthTest ?? true;
|
|
27293
27277
|
this._depthWrite = options.depthWrite ?? false;
|
|
@@ -27541,9 +27525,9 @@ class GaussianSplatRenderer extends THREE__namespace.Mesh {
|
|
|
27541
27525
|
const display = gaussianSplatRenderer.display;
|
|
27542
27526
|
this.uniforms.renderOrigin.value.copy(display.viewOrigin);
|
|
27543
27527
|
const geometry = this.geometry;
|
|
27544
|
-
|
|
27545
|
-
|
|
27546
|
-
|
|
27528
|
+
const splatCount = gaussianSplatRenderer.stochasticFrame ? display.numSplats : gaussianSplatRenderer.activeSplats;
|
|
27529
|
+
geometry.setSplatCount(splatCount);
|
|
27530
|
+
this.uniforms.splatCount.value = splatCount;
|
|
27547
27531
|
renderToViewMatrixTmp.copy(camera.matrixWorld).invert().multiply(renderTranslationTmp.makeTranslation(display.viewOrigin)).decompose(
|
|
27548
27532
|
this.uniforms.renderToViewPos.value,
|
|
27549
27533
|
this.uniforms.renderToViewQuat.value,
|
|
@@ -27568,8 +27552,6 @@ class GaussianSplatRenderer extends THREE__namespace.Mesh {
|
|
|
27568
27552
|
if (this.stochasticModeEnabled) {
|
|
27569
27553
|
this.applyMaterialState(gaussianSplatRenderer.stochasticFrame);
|
|
27570
27554
|
}
|
|
27571
|
-
this.uniforms.time.value = display.time;
|
|
27572
|
-
this.uniforms.deltaTime.value = display.deltaTime;
|
|
27573
27555
|
if (this.backend.kind === "webgpu") {
|
|
27574
27556
|
if (this.backend.sortError) throw this.backend.sortError;
|
|
27575
27557
|
if (this.backend.precompile) {
|
|
@@ -27969,13 +27951,6 @@ class GaussianSplatRenderer extends THREE__namespace.Mesh {
|
|
|
27969
27951
|
get depthMesh() {
|
|
27970
27952
|
return this.depthPass.mesh;
|
|
27971
27953
|
}
|
|
27972
|
-
assertBuiltInSplatShaders(enabled) {
|
|
27973
|
-
if (enabled && !this.supportsStochasticShaders) {
|
|
27974
|
-
throw new Error(
|
|
27975
|
-
"Stochastic and renderDepth modes require the built-in Splat shaders"
|
|
27976
|
-
);
|
|
27977
|
-
}
|
|
27978
|
-
}
|
|
27979
27954
|
refreshRenderConfiguration() {
|
|
27980
27955
|
this.applyRenderOrder();
|
|
27981
27956
|
this.applyMaterialState(this.stochasticFrame);
|
|
@@ -28036,7 +28011,6 @@ class GaussianSplatRenderer extends THREE__namespace.Mesh {
|
|
|
28036
28011
|
set autoStochastic(value) {
|
|
28037
28012
|
const nextValue = Boolean(value);
|
|
28038
28013
|
if (nextValue === this._autoStochastic) return;
|
|
28039
|
-
this.assertBuiltInSplatShaders(nextValue);
|
|
28040
28014
|
this._autoStochastic = nextValue;
|
|
28041
28015
|
this.refreshStochasticConfiguration();
|
|
28042
28016
|
}
|
|
@@ -28060,7 +28034,6 @@ class GaussianSplatRenderer extends THREE__namespace.Mesh {
|
|
|
28060
28034
|
set stochastic(value) {
|
|
28061
28035
|
const nextValue = Boolean(value);
|
|
28062
28036
|
if (nextValue === this._stochastic) return;
|
|
28063
|
-
this.assertBuiltInSplatShaders(nextValue);
|
|
28064
28037
|
this._stochastic = nextValue;
|
|
28065
28038
|
this.refreshStochasticConfiguration();
|
|
28066
28039
|
}
|
|
@@ -28070,7 +28043,6 @@ class GaussianSplatRenderer extends THREE__namespace.Mesh {
|
|
|
28070
28043
|
set renderDepth(value) {
|
|
28071
28044
|
const nextValue = Boolean(value);
|
|
28072
28045
|
if (nextValue === this._renderDepth) return;
|
|
28073
|
-
this.assertBuiltInSplatShaders(nextValue);
|
|
28074
28046
|
this._renderDepth = nextValue;
|
|
28075
28047
|
this.refreshRenderConfiguration();
|
|
28076
28048
|
this.setDirty();
|