gaussian-splat-lite 0.1.4 → 0.1.6

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 CHANGED
@@ -7,6 +7,23 @@ and this project follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.6] - 2026-08-28
11
+
12
+ ### Changed
13
+
14
+ - Reduced accumulator shader work by projecting quaternion vector parts directly during octahedral encoding and constructing packed SH scale factors from exact float exponent bits.
15
+ - Reduced rendering shader work by clipping ordinary Gaussian support to the configured alpha threshold, precomputing wide-kernel powers per vertex, and projecting covariance without intermediate matrices.
16
+
17
+ ### Fixed
18
+
19
+ - Preserved wide-kernel semantic opacity when applying SDF opacity edits or mesh-wide opacity, including fully hiding meshes whose opacity is zero.
20
+
21
+ ## [0.1.5] - 2026-08-27
22
+
23
+ ### Added
24
+
25
+ - Added `Splats.getByteLength()` for current retained array storage.
26
+
10
27
  ## [0.1.4] - 2026-08-27
11
28
 
12
29
  ### Added
@@ -84,7 +101,9 @@ and this project follows [Semantic Versioning](https://semver.org/).
84
101
 
85
102
  - Initial public release of the Three.js Gaussian Splatting renderer.
86
103
 
87
- [Unreleased]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v0.1.4...HEAD
104
+ [Unreleased]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v0.1.6...HEAD
105
+ [0.1.6]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v0.1.5...v0.1.6
106
+ [0.1.5]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v0.1.4...v0.1.5
88
107
  [0.1.4]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v0.1.3...v0.1.4
89
108
  [0.1.3]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v0.1.2...v0.1.3
90
109
  [0.1.2]: https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/compare/v0.1.1...v0.1.2
@@ -1,104 +1,35 @@
1
1
  <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
2
  <svg
3
- width="645"
4
- height="180"
5
- viewBox="0 0 645 180"
3
+ width="640"
4
+ height="120"
5
+ viewBox="3 30 640 120"
6
6
  version="1.1"
7
7
  id="svg16"
8
8
  xmlns="http://www.w3.org/2000/svg"
9
9
  xmlns:svg="http://www.w3.org/2000/svg">
10
- <defs
11
- id="defs20" />
12
- <rect
13
- width="645"
14
- height="180"
15
- fill="#10151e"
16
- id="rect2" />
17
- <circle
18
- cx="83"
19
- cy="90"
20
- r="38"
21
- fill="none"
22
- stroke="#69717e"
23
- stroke-width="3"
24
- opacity=".82"
25
- id="circle4" />
26
- <circle
27
- cx="54"
28
- cy="65"
29
- r="11"
30
- fill="#cfff58"
31
- id="circle6" />
32
- <circle
33
- cx="112"
34
- cy="65"
35
- r="11"
36
- fill="#8ea9ff"
37
- id="circle8" />
38
- <circle
39
- cx="83"
40
- cy="124"
41
- r="11"
42
- fill="#f6f5f0"
43
- id="circle10" />
44
- <g
45
- aria-label="Gaussian Splat Lite"
46
- id="text14"
47
- style="fill:#ffffff">
48
- <path
49
- d="m 183.3,81.05 q -1.15,-2.9 -3.25,-4.45 -2.1,-1.6 -6.55,-1.6 -2.45,0 -4.2,0.65 -1.75,0.6 -3.15,2.1 -1.4,1.5 -2.1,4.35 -0.7,2.8 -0.7,6.95 v 4.9 q 0,4.15 0.7,7 0.7,2.8 2.1,4.3 1.4,1.5 3.15,2.15 1.75,0.6 4.2,0.6 4.5,0 7.15,-1.9 2.65,-1.95 2.65,-4.15 V 93.5 h -6.15 V 92 h 7.95 v 9.45 q 0,3.35 -3.05,5.7 -3,2.35 -8.55,2.35 -6.15,0 -8.9,-3.75 -2.75,-3.8 -2.75,-11.8 v -4.9 q 0,-8 2.75,-11.75 2.75,-3.8 8.9,-3.8 4.95,0 7.4,1.85 2.45,1.8 3.8,5.15 z"
50
- id="path22" />
51
- <path
52
- d="m 195.74999,107.5 h 16.3 l -10.25,-24.15 -10.9,25.65 h -1.6 l 12.5,-29.5 12.5,29.5 h -18.55 z"
53
- id="path24" />
54
- <path
55
- d="m 220.59999,80 v 14.5 q 0,7.45 2.35,10.5 2.4,3 6.55,3 4.15,0 6.5,-3 2.4,-3.05 2.4,-10.5 V 80 h 1.5 v 14.5 q 0,15 -10.4,15 -10.4,0 -10.4,-15 V 80 Z"
56
- id="path26" />
57
- <path
58
- d="m 256.15002,79.4 q 6.2,0 8.8,2.75 l -1,1.1 q -2.4,-2.35 -7.6,-2.35 -7.8,0 -7.8,6.2 0,2.4 1.9,3.85 1.9,1.4 4.6,2.15 2.75,0.75 5.45,1.6 2.75,0.8 4.65,2.65 1.9,1.8 1.9,4.75 0,3.45 -2.85,5.5 -2.85,2.05 -8.25,2.05 -2.65,0 -5.25,-0.7 -2.55,-0.7 -3.8,-2.05 l 1,-1.1 q 2.55,2.35 7.85,2.35 4.85,0 7.3,-1.8 2.5,-1.8 2.5,-4.2 0,-2.5 -1.9,-4.05 -1.9,-1.55 -4.65,-2.3 -2.7,-0.8 -5.45,-1.6 -2.7,-0.85 -4.6,-2.6 -1.9,-1.75 -1.9,-4.6 0,-3.85 2.55,-5.7 2.6,-1.9 6.55,-1.9 z"
59
- id="path28" />
60
- <path
61
- d="m 281.60003,79.4 q 6.2,0 8.8,2.75 l -1,1.1 q -2.4,-2.35 -7.6,-2.35 -7.8,0 -7.8,6.2 0,2.4 1.9,3.85 1.9,1.4 4.6,2.15 2.75,0.75 5.45,1.6 2.75,0.8 4.65,2.65 1.9,1.8 1.9,4.75 0,3.45 -2.85,5.5 -2.85,2.05 -8.25,2.05 -2.65,0 -5.25,-0.7 -2.55,-0.7 -3.8,-2.05 l 1,-1.1 q 2.55,2.35 7.85,2.35 4.85,0 7.3,-1.8 2.5,-1.8 2.5,-4.2 0,-2.5 -1.9,-4.05 -1.9,-1.55 -4.65,-2.3 -2.7,-0.8 -5.45,-1.6 -2.7,-0.85 -4.6,-2.6 -1.9,-1.75 -1.9,-4.6 0,-3.85 2.55,-5.7 2.6,-1.9 6.55,-1.9 z"
62
- id="path30" />
63
- <path
64
- d="m 299.40004,80 h 1.5 v 29 h -1.5 z"
65
- id="path32" />
66
- <path
67
- d="m 312.65,107.5 h 16.3 L 318.7,83.35 307.8,109 h -1.6 l 12.5,-29.5 12.5,29.5 h -18.55 z"
68
- id="path34" />
69
- <path
70
- d="M 336.5,109 V 80 h 1.5 l 16.3,26.25 V 80 h 1.5 v 29 h -1.5 L 338,82.7 V 109 Z"
71
- id="path36" />
72
- <path
73
- d="m 378.40002,82.65 q 0,-4.85 2.45,-7 2.45,-2.15 7.95,-2.15 3.85,0 6.2,2 2.35,2 3.4,6.1 l -4.65,3.5 h -2.45 l 5.4,-4.05 q -1.05,-3.35 -3.05,-4.7 -1.95,-1.35 -4.85,-1.35 -2,0 -3.4,0.25 -1.35,0.25 -2.75,1 -1.35,0.7 -2.05,2.3 -0.7,1.6 -0.7,4.1 0,2.2 2,3.9 2.05,1.7 4.95,2.9 2.9,1.2 5.8,2.45 2.95,1.25 4.95,3.2 2.05,1.95 2.05,4.5 0,5 -2.5,7.45 -2.45,2.45 -8.45,2.45 -4.9,0 -7.7,-1.95 -2.8,-2 -3.85,-6.15 l 1.4,-0.6 q 1,4.05 3.4,5.65 2.45,1.55 6.75,1.55 4.8,0 7.1,-1.85 2.35,-1.85 2.35,-6.55 0,-2.2 -2.05,-3.9 -2,-1.7 -4.95,-2.9 -2.9,-1.2 -5.8,-2.45 -2.9,-1.25 -4.95,-3.2 -2,-1.95 -2,-4.5 z"
74
- id="path38" />
75
- <path
76
- d="m 419.30005,98.2 -0.75,-1.3 2.8,-1.6 q 3.45,-1.9 3.45,-6.05 0,-7.75 -11.8,-7.75 h -4.6 V 119 h -1.5 V 80 h 6.1 q 6.6,0 9.95,2.45 3.35,2.4 3.35,6.8 0,5 -4.2,7.35 z"
77
- id="path40" />
78
- <path
79
- d="m 449.65004,107.5 v 1.5 h -16.7 V 80 h 1.5 v 27.5 z"
80
- id="path42" />
81
- <path
82
- d="m 457.65,107.5 h 16.3 L 463.7,83.35 452.8,109 h -1.6 l 12.5,-29.5 12.5,29.5 h -18.55 z"
83
- id="path44" />
84
- <path
85
- d="m 500.25,80 v 1.5 h -10.5 V 109 h -1.5 V 81.5 h -10.5 V 80 Z"
86
- id="path46" />
87
- <path
88
- d="m 541.04998,107.5 v 1.5 h -20.9 V 74 h 1.5 v 33.5 z"
89
- style="fill:#cfff58"
90
- id="path48" />
91
- <path
92
- d="m 546.14996,80 h 1.5 v 29 h -1.5 z"
93
- style="fill:#cfff58"
94
- id="path50" />
95
- <path
96
- d="m 575.49994,80 v 1.5 h -10.5 V 109 h -1.5 V 81.5 h -10.5 V 80 Z"
97
- style="fill:#cfff58"
98
- id="path52" />
99
- <path
100
- d="m 600.24995,106.05 q -2.75,3.45 -9,3.45 -6.25,0 -8.95,-3.55 -2.7,-3.55 -2.7,-11.45 0,-7.9 2.7,-11.45 2.7,-3.55 8.95,-3.55 7.25,0 9.85,4.75 l -12.25,10.25 h -2.35 l 12.65,-10.55 q -2.2,-2.95 -7.9,-2.95 -2.5,0 -4.2,0.55 -1.7,0.5 -3.15,1.95 -1.4,1.4 -2.1,4.15 -0.7,2.7 -0.7,6.85 0,4.15 0.7,6.9 0.7,2.7 2.1,4.15 1.45,1.4 3.15,1.95 1.7,0.5 4.2,0.5 5.7,0 7.9,-2.95 z"
101
- style="fill:#cfff58"
102
- id="path54" />
10
+ <defs id="defs20" />
11
+ <rect width="645" height="180" fill="#10151e" id="rect2" />
12
+ <circle cx="83" cy="90" r="38" fill="none" stroke="#69717e" stroke-width="3" opacity=".82" id="circle4" transform="translate(-1 0)" />
13
+ <circle cx="54" cy="65" r="11" fill="#cfff58" id="circle6" transform="translate(-1 0)" />
14
+ <circle cx="112" cy="65" r="11" fill="#8ea9ff" id="circle8" transform="translate(-1 0)" />
15
+ <circle cx="83" cy="124" r="11" fill="#f6f5f0" id="circle10" transform="translate(-1 0)" />
16
+ <g aria-label="Gaussian Splat Lite" id="text14" style="fill:#ffffff" transform="translate(-1 -3)">
17
+ <path d="m 183.3,81.05 q -1.15,-2.9 -3.25,-4.45 -2.1,-1.6 -6.55,-1.6 -2.45,0 -4.2,0.65 -1.75,0.6 -3.15,2.1 -1.4,1.5 -2.1,4.35 -0.7,2.8 -0.7,6.95 v 4.9 q 0,4.15 0.7,7 0.7,2.8 2.1,4.3 1.4,1.5 3.15,2.15 1.75,0.6 4.2,0.6 4.5,0 7.15,-1.9 2.65,-1.95 2.65,-4.15 V 93.5 h -6.15 V 92 h 7.95 v 9.45 q 0,3.35 -3.05,5.7 -3,2.35 -8.55,2.35 -6.15,0 -8.9,-3.75 -2.75,-3.8 -2.75,-11.8 v -4.9 q 0,-8 2.75,-11.75 2.75,-3.8 8.9,-3.8 4.95,0 7.4,1.85 2.45,1.8 3.8,5.15 z" id="path22" />
18
+ <path d="m 195.74999,107.5 h 16.3 l -10.25,-24.15 -10.9,25.65 h -1.6 l 12.5,-29.5 12.5,29.5 h -18.55 z" id="path24" />
19
+ <path d="m 220.59999,80 v 14.5 q 0,7.45 2.35,10.5 2.4,3 6.55,3 4.15,0 6.5,-3 2.4,-3.05 2.4,-10.5 V 80 h 1.5 v 14.5 q 0,15 -10.4,15 -10.4,0 -10.4,-15 V 80 Z" id="path26" />
20
+ <path d="m 256.15002,79.4 q 6.2,0 8.8,2.75 l -1,1.1 q -2.4,-2.35 -7.6,-2.35 -7.8,0 -7.8,6.2 0,2.4 1.9,3.85 1.9,1.4 4.6,2.15 2.75,0.75 5.45,1.6 2.75,0.8 4.65,2.65 1.9,1.8 1.9,4.75 0,3.45 -2.85,5.5 -2.85,2.05 -8.25,2.05 -2.65,0 -5.25,-0.7 -2.55,-0.7 -3.8,-2.05 l 1,-1.1 q 2.55,2.35 7.85,2.35 4.85,0 7.3,-1.8 2.5,-1.8 2.5,-4.2 0,-2.5 -1.9,-4.05 -1.9,-1.55 -4.65,-2.3 -2.7,-0.8 -5.45,-1.6 -2.7,-0.85 -4.6,-2.6 -1.9,-1.75 -1.9,-4.6 0,-3.85 2.55,-5.7 2.6,-1.9 6.55,-1.9 z" id="path28" />
21
+ <path d="m 281.60003,79.4 q 6.2,0 8.8,2.75 l -1,1.1 q -2.4,-2.35 -7.6,-2.35 -7.8,0 -7.8,6.2 0,2.4 1.9,3.85 1.9,1.4 4.6,2.15 2.75,0.75 5.45,1.6 2.75,0.8 4.65,2.65 1.9,1.8 1.9,4.75 0,3.45 -2.85,5.5 -2.85,2.05 -8.25,2.05 -2.65,0 -5.25,-0.7 -2.55,-0.7 -3.8,-2.05 l 1,-1.1 q 2.55,2.35 7.85,2.35 4.85,0 7.3,-1.8 2.5,-1.8 2.5,-4.2 0,-2.5 -1.9,-4.05 -1.9,-1.55 -4.65,-2.3 -2.7,-0.8 -5.45,-1.6 -2.7,-0.85 -4.6,-2.6 -1.9,-1.75 -1.9,-4.6 0,-3.85 2.55,-5.7 2.6,-1.9 6.55,-1.9 z" id="path30" />
22
+ <path d="m 299.40004,80 h 1.5 v 29 h -1.5 z" id="path32" />
23
+ <path d="m 312.65,107.5 h 16.3 L 318.7,83.35 307.8,109 h -1.6 l 12.5,-29.5 12.5,29.5 h -18.55 z" id="path34" />
24
+ <path d="M 336.5,109 V 80 h 1.5 l 16.3,26.25 V 80 h 1.5 v 29 h -1.5 L 338,82.7 V 109 Z" id="path36" />
25
+ <path d="m 378.40002,82.65 q 0,-4.85 2.45,-7 2.45,-2.15 7.95,-2.15 3.85,0 6.2,2 2.35,2 3.4,6.1 l -4.65,3.5 h -2.45 l 5.4,-4.05 q -1.05,-3.35 -3.05,-4.7 -1.95,-1.35 -4.85,-1.35 -2,0 -3.4,0.25 -1.35,0.25 -2.75,1 -1.35,0.7 -2.05,2.3 -0.7,1.6 -0.7,4.1 0,2.2 2,3.9 2.05,1.7 4.95,2.9 2.9,1.2 5.8,2.45 2.95,1.25 4.95,3.2 2.05,1.95 2.05,4.5 0,5 -2.5,7.45 -2.45,2.45 -8.45,2.45 -4.9,0 -7.7,-1.95 -2.8,-2 -3.85,-6.15 l 1.4,-0.6 q 1,4.05 3.4,5.65 2.45,1.55 6.75,1.55 4.8,0 7.1,-1.85 2.35,-1.85 2.35,-6.55 0,-2.2 -2.05,-3.9 -2,-1.7 -4.95,-2.9 -2.9,-1.2 -5.8,-2.45 -2.9,-1.25 -4.95,-3.2 -2,-1.95 -2,-4.5 z" id="path38" />
26
+ <path d="m 419.30005,98.2 -0.75,-1.3 2.8,-1.6 q 3.45,-1.9 3.45,-6.05 0,-7.75 -11.8,-7.75 h -4.6 V 119 h -1.5 V 80 h 6.1 q 6.6,0 9.95,2.45 3.35,2.4 3.35,6.8 0,5 -4.2,7.35 z" id="path40" />
27
+ <path d="m 449.65004,107.5 v 1.5 h -16.7 V 80 h 1.5 v 27.5 z" id="path42" />
28
+ <path d="m 457.65,107.5 h 16.3 L 463.7,83.35 452.8,109 h -1.6 l 12.5,-29.5 12.5,29.5 h -18.55 z" id="path44" />
29
+ <path d="m 500.25,80 v 1.5 h -10.5 V 109 h -1.5 V 81.5 h -10.5 V 80 Z" id="path46" />
30
+ <path d="m 541.04998,107.5 v 1.5 h -20.9 V 74 h 1.5 v 33.5 z" style="fill:#cfff58" id="path48" />
31
+ <path d="m 546.14996,80 h 1.5 v 29 h -1.5 z" style="fill:#cfff58" id="path50" />
32
+ <path d="m 575.49994,80 v 1.5 h -10.5 V 109 h -1.5 V 81.5 h -10.5 V 80 Z" style="fill:#cfff58" id="path52" />
33
+ <path d="m 600.24995,106.05 q -2.75,3.45 -9,3.45 -6.25,0 -8.95,-3.55 -2.7,-3.55 -2.7,-11.45 0,-7.9 2.7,-11.45 2.7,-3.55 8.95,-3.55 7.25,0 9.85,4.75 l -12.25,10.25 h -2.35 l 12.65,-10.55 q -2.2,-2.95 -7.9,-2.95 -2.5,0 -4.2,0.55 -1.7,0.5 -3.15,1.95 -1.4,1.4 -2.1,4.15 -0.7,2.7 -0.7,6.85 0,4.15 0.7,6.9 0.7,2.7 2.1,4.15 1.45,1.4 3.15,1.95 1.7,0.5 4.2,0.5 5.7,0 7.9,-2.95 z" style="fill:#cfff58" id="path54" />
103
34
  </g>
104
- </svg>
35
+ </svg>
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
8
8
 
9
9
  <p align="center">
10
- <img src="./Gaussian-Splat-Lite.svg" alt="Gaussian Splat Lite" width="645">
10
+ <img src="./Gaussian-Splat-Lite.svg" alt="Gaussian Splat Lite" width="1000">
11
11
  </p>
12
12
 
13
13
  </div>
@@ -1267,6 +1267,16 @@ const _Splats = class _Splats {
1267
1267
  getNumSh() {
1268
1268
  return !this.extra.sh1 ? 0 : !this.extra.sh2 ? 1 : !this.extra.sh3a || !this.extra.sh3b ? 2 : 3;
1269
1269
  }
1270
+ /** Current retained bytes for encoded Splat, sort-center, and SH arrays. */
1271
+ getByteLength() {
1272
+ let byteLength = this.splatArrays[0].byteLength + this.splatArrays[1].byteLength + this.sortCenters.byteLength;
1273
+ for (const value of Object.values(this.extra)) {
1274
+ if (ArrayBuffer.isView(value)) {
1275
+ byteLength += value.byteLength;
1276
+ }
1277
+ }
1278
+ return byteLength;
1279
+ }
1270
1280
  get needsUpdate() {
1271
1281
  return this.updateNeeded;
1272
1282
  }
@@ -1959,7 +1969,7 @@ class SplatMesh extends THREE__namespace.Object3D {
1959
1969
  this.recolor.r,
1960
1970
  this.recolor.g,
1961
1971
  this.recolor.b,
1962
- this.opacity
1972
+ THREE__namespace.MathUtils.clamp(this.opacity, 0, 1)
1963
1973
  );
1964
1974
  if (!recolor.equals(this.lastRecolor)) {
1965
1975
  this.lastRecolor.copy(recolor);
@@ -2060,9 +2070,9 @@ class SplatMesh extends THREE__namespace.Object3D {
2060
2070
  }
2061
2071
  }
2062
2072
  }
2063
- 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\nconst float INFINITY = 1.0 / 0.0;\n\nvec3 srgbToLinear(vec3 rgb) {\n return pow(rgb, vec3(2.2));\n}\n\nuint encodeQuatOctXy1010R12(vec4 q) {\n \n if (q.w < 0.0) {\n q = -q;\n }\n \n float halfTheta = acos(q.w);\n float theta = 2.0 * halfTheta;\n float s = sin(halfTheta);\n \n vec3 axis = (abs(s) < 1e-6) ? vec3(1.0, 0.0, 0.0) : q.xyz / s;\n \n \n \n float sum = abs(axis.x) + abs(axis.y) + abs(axis.z);\n vec2 p = vec2(axis.x, axis.y) / sum;\n \n if (axis.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 float divisor = exp2(float(int(biasedBase) - 15)) / 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}";
2064
- var splatFragment_default = "precision highp float;\nprecision highp int;\n\n#include <splatDefines>\n\nuniform float near;\nuniform float far;\nuniform bool encodeLinear;\nuniform float time;\nuniform bool debugFlag;\nuniform float minAlpha;\n\nout vec4 fragColor;\n\nin vec4 vRgba;\nin vec2 vSplatUv;\nin vec3 vNdc;\nflat in uint vSplatIndex;\nflat in float adjustedStdDev;\nflat in float vKernelShape;\n\n#include <logdepthbuf_pars_fragment>\n\nvoid main() {\n vec4 rgba = vRgba;\n\n float z2 = dot(vSplatUv, vSplatUv);\n if (z2 > (adjustedStdDev * adjustedStdDev)) {\n discard;\n }\n\n float kernelShape = vKernelShape;\n if (kernelShape <= 1.0) {\n rgba.a *= exp(-0.5 * z2);\n } else {\n float power = exp((kernelShape * kernelShape - 1.0) / 2.718281828459045);\n float alpha = 1.0 - pow(1.0 - exp(-0.5 * z2), power);\n rgba.a *= alpha;\n }\n\n if (rgba.a < minAlpha) {\n discard;\n }\n if (encodeLinear) {\n rgba.rgb = srgbToLinear(rgba.rgb);\n }\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}";
2065
- var splatVertex_default = "precision highp float;\nprecision highp int;\nprecision highp usampler2DArray;\n\n#include <splatDefines>\n\nout vec4 vRgba;\nout vec2 vSplatUv;\nout vec3 vNdc;\nflat out uint vSplatIndex;\nflat out float adjustedStdDev;\nflat out float vKernelShape;\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 time;\nuniform float deltaTime;\nuniform bool debugFlag;\nuniform float minAlpha;\nuniform bool enable2DGS;\nuniform float blurAmount;\nuniform float preBlurAmount;\nuniform float clipXY;\nuniform float focalAdjustment;\n\nuniform usampler2D ordering;\nuniform usampler2DArray splats;\nuniform usampler2DArray splats2;\n\nbool isPerspectiveMatrix( mat4 m ) {\n return m[ 2 ][ 3 ] == -1.0;\n}\n\n#include <logdepthbuf_pars_vertex>\n\nvoid main() {\n \n gl_Position = vec4(0.0, 0.0, 2.0, 1.0);\n\n ivec2 orderingCoord = ivec2((gl_InstanceID >> 2) & 4095, gl_InstanceID >> 14);\n uint splatIndex = texelFetch(ordering, orderingCoord, 0)[gl_InstanceID & 3];\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 bvec3 zeroScales = equal(scales, vec3(0.0));\n if (all(zeroScales)) {\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 vKernelShape = kernelShape;\n\n \n adjustedStdDev = maxStdDev + 0.7 * max(kernelShape - 1.0, 0.0);\n\n scales *= renderToViewScale;\n\n vRgba = vec4(rgba.rgb, alpha);\n vSplatUv = position.xy * adjustedStdDev;\n\n \n vSplatIndex = splatIndex;\n\n \n vec4 viewQuaternion = quatQuat(renderToViewQuat, quaternion);\n\n if (enable2DGS && any(zeroScales)) {\n vec3 offset;\n if (zeroScales.z) {\n offset = vec3(vSplatUv.xy * scales.xy, 0.0);\n } else if (zeroScales.y) {\n offset = vec3(vSplatUv.x * scales.x, 0.0, vSplatUv.y * scales.z);\n } else {\n offset = vec3(0.0, vSplatUv.xy * scales.yz);\n }\n\n vec3 viewPos = viewCenter + quatVec(viewQuaternion, offset);\n gl_Position = projectionMatrix * vec4(viewPos, 1.0);\n vNdc = gl_Position.xyz / gl_Position.w;\n\n #include <logdepthbuf_vertex>\n return;\n }\n\n \n mat3 RS = scaleQuaternionToMatrix(scales, viewQuaternion);\n mat3 cov3D = RS * transpose(RS);\n\n \n vec2 scaledRenderSize = renderSize * focalAdjustment;\n vec2 focal = 0.5 * scaledRenderSize * vec2(projectionMatrix[0][0], projectionMatrix[1][1]);\n\n mat3 J;\n if (isOrthographic) {\n J = mat3(\n focal.x, 0.0, 0.0,\n 0.0, focal.y, 0.0,\n 0.0, 0.0, 0.0\n );\n } else {\n float invZ = 1.0 / viewCenter.z;\n vec2 J1 = focal * invZ;\n vec2 J2 = -(J1 * viewCenter.xy) * invZ;\n J = mat3(\n J1.x, 0.0, J2.x,\n 0.0, J1.y, J2.y,\n 0.0, 0.0, 0.0\n );\n }\n\n \n \n mat3 cov2D = transpose(J) * cov3D * J;\n float a = cov2D[0][0];\n float d = cov2D[1][1];\n float b = cov2D[0][1];\n\n \n a += preBlurAmount;\n d += preBlurAmount;\n\n \n float detOrig = a * d - b * b;\n a += blurAmount;\n d += blurAmount;\n float det = a * d - b * b;\n\n \n float blurAdjust = sqrt(max(0.0, detOrig / det));\n alpha *= blurAdjust;\n if (alpha < minAlpha) {\n return;\n }\n vRgba.a = alpha;\n\n \n float eigenAvg = 0.5 * (a + d);\n float eigenDelta = sqrt(max(0.0, eigenAvg * eigenAvg - det));\n float eigen1 = eigenAvg + eigenDelta;\n float eigen2 = eigenAvg - eigenDelta;\n\n vec2 eigenVec1 = (abs(b) > 0.001) ? 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 float scale1 = min(maxPixelRadius, adjustedStdDev * sqrt(eigen1));\n float scale2 = min(maxPixelRadius, adjustedStdDev * sqrt(eigen2));\n if (scale1 < minPixelRadius && scale2 < minPixelRadius) {\n return;\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 vNdc = ndc;\n gl_Position = vec4(ndc.xy * clipCenter.w, clipCenter.zw);\n\n #include <logdepthbuf_vertex>\n}";
2073
+ 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\nconst float INFINITY = 1.0 / 0.0;\n\nvec3 srgbToLinear(vec3 rgb) {\n return pow(rgb, vec3(2.2));\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}";
2074
+ var splatFragment_default = "precision highp float;\nprecision highp int;\n\n#include <splatDefines>\n\nuniform float near;\nuniform float far;\nuniform bool encodeLinear;\nuniform float time;\nuniform bool debugFlag;\nuniform float minAlpha;\n\nout vec4 fragColor;\n\nin vec4 vRgba;\nin vec2 vSplatUv;\nin vec3 vNdc;\nflat in uint vSplatIndex;\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 (encodeLinear) {\n rgba.rgb = srgbToLinear(rgba.rgb);\n }\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}";
2075
+ var splatVertex_default = "precision highp float;\nprecision highp int;\nprecision highp usampler2DArray;\n\n#include <splatDefines>\n\nout vec4 vRgba;\nout vec2 vSplatUv;\nout vec3 vNdc;\nflat out uint vSplatIndex;\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 time;\nuniform float deltaTime;\nuniform bool debugFlag;\nuniform float minAlpha;\nuniform bool enable2DGS;\nuniform float blurAmount;\nuniform float preBlurAmount;\nuniform float clipXY;\nuniform float focalAdjustment;\n\nuniform usampler2D ordering;\nuniform usampler2DArray splats;\nuniform usampler2DArray splats2;\n\nbool isPerspectiveMatrix( mat4 m ) {\n return m[ 2 ][ 3 ] == -1.0;\n}\n\n#include <logdepthbuf_pars_vertex>\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\nvoid main() {\n \n gl_Position = vec4(0.0, 0.0, 2.0, 1.0);\n\n ivec2 orderingCoord = ivec2((gl_InstanceID >> 2) & 4095, gl_InstanceID >> 14);\n uint splatIndex = texelFetch(ordering, orderingCoord, 0)[gl_InstanceID & 3];\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 bvec3 zeroScales = equal(scales, vec3(0.0));\n if (all(zeroScales)) {\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 vSplatIndex = splatIndex;\n\n \n vec4 viewQuaternion = quatQuat(renderToViewQuat, quaternion);\n\n if (enable2DGS && any(zeroScales)) {\n if (kernelPower == 0.0) {\n supportRadius = gaussianSupportRadius(alpha, supportRadius);\n }\n vSupportRadiusSquared = supportRadius * supportRadius;\n vSplatUv = position.xy * supportRadius;\n\n vec3 offset;\n if (zeroScales.z) {\n offset = vec3(vSplatUv.xy * scales.xy, 0.0);\n } else if (zeroScales.y) {\n offset = vec3(vSplatUv.x * scales.x, 0.0, vSplatUv.y * scales.z);\n } else {\n offset = vec3(0.0, vSplatUv.xy * scales.yz);\n }\n\n vec3 viewPos = viewCenter + quatVec(viewQuaternion, offset);\n gl_Position = projectionMatrix * vec4(viewPos, 1.0);\n vNdc = gl_Position.xyz / gl_Position.w;\n\n #include <logdepthbuf_vertex>\n return;\n }\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 \n float detOrig = a * d - b * b;\n a += blurAmount;\n d += blurAmount;\n float det = a * d - b * b;\n\n \n float blurAdjust = sqrt(max(0.0, detOrig / det));\n alpha *= blurAdjust;\n if (alpha < minAlpha) {\n return;\n }\n vRgba.a = alpha;\n\n \n \n if (kernelPower == 0.0) {\n supportRadius = gaussianSupportRadius(alpha, supportRadius);\n }\n vSupportRadiusSquared = supportRadius * supportRadius;\n vSplatUv = position.xy * supportRadius;\n\n \n float eigenAvg = 0.5 * (a + d);\n float eigenDelta = sqrt(max(0.0, eigenAvg * eigenAvg - det));\n float eigen1 = eigenAvg + eigenDelta;\n float eigen2 = eigenAvg - eigenDelta;\n\n vec2 eigenVec1 = (abs(b) > 0.001) ? 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 scale1 = min(maxPixelRadius, maximumSupportRadius * sqrt(eigen1));\n float scale2 = min(maxPixelRadius, maximumSupportRadius * sqrt(eigen2));\n float supportScale = (maximumSupportRadius > 0.0)\n ? supportRadius / maximumSupportRadius\n : 0.0;\n scale1 *= supportScale;\n scale2 *= supportScale;\n if (scale1 < minPixelRadius && scale2 < minPixelRadius) {\n return;\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 vNdc = ndc;\n gl_Position = vec4(ndc.xy * clipCenter.w, clipCenter.zw);\n\n #include <logdepthbuf_vertex>\n}";
2066
2076
  let shaders = null;
2067
2077
  function getShaders() {
2068
2078
  if (!shaders) {
@@ -2074,7 +2084,7 @@ function getShaders() {
2074
2084
  }
2075
2085
  return shaders;
2076
2086
  }
2077
- var splatGenerate_default = "precision highp float;\nprecision highp int;\nprecision highp usampler2D;\nprecision highp usampler2DArray;\n\n#include <splatDefines>\n\nuniform uint targetLayer;\nuniform int targetBase;\nuniform int targetCount;\n\nuniform usampler2DArray sourceSplats;\nuniform usampler2DArray sourceSplats2;\n\nuniform int numSh;\nuniform usampler2DArray sh1Texture;\nuniform usampler2DArray sh2Texture;\nuniform usampler2DArray sh3TextureA;\nuniform usampler2DArray sh3TextureB;\n\nuniform mat3 objectBasis;\nuniform vec3 objectOffset;\nuniform vec3 objectLnScale;\nuniform vec4 objectQuaternion;\nuniform vec4 recolor;\n\nuniform int numSdfs;\nuniform int numEdits;\nuniform usampler2D sdfTexture;\nuniform usampler2D editTexture;\n\nlayout(location = 0) out uvec4 target;\nlayout(location = 1) out uvec4 target2;\n\nvec3 evaluateSH1(uvec4 data, vec3 direction) {\n return decodeSplatShRgb(data.x) * (-0.4886025 * direction.y)\n + decodeSplatShRgb(data.y) * (0.4886025 * direction.z)\n + decodeSplatShRgb(data.z) * (-0.4886025 * direction.x);\n}\n\nvec3 evaluateSH12(uvec4 first, uvec4 second, vec3 direction) {\n vec3 result = evaluateSH1(first, direction);\n result += decodeSplatShRgb(first.w) * (1.0925484 * direction.x * direction.y);\n result += decodeSplatShRgb(second.x) * (-1.0925484 * direction.y * direction.z);\n result += decodeSplatShRgb(second.y) * (0.3153915 * (2.0 * direction.z * direction.z - direction.x * direction.x - direction.y * direction.y));\n result += decodeSplatShRgb(second.z) * (-1.0925484 * direction.x * direction.z);\n result += decodeSplatShRgb(second.w) * (0.5462742 * (direction.x * direction.x - direction.y * direction.y));\n return result;\n}\n\nvec3 evaluateSH3(uvec4 first, uvec4 second, vec3 direction) {\n float xx = direction.x * direction.x;\n float yy = direction.y * direction.y;\n float zz = direction.z * direction.z;\n return decodeSplatShRgb(first.x) * (-0.5900436 * direction.y * (3.0 * xx - yy))\n + decodeSplatShRgb(first.y) * (2.8906114 * direction.x * direction.y * direction.z)\n + decodeSplatShRgb(first.z) * (-0.4570458 * direction.y * (4.0 * zz - xx - yy))\n + decodeSplatShRgb(first.w) * (0.3731763 * direction.z * (2.0 * zz - 3.0 * xx - 3.0 * yy))\n + decodeSplatShRgb(second.x) * (-0.4570458 * direction.x * (4.0 * zz - xx - yy))\n + decodeSplatShRgb(second.y) * (1.4453057 * direction.z * (xx - yy))\n + decodeSplatShRgb(second.z) * (-0.5900436 * direction.x * (xx - 3.0 * yy));\n}\n\nvec3 evaluateSH(ivec3 coord, vec3 direction) {\n vec3 result = vec3(0.0);\n if (numSh == 1) {\n result = evaluateSH1(texelFetch(sh1Texture, coord, 0), direction);\n } else if (numSh >= 2) {\n result = evaluateSH12(\n texelFetch(sh1Texture, coord, 0),\n texelFetch(sh2Texture, coord, 0),\n direction\n );\n if (numSh >= 3) {\n result += evaluateSH3(\n texelFetch(sh3TextureA, coord, 0),\n texelFetch(sh3TextureB, coord, 0),\n direction\n );\n }\n }\n return result;\n}\n\nvoid unpackSdf(\n int index,\n out uint flags,\n out vec3 center,\n out vec4 quaternion,\n out vec3 scale,\n out vec4 sizes,\n out vec4 sdfRgba\n) {\n uvec4 data = texelFetch(sdfTexture, ivec2(0, index), 0);\n center = vec3(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z));\n flags = data.w;\n data = texelFetch(sdfTexture, ivec2(1, index), 0);\n quaternion = vec4(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z), uintBitsToFloat(data.w));\n data = texelFetch(sdfTexture, ivec2(2, index), 0);\n scale = vec3(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z));\n data = texelFetch(sdfTexture, ivec2(3, index), 0);\n sizes = vec4(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z), uintBitsToFloat(data.w));\n data = texelFetch(sdfTexture, ivec2(4, index), 0);\n sdfRgba = vec4(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z), uintBitsToFloat(data.w));\n}\n\nfloat sdfDistance(uint type, vec3 position, vec4 sizes) {\n switch (type) {\n case 0u: return -INFINITY;\n case 1u: return position.z;\n case 2u: return length(position) - sizes.w;\n case 3u: {\n vec3 q = abs(position) - sizes.xyz + sizes.w;\n return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - sizes.w;\n }\n case 4u: {\n float k0 = length(position / sizes.xyz);\n float k1 = length(position / dot(sizes.xyz, sizes.xyz));\n return k0 * (k0 - 1.0) / k1;\n }\n case 5u: {\n vec2 d = abs(vec2(length(position.xz), position.y)) - sizes.wy;\n return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));\n }\n case 6u: {\n position.y -= clamp(position.y, -0.5 * sizes.y, 0.5 * sizes.y);\n return length(position) - sizes.w;\n }\n case 7u: {\n float angle = 0.25 * PI * sizes.w;\n vec2 c = vec2(sin(angle), cos(angle));\n vec2 q = vec2(length(position.xy), -position.z);\n float distance = length(q - c * max(dot(q, c), 0.0));\n return distance * (((q.x * c.y - q.y * c.x) < 0.0) ? -1.0 : 1.0);\n }\n }\n return INFINITY;\n}\n\nfloat evaluateSdfs(\n int sdfFirst,\n int sdfCount,\n vec3 position,\n float smoothAmount,\n out vec4 resultRgba,\n out vec4 resultRgbaMask\n) {\n float distanceAccum = smoothAmount == 0.0 ? INFINITY : 0.0;\n float maxExponent = -INFINITY;\n resultRgba = vec4(0.0);\n resultRgbaMask = vec4(0.0);\n int sdfLast = min(sdfFirst + sdfCount, numSdfs);\n\n for (int index = sdfFirst; index < sdfLast; ++index) {\n uint flags;\n vec3 center;\n vec4 quaternion;\n vec3 scale;\n vec4 sizes;\n vec4 value;\n unpackSdf(index, flags, center, quaternion, scale, sizes, value);\n vec4 valueMask = vec4(\n (flags & 0x10000u) != 0u ? 1.0 : 0.0,\n (flags & 0x20000u) != 0u ? 1.0 : 0.0,\n (flags & 0x40000u) != 0u ? 1.0 : 0.0,\n (flags & 0x80000u) != 0u ? 1.0 : 0.0\n );\n vec3 sdfPosition = quatVec(quaternion, position * scale) + center;\n float distance = sdfDistance(flags & 0xffu, sdfPosition, sizes);\n if ((flags & 0x100u) != 0u) distance = -distance;\n\n if (smoothAmount == 0.0) {\n if (distance < distanceAccum) {\n distanceAccum = distance;\n resultRgba = value * valueMask;\n resultRgbaMask = valueMask;\n }\n } else {\n float exponent = -distance / smoothAmount;\n if (exponent > maxExponent) {\n float rescale = exp(maxExponent - exponent);\n distanceAccum *= rescale;\n resultRgba *= rescale;\n resultRgbaMask *= rescale;\n maxExponent = exponent;\n }\n float weight = exp(exponent - maxExponent);\n distanceAccum += weight;\n resultRgba += weight * value * valueMask;\n resultRgbaMask += weight * valueMask;\n }\n }\n\n if (smoothAmount == 0.0 || distanceAccum == 0.0) {\n return distanceAccum == 0.0 ? INFINITY : distanceAccum;\n }\n resultRgba /= distanceAccum;\n resultRgbaMask /= distanceAccum;\n return (-log(distanceAccum) - maxExponent) * smoothAmount;\n}\n\nvoid applySdfEdits(vec3 position, inout vec4 rgba) {\n for (int editIndex = 0; editIndex < numEdits; ++editIndex) {\n uvec4 edit = texelFetch(editTexture, ivec2(0, editIndex), 0);\n uint blendMode = edit.x & 0xffu;\n bool invert = (edit.x & 0x100u) != 0u;\n int sdfFirst = int(edit.y & 0xffffu);\n int sdfCount = int(edit.y >> 16u);\n float softEdge = uintBitsToFloat(edit.z);\n float smoothAmount = uintBitsToFloat(edit.w);\n\n vec4 sdfRgba;\n vec4 sdfRgbaMask;\n float distance = evaluateSdfs(\n sdfFirst,\n sdfCount,\n position,\n smoothAmount,\n sdfRgba,\n sdfRgbaMask\n );\n if (invert) distance = -distance;\n float amount = softEdge == 0.0\n ? (distance < 0.0 ? 1.0 : 0.0)\n : clamp(-distance / softEdge + 0.5, 0.0, 1.0);\n vec4 target = rgba;\n switch (blendMode) {\n case 0u:\n target = rgba * (vec4(1.0) + sdfRgba - sdfRgbaMask);\n break;\n case 1u:\n target = rgba * (vec4(1.0) - sdfRgbaMask) + sdfRgba;\n break;\n case 2u:\n target = rgba + sdfRgba;\n break;\n }\n rgba = mix(rgba, target, amount);\n }\n}\n\nvoid produceSplat(int index) {\n ivec3 coord = splatTexCoord(index);\n uvec4 sourceSplat = texelFetch(sourceSplats, coord, 0);\n vec2 alphaShapeAmount = decodeSplatAlphaShapeAmount(sourceSplat);\n vec3 center = decodeSplatCenter(sourceSplat);\n vec3 lnScales;\n vec4 quaternion;\n vec4 rgba;\n decodeSplatAttributesLnScale(\n texelFetch(sourceSplats2, coord, 0),\n alphaShapeAmount.x,\n lnScales,\n quaternion,\n rgba\n );\n if (all(equal(lnScales, vec3(-INFINITY)))) return;\n float shapeAmount = alphaShapeAmount.y;\n\n \n \n \n center = objectBasis * center;\n if (numSh > 0) {\n vec3 worldViewDirection = center + objectOffset;\n vec4 inverseObjectQuaternion = vec4(-objectQuaternion.xyz, objectQuaternion.w);\n vec3 sourceViewDirection = normalize(quatVec(inverseObjectQuaternion, worldViewDirection));\n rgba.rgb += evaluateSH(coord, sourceViewDirection);\n }\n lnScales += objectLnScale;\n quaternion = quatQuat(objectQuaternion, quaternion);\n\n vec3 editPosition = center;\n center += objectOffset;\n\n applySdfEdits(editPosition, rgba);\n vec3 relativeCenter = center;\n \n \n \n rgba *= vec4(recolor.rgb, clamp(recolor.a, 0.0, 1.0));\n \n \n rgba.a = clamp(rgba.a, 0.0, 1.0);\n\n \n encodeSplatLnScale(\n target,\n target2,\n relativeCenter,\n lnScales,\n quaternion,\n rgba,\n shapeAmount\n );\n}\n\nvoid main() {\n int targetIndex = int(targetLayer << SPLAT_TEX_LAYER_BITS)\n + int(uint(gl_FragCoord.y) << SPLAT_TEX_WIDTH_BITS)\n + int(gl_FragCoord.x);\n int index = targetIndex - targetBase;\n\n target = uvec4(0u);\n target2 = uvec4(0u);\n if (index >= 0 && index < targetCount) {\n produceSplat(index);\n }\n}";
2087
+ var splatGenerate_default = "precision highp float;\nprecision highp int;\nprecision highp usampler2D;\nprecision highp usampler2DArray;\n\n#include <splatDefines>\n\nuniform uint targetLayer;\nuniform int targetBase;\nuniform int targetCount;\n\nuniform usampler2DArray sourceSplats;\nuniform usampler2DArray sourceSplats2;\n\nuniform int numSh;\nuniform usampler2DArray sh1Texture;\nuniform usampler2DArray sh2Texture;\nuniform usampler2DArray sh3TextureA;\nuniform usampler2DArray sh3TextureB;\n\nuniform mat3 objectBasis;\nuniform vec3 objectOffset;\nuniform vec3 objectLnScale;\nuniform vec4 objectQuaternion;\nuniform vec4 recolor;\n\nuniform int numSdfs;\nuniform int numEdits;\nuniform usampler2D sdfTexture;\nuniform usampler2D editTexture;\n\nlayout(location = 0) out uvec4 target;\nlayout(location = 1) out uvec4 target2;\n\nconst float MAX_SEMANTIC_OPACITY = 1000.0;\n\nfloat decodeSemanticOpacity(float alpha, float shapeAmount) {\n if (shapeAmount <= 0.0) return alpha;\n\n float kernelShape = 1.0 + 4.0 * shapeAmount;\n float kernelOpacity = exp(\n (kernelShape * kernelShape - 1.0) / 2.718281828459045\n );\n return min(MAX_SEMANTIC_OPACITY, alpha * kernelOpacity);\n}\n\nfloat encodeWideSemanticOpacity(float opacity) {\n opacity = min(opacity, MAX_SEMANTIC_OPACITY);\n float kernelShape = sqrt(log(opacity) * 2.718281828459045 + 1.0);\n return 0.25 * (kernelShape - 1.0);\n}\n\nvec3 evaluateSH1(uvec4 data, vec3 direction) {\n return decodeSplatShRgb(data.x) * (-0.4886025 * direction.y)\n + decodeSplatShRgb(data.y) * (0.4886025 * direction.z)\n + decodeSplatShRgb(data.z) * (-0.4886025 * direction.x);\n}\n\nvec3 evaluateSH12(uvec4 first, uvec4 second, vec3 direction) {\n vec3 result = evaluateSH1(first, direction);\n result += decodeSplatShRgb(first.w) * (1.0925484 * direction.x * direction.y);\n result += decodeSplatShRgb(second.x) * (-1.0925484 * direction.y * direction.z);\n result += decodeSplatShRgb(second.y) * (0.3153915 * (2.0 * direction.z * direction.z - direction.x * direction.x - direction.y * direction.y));\n result += decodeSplatShRgb(second.z) * (-1.0925484 * direction.x * direction.z);\n result += decodeSplatShRgb(second.w) * (0.5462742 * (direction.x * direction.x - direction.y * direction.y));\n return result;\n}\n\nvec3 evaluateSH3(uvec4 first, uvec4 second, vec3 direction) {\n float xx = direction.x * direction.x;\n float yy = direction.y * direction.y;\n float zz = direction.z * direction.z;\n return decodeSplatShRgb(first.x) * (-0.5900436 * direction.y * (3.0 * xx - yy))\n + decodeSplatShRgb(first.y) * (2.8906114 * direction.x * direction.y * direction.z)\n + decodeSplatShRgb(first.z) * (-0.4570458 * direction.y * (4.0 * zz - xx - yy))\n + decodeSplatShRgb(first.w) * (0.3731763 * direction.z * (2.0 * zz - 3.0 * xx - 3.0 * yy))\n + decodeSplatShRgb(second.x) * (-0.4570458 * direction.x * (4.0 * zz - xx - yy))\n + decodeSplatShRgb(second.y) * (1.4453057 * direction.z * (xx - yy))\n + decodeSplatShRgb(second.z) * (-0.5900436 * direction.x * (xx - 3.0 * yy));\n}\n\nvec3 evaluateSH(ivec3 coord, vec3 direction) {\n vec3 result = vec3(0.0);\n if (numSh == 1) {\n result = evaluateSH1(texelFetch(sh1Texture, coord, 0), direction);\n } else if (numSh >= 2) {\n result = evaluateSH12(\n texelFetch(sh1Texture, coord, 0),\n texelFetch(sh2Texture, coord, 0),\n direction\n );\n if (numSh >= 3) {\n result += evaluateSH3(\n texelFetch(sh3TextureA, coord, 0),\n texelFetch(sh3TextureB, coord, 0),\n direction\n );\n }\n }\n return result;\n}\n\nvoid unpackSdf(\n int index,\n out uint flags,\n out vec3 center,\n out vec4 quaternion,\n out vec3 scale,\n out vec4 sizes,\n out vec4 sdfRgba\n) {\n uvec4 data = texelFetch(sdfTexture, ivec2(0, index), 0);\n center = vec3(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z));\n flags = data.w;\n data = texelFetch(sdfTexture, ivec2(1, index), 0);\n quaternion = vec4(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z), uintBitsToFloat(data.w));\n data = texelFetch(sdfTexture, ivec2(2, index), 0);\n scale = vec3(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z));\n data = texelFetch(sdfTexture, ivec2(3, index), 0);\n sizes = vec4(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z), uintBitsToFloat(data.w));\n data = texelFetch(sdfTexture, ivec2(4, index), 0);\n sdfRgba = vec4(uintBitsToFloat(data.x), uintBitsToFloat(data.y), uintBitsToFloat(data.z), uintBitsToFloat(data.w));\n}\n\nfloat sdfDistance(uint type, vec3 position, vec4 sizes) {\n switch (type) {\n case 0u: return -INFINITY;\n case 1u: return position.z;\n case 2u: return length(position) - sizes.w;\n case 3u: {\n vec3 q = abs(position) - sizes.xyz + sizes.w;\n return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - sizes.w;\n }\n case 4u: {\n float k0 = length(position / sizes.xyz);\n float k1 = length(position / dot(sizes.xyz, sizes.xyz));\n return k0 * (k0 - 1.0) / k1;\n }\n case 5u: {\n vec2 d = abs(vec2(length(position.xz), position.y)) - sizes.wy;\n return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));\n }\n case 6u: {\n position.y -= clamp(position.y, -0.5 * sizes.y, 0.5 * sizes.y);\n return length(position) - sizes.w;\n }\n case 7u: {\n float angle = 0.25 * PI * sizes.w;\n vec2 c = vec2(sin(angle), cos(angle));\n vec2 q = vec2(length(position.xy), -position.z);\n float distance = length(q - c * max(dot(q, c), 0.0));\n return distance * (((q.x * c.y - q.y * c.x) < 0.0) ? -1.0 : 1.0);\n }\n }\n return INFINITY;\n}\n\nfloat evaluateSdfs(\n int sdfFirst,\n int sdfCount,\n vec3 position,\n float smoothAmount,\n out vec4 resultRgba,\n out vec4 resultRgbaMask\n) {\n float distanceAccum = smoothAmount == 0.0 ? INFINITY : 0.0;\n float maxExponent = -INFINITY;\n resultRgba = vec4(0.0);\n resultRgbaMask = vec4(0.0);\n int sdfLast = min(sdfFirst + sdfCount, numSdfs);\n\n for (int index = sdfFirst; index < sdfLast; ++index) {\n uint flags;\n vec3 center;\n vec4 quaternion;\n vec3 scale;\n vec4 sizes;\n vec4 value;\n unpackSdf(index, flags, center, quaternion, scale, sizes, value);\n vec4 valueMask = vec4(\n (flags & 0x10000u) != 0u ? 1.0 : 0.0,\n (flags & 0x20000u) != 0u ? 1.0 : 0.0,\n (flags & 0x40000u) != 0u ? 1.0 : 0.0,\n (flags & 0x80000u) != 0u ? 1.0 : 0.0\n );\n vec3 sdfPosition = quatVec(quaternion, position * scale) + center;\n float distance = sdfDistance(flags & 0xffu, sdfPosition, sizes);\n if ((flags & 0x100u) != 0u) distance = -distance;\n\n if (smoothAmount == 0.0) {\n if (distance < distanceAccum) {\n distanceAccum = distance;\n resultRgba = value * valueMask;\n resultRgbaMask = valueMask;\n }\n } else {\n float exponent = -distance / smoothAmount;\n if (exponent > maxExponent) {\n float rescale = exp(maxExponent - exponent);\n distanceAccum *= rescale;\n resultRgba *= rescale;\n resultRgbaMask *= rescale;\n maxExponent = exponent;\n }\n float weight = exp(exponent - maxExponent);\n distanceAccum += weight;\n resultRgba += weight * value * valueMask;\n resultRgbaMask += weight * valueMask;\n }\n }\n\n if (smoothAmount == 0.0 || distanceAccum == 0.0) {\n return distanceAccum == 0.0 ? INFINITY : distanceAccum;\n }\n resultRgba /= distanceAccum;\n resultRgbaMask /= distanceAccum;\n return (-log(distanceAccum) - maxExponent) * smoothAmount;\n}\n\nbool applySdfEdits(\n vec3 position,\n inout vec4 rgba,\n float shapeAmount\n) {\n bool semanticOpacityDecoded = false;\n for (int editIndex = 0; editIndex < numEdits; ++editIndex) {\n uvec4 edit = texelFetch(editTexture, ivec2(0, editIndex), 0);\n uint blendMode = edit.x & 0xffu;\n bool invert = (edit.x & 0x100u) != 0u;\n int sdfFirst = int(edit.y & 0xffffu);\n int sdfCount = int(edit.y >> 16u);\n float softEdge = uintBitsToFloat(edit.z);\n float smoothAmount = uintBitsToFloat(edit.w);\n\n vec4 sdfRgba;\n vec4 sdfRgbaMask;\n float distance = evaluateSdfs(\n sdfFirst,\n sdfCount,\n position,\n smoothAmount,\n sdfRgba,\n sdfRgbaMask\n );\n if (invert) distance = -distance;\n float amount = softEdge == 0.0\n ? (distance < 0.0 ? 1.0 : 0.0)\n : clamp(-distance / softEdge + 0.5, 0.0, 1.0);\n bool editOpacity = amount > 0.0 && sdfRgbaMask.a > 0.0;\n if (editOpacity && !semanticOpacityDecoded) {\n \n \n rgba.a = decodeSemanticOpacity(\n clamp(rgba.a, 0.0, 1.0),\n shapeAmount\n );\n semanticOpacityDecoded = true;\n }\n vec4 target = rgba;\n switch (blendMode) {\n case 0u:\n target = rgba * (vec4(1.0) + sdfRgba - sdfRgbaMask);\n break;\n case 1u:\n target = rgba * (vec4(1.0) - sdfRgbaMask) + sdfRgba;\n break;\n case 2u:\n target = rgba + sdfRgba;\n break;\n }\n rgba = mix(rgba, target, amount);\n }\n return semanticOpacityDecoded;\n}\n\nvoid produceSplat(int index) {\n ivec3 coord = splatTexCoord(index);\n uvec4 sourceSplat = texelFetch(sourceSplats, coord, 0);\n vec2 alphaShapeAmount = decodeSplatAlphaShapeAmount(sourceSplat);\n vec3 center = decodeSplatCenter(sourceSplat);\n vec3 lnScales;\n vec4 quaternion;\n vec4 rgba;\n decodeSplatAttributesLnScale(\n texelFetch(sourceSplats2, coord, 0),\n alphaShapeAmount.x,\n lnScales,\n quaternion,\n rgba\n );\n if (all(equal(lnScales, vec3(-INFINITY)))) return;\n float shapeAmount = alphaShapeAmount.y;\n\n \n \n \n center = objectBasis * center;\n if (numSh > 0) {\n vec3 worldViewDirection = center + objectOffset;\n vec4 inverseObjectQuaternion = vec4(-objectQuaternion.xyz, objectQuaternion.w);\n vec3 sourceViewDirection = normalize(quatVec(inverseObjectQuaternion, worldViewDirection));\n rgba.rgb += evaluateSH(coord, sourceViewDirection);\n }\n lnScales += objectLnScale;\n quaternion = quatQuat(objectQuaternion, quaternion);\n\n vec3 editPosition = center;\n center += objectOffset;\n\n \n float opacityScale = recolor.a;\n bool semanticOpacityDecoded = applySdfEdits(\n editPosition,\n rgba,\n shapeAmount\n );\n rgba.rgb *= recolor.rgb;\n if (!semanticOpacityDecoded && opacityScale >= 1.0) {\n \n \n rgba.a = clamp(rgba.a, 0.0, 1.0);\n } else {\n if (!semanticOpacityDecoded) {\n rgba.a = decodeSemanticOpacity(\n clamp(rgba.a, 0.0, 1.0),\n shapeAmount\n );\n }\n float semanticOpacity = rgba.a * opacityScale;\n if (semanticOpacity <= 1.0) {\n rgba.a = clamp(semanticOpacity, 0.0, 1.0);\n shapeAmount = 0.0;\n } else {\n rgba.a = 1.0;\n shapeAmount = encodeWideSemanticOpacity(semanticOpacity);\n }\n }\n\n encodeSplatLnScale(\n target,\n target2,\n center,\n lnScales,\n quaternion,\n rgba,\n shapeAmount\n );\n}\n\nvoid main() {\n int targetIndex = int(targetLayer << SPLAT_TEX_LAYER_BITS)\n + int(uint(gl_FragCoord.y) << SPLAT_TEX_WIDTH_BITS)\n + int(gl_FragCoord.x);\n int index = targetIndex - targetBase;\n\n target = uvec4(0u);\n target2 = uvec4(0u);\n if (index >= 0 && index < targetCount) {\n produceSplat(index);\n }\n}";
2078
2088
  const rotationMatrix = new THREE__namespace.Matrix4();
2079
2089
  const axisX = new THREE__namespace.Vector3();
2080
2090
  const axisY = new THREE__namespace.Vector3();
@@ -2229,7 +2239,7 @@ const _SplatAccumulator = class _SplatAccumulator {
2229
2239
  mesh.recolor.r,
2230
2240
  mesh.recolor.g,
2231
2241
  mesh.recolor.b,
2232
- mesh.opacity
2242
+ THREE__namespace.MathUtils.clamp(mesh.opacity, 0, 1)
2233
2243
  );
2234
2244
  const edits = mesh.sdfEdits;
2235
2245
  uniforms.numSdfs.value = (edits == null ? void 0 : edits.numSdfs) ?? 0;
@@ -2314,7 +2324,7 @@ const _SplatAccumulator = class _SplatAccumulator {
2314
2324
  }
2315
2325
  const visibleMeshes = [];
2316
2326
  scene.traverseVisible((node) => {
2317
- if (node instanceof SplatMesh && camera.layers.test(node.layers)) {
2327
+ if (node instanceof SplatMesh && camera.layers.test(node.layers) && node.opacity > 0) {
2318
2328
  visibleMeshes.push(node);
2319
2329
  }
2320
2330
  });