playcanvas 2.24.0-beta.33 → 2.24.0-beta.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/build/playcanvas/src/core/core.js +2 -2
  2. package/build/playcanvas/src/framework/components/gsplat/component.d.ts +4 -4
  3. package/build/playcanvas/src/framework/parsers/sog-bundle.js +20 -3
  4. package/build/playcanvas/src/framework/parsers/sog.js +23 -7
  5. package/build/playcanvas/src/scene/gsplat/gsplat-data.d.ts +7 -0
  6. package/build/playcanvas/src/scene/gsplat/gsplat-data.js +1 -0
  7. package/build/playcanvas/src/scene/gsplat/gsplat-resource-base.d.ts +8 -0
  8. package/build/playcanvas/src/scene/gsplat/gsplat-resource-base.js +3 -0
  9. package/build/playcanvas/src/scene/gsplat/gsplat-resource.d.ts +2 -1
  10. package/build/playcanvas/src/scene/gsplat/gsplat-resource.js +8 -1
  11. package/build/playcanvas/src/scene/gsplat/gsplat-sog-blind.d.ts +55 -0
  12. package/build/playcanvas/src/scene/gsplat/gsplat-sog-blind.js +55 -0
  13. package/build/playcanvas/src/scene/gsplat/gsplat-sog-data.d.ts +9 -3
  14. package/build/playcanvas/src/scene/gsplat/gsplat-sog-data.js +58 -29
  15. package/build/playcanvas/src/scene/gsplat/gsplat-sog-resource.d.ts +8 -0
  16. package/build/playcanvas/src/scene/gsplat/gsplat-sog-resource.js +29 -8
  17. package/build/playcanvas/src/scene/gsplat-unified/gsplat-octree.resource.d.ts +8 -0
  18. package/build/playcanvas/src/scene/gsplat-unified/gsplat-octree.resource.js +3 -0
  19. package/build/playcanvas/src/scene/gsplat-unified/gsplat-params.d.ts +3 -2
  20. package/build/playcanvas/src/scene/gsplat-unified/gsplat-params.js +4 -4
  21. package/build/playcanvas/src/scene/gsplat-unified/gsplat-projector.js +1 -1
  22. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/frag/formats/containerCompactWrite.d.ts +1 -1
  23. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/frag/formats/containerCompactWrite.js +1 -1
  24. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/frag/gsplat.d.ts +1 -1
  25. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/frag/gsplat.js +10 -1
  26. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/containerCompactRead.d.ts +1 -1
  27. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/containerCompactRead.js +2 -1
  28. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sog.d.ts +1 -1
  29. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sog.js +25 -5
  30. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogBlind.d.ts +2 -0
  31. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogBlind.js +19 -0
  32. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogBlindField.d.ts +2 -0
  33. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogBlindField.js +6 -0
  34. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogSH.d.ts +1 -1
  35. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogSH.js +5 -2
  36. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplat.d.ts +1 -1
  37. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplat.js +4 -1
  38. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatCommon.d.ts +1 -1
  39. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatCommon.js +5 -1
  40. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatHelpers.d.ts +1 -1
  41. package/build/playcanvas/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatHelpers.js +4 -0
  42. package/build/playcanvas/src/scene/shader-lib/glsl/collections/gsplat-chunks-glsl.d.ts +2 -0
  43. package/build/playcanvas/src/scene/shader-lib/glsl/collections/gsplat-chunks-glsl.js +2 -0
  44. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-projector.d.ts +1 -1
  45. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-projector.js +2 -2
  46. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/frag/formats/containerCompactWrite.d.ts +1 -1
  47. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/frag/formats/containerCompactWrite.js +1 -1
  48. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/frag/gsplat.d.ts +1 -1
  49. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/frag/gsplat.js +11 -2
  50. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/containerCompactRead.d.ts +1 -1
  51. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/containerCompactRead.js +2 -1
  52. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sog.d.ts +1 -1
  53. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sog.js +28 -8
  54. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlind.d.ts +2 -0
  55. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlind.js +19 -0
  56. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlindField.d.ts +2 -0
  57. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlindField.js +6 -0
  58. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogSH.d.ts +1 -1
  59. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogSH.js +18 -3
  60. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplat.d.ts +1 -1
  61. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplat.js +4 -1
  62. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatCommon.d.ts +1 -1
  63. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatCommon.js +5 -1
  64. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHelpers.d.ts +1 -1
  65. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHelpers.js +4 -0
  66. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHybrid.d.ts +1 -1
  67. package/build/playcanvas/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHybrid.js +12 -5
  68. package/build/playcanvas/src/scene/shader-lib/wgsl/collections/gsplat-chunks-wgsl.d.ts +2 -0
  69. package/build/playcanvas/src/scene/shader-lib/wgsl/collections/gsplat-chunks-wgsl.js +2 -0
  70. package/build/playcanvas.d.ts +49 -10
  71. package/build/playcanvas.dbg/src/core/core.js +2 -2
  72. package/build/playcanvas.dbg/src/framework/parsers/sog-bundle.js +20 -3
  73. package/build/playcanvas.dbg/src/framework/parsers/sog.js +23 -7
  74. package/build/playcanvas.dbg/src/scene/gsplat/gsplat-data.js +7 -0
  75. package/build/playcanvas.dbg/src/scene/gsplat/gsplat-resource-base.js +10 -0
  76. package/build/playcanvas.dbg/src/scene/gsplat/gsplat-resource.js +10 -2
  77. package/build/playcanvas.dbg/src/scene/gsplat/gsplat-sog-blind.js +65 -0
  78. package/build/playcanvas.dbg/src/scene/gsplat/gsplat-sog-data.js +66 -32
  79. package/build/playcanvas.dbg/src/scene/gsplat/gsplat-sog-resource.js +42 -8
  80. package/build/playcanvas.dbg/src/scene/gsplat-unified/gsplat-octree.resource.js +10 -0
  81. package/build/playcanvas.dbg/src/scene/gsplat-unified/gsplat-params.js +7 -6
  82. package/build/playcanvas.dbg/src/scene/gsplat-unified/gsplat-projector.js +1 -1
  83. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/frag/formats/containerCompactWrite.js +2 -1
  84. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/frag/gsplat.js +15 -1
  85. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/containerCompactRead.js +3 -1
  86. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sog.js +30 -6
  87. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogBlind.js +27 -0
  88. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogBlindField.js +9 -0
  89. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogSH.js +6 -3
  90. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplat.js +7 -1
  91. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatCommon.js +6 -1
  92. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatHelpers.js +15 -0
  93. package/build/playcanvas.dbg/src/scene/shader-lib/glsl/collections/gsplat-chunks-glsl.js +2 -0
  94. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-projector.js +4 -2
  95. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/frag/formats/containerCompactWrite.js +2 -1
  96. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/frag/gsplat.js +15 -2
  97. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/containerCompactRead.js +3 -1
  98. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sog.js +33 -9
  99. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlind.js +27 -0
  100. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlindField.js +9 -0
  101. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogSH.js +19 -4
  102. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplat.js +7 -1
  103. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatCommon.js +6 -1
  104. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHelpers.js +15 -0
  105. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHybrid.js +16 -5
  106. package/build/playcanvas.dbg/src/scene/shader-lib/wgsl/collections/gsplat-chunks-wgsl.js +2 -0
  107. package/build/playcanvas.dbg.js +531 -104
  108. package/build/playcanvas.dbg.mjs +531 -104
  109. package/build/playcanvas.js +396 -94
  110. package/build/playcanvas.min.js +876 -733
  111. package/build/playcanvas.min.mjs +863 -720
  112. package/build/playcanvas.mjs +391 -94
  113. package/build/playcanvas.prf/src/core/core.js +2 -2
  114. package/build/playcanvas.prf/src/framework/parsers/sog-bundle.js +20 -3
  115. package/build/playcanvas.prf/src/framework/parsers/sog.js +23 -7
  116. package/build/playcanvas.prf/src/scene/gsplat/gsplat-data.js +1 -0
  117. package/build/playcanvas.prf/src/scene/gsplat/gsplat-resource-base.js +3 -0
  118. package/build/playcanvas.prf/src/scene/gsplat/gsplat-resource.js +8 -1
  119. package/build/playcanvas.prf/src/scene/gsplat/gsplat-sog-blind.js +55 -0
  120. package/build/playcanvas.prf/src/scene/gsplat/gsplat-sog-data.js +58 -29
  121. package/build/playcanvas.prf/src/scene/gsplat/gsplat-sog-resource.js +29 -8
  122. package/build/playcanvas.prf/src/scene/gsplat-unified/gsplat-octree.resource.js +3 -0
  123. package/build/playcanvas.prf/src/scene/gsplat-unified/gsplat-params.js +4 -4
  124. package/build/playcanvas.prf/src/scene/gsplat-unified/gsplat-projector.js +1 -1
  125. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/frag/formats/containerCompactWrite.js +1 -1
  126. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/frag/gsplat.js +10 -1
  127. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/containerCompactRead.js +2 -1
  128. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sog.js +25 -5
  129. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogBlind.js +19 -0
  130. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogBlindField.js +6 -0
  131. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/vert/formats/sogSH.js +5 -2
  132. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplat.js +4 -1
  133. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatCommon.js +5 -1
  134. package/build/playcanvas.prf/src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatHelpers.js +4 -0
  135. package/build/playcanvas.prf/src/scene/shader-lib/glsl/collections/gsplat-chunks-glsl.js +2 -0
  136. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-projector.js +2 -2
  137. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/frag/formats/containerCompactWrite.js +1 -1
  138. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/frag/gsplat.js +11 -2
  139. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/containerCompactRead.js +2 -1
  140. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sog.js +28 -8
  141. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlind.js +19 -0
  142. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlindField.js +6 -0
  143. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/formats/sogSH.js +18 -3
  144. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplat.js +4 -1
  145. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatCommon.js +5 -1
  146. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHelpers.js +4 -0
  147. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHybrid.js +12 -5
  148. package/build/playcanvas.prf/src/scene/shader-lib/wgsl/collections/gsplat-chunks-wgsl.js +2 -0
  149. package/build/playcanvas.prf.js +396 -94
  150. package/build/playcanvas.prf.mjs +391 -94
  151. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- const version = "2.24.0-beta.33";
2
- const revision = "217cc5b";
1
+ const version = "2.24.0-beta.34";
2
+ const revision = "eb5f1c2";
3
3
  function extend(target, ex) {
4
4
  for (const prop in ex) {
5
5
  const copy = ex[prop];
@@ -29,13 +29,13 @@
29
29
  * - [Billions of Splats](https://playcanvas.github.io/#/gaussian-splatting/billions)
30
30
  * - [Downtown Streaming](https://playcanvas.github.io/#/gaussian-splatting/downtown)
31
31
  * - [Global Sorting](https://playcanvas.github.io/#/gaussian-splatting/global-sorting)
32
- * - [LOD Instances](https://playcanvas.github.io/#/gaussian-splatting/lod-instances)
32
+ * - [LOD Instances](https://playcanvas.github.io/#/gaussian-splatting/streamed-instances)
33
33
  * - [Multi-Splat](https://playcanvas.github.io/#/gaussian-splatting/multi-splat)
34
34
  * - [Multi-View](https://playcanvas.github.io/#/gaussian-splatting/multi-view)
35
35
  * - [Picking](https://playcanvas.github.io/#/gaussian-splatting/picking)
36
- * - [Reveal Effect](https://playcanvas.github.io/#/gaussian-splatting/reveal)
37
- * - [Shader Effects](https://playcanvas.github.io/#/gaussian-splatting/shader-effects)
38
- * - [Spherical Harmonics](https://playcanvas.github.io/#/gaussian-splatting/spherical-harmonics)
36
+ * - [Reveal Effect](https://playcanvas.github.io/#/gaussian-splatting-fx/reveal)
37
+ * - [Shader Effects](https://playcanvas.github.io/#/gaussian-splatting-fx/shader-effects)
38
+ * - [Spherical Harmonics](https://playcanvas.github.io/#/gaussian-splatting/simple-sh)
39
39
  * - [Streamed LCC2](https://playcanvas.github.io/#/gaussian-splatting/streamed-lcc2)
40
40
  * - [Streamed SOG](https://playcanvas.github.io/#/gaussian-splatting/streamed-sog)
41
41
  * - [Streamed SOG with Spherical Harmonics](https://playcanvas.github.io/#/gaussian-splatting/streamed-sog-sh)
@@ -159,7 +159,14 @@ class SogBundleParser {
159
159
  callback(`Error parsing meta.json: ${err}`);
160
160
  return;
161
161
  }
162
- const filenames = ["means", "scales", "quats", "sh0", "shN"].map((key) => meta[key]?.files ?? []).flat();
162
+ if (meta.version !== void 0 && meta.version !== 2 && meta.version !== 3) {
163
+ callback(`Error loading gsplat: unsupported SOG version ${meta.version} in ${url.original}`);
164
+ return;
165
+ }
166
+ const filenames = [
167
+ ...["means", "scales", "quats", "sh0", "shN"].map((key) => meta[key]?.files ?? []).flat(),
168
+ ...(meta.blind ?? []).map((t) => t.files[0])
169
+ ];
163
170
  const promises = [];
164
171
  for (const filename of filenames) {
165
172
  const file = files.find((f) => f.filename === filename);
@@ -194,7 +201,7 @@ class SogBundleParser {
194
201
  promises.push(promise);
195
202
  }
196
203
  Object.values(textures).forEach((t) => this.app.assets.load(t));
197
- await Promise.allSettled(promises);
204
+ const results = await Promise.allSettled(promises);
198
205
  if (this._shouldAbort(asset, unloaded)) {
199
206
  Object.values(textures).forEach((t) => {
200
207
  assets.remove(t);
@@ -203,6 +210,15 @@ class SogBundleParser {
203
210
  callback(null, null);
204
211
  return;
205
212
  }
213
+ const failed = results.findIndex((r) => r.status === "rejected");
214
+ if (failed !== -1) {
215
+ Object.values(textures).forEach((t) => {
216
+ assets.remove(t);
217
+ t.unload();
218
+ });
219
+ callback(`Error loading gsplat: failed to load ${filenames[failed]} in ${url.original}: ${results[failed].reason}`);
220
+ return;
221
+ }
206
222
  Object.values(textures).forEach((t) => {
207
223
  if (t.file) {
208
224
  t.file.contents = null;
@@ -215,11 +231,12 @@ class SogBundleParser {
215
231
  data.numSplats = meta.count;
216
232
  data.means_l = textures[meta.means.files[0]].resource;
217
233
  data.means_u = textures[meta.means.files[1]].resource;
218
- data.quats = textures[meta.quats.files[0]].resource;
234
+ data.quats = meta.quats ? textures[meta.quats.files[0]].resource : null;
219
235
  data.scales = textures[meta.scales.files[0]].resource;
220
236
  data.sh0 = textures[meta.sh0.files[0]].resource;
221
237
  data.sh_centroids = textures[meta.shN?.files[0]]?.resource;
222
238
  data.sh_labels = textures[meta.shN?.files[1]]?.resource;
239
+ data.blind = (meta.blind ?? []).map((t) => textures[t.files[0]].resource);
223
240
  data.shBands = GSplatSogData.calcBands(data.sh_centroids?.width);
224
241
  if (!decompress) {
225
242
  if (this._shouldAbort(asset, unloaded)) {
@@ -81,16 +81,19 @@ class SogParser {
81
81
  }
82
82
  async loadTextures(url, callback, asset, meta) {
83
83
  const gsplatCentersEnabledAtLoad = this.app.scene?.gsplatCentersEnabled !== false;
84
- if (meta.version !== 2) {
84
+ if (meta.version === void 0) {
85
85
  meta = upgradeMeta(meta);
86
+ } else if (meta.version !== 2 && meta.version !== 3) {
87
+ callback(`Error loading gsplat: unsupported SOG version ${meta.version} in ${url.original}`);
88
+ return;
86
89
  }
87
90
  const { assets } = this.app;
88
- const subs = ["means", "quats", "scales", "sh0", "shN"];
91
+ const subs = ["means", "quats", "scales", "sh0", "shN", "blind"];
89
92
  const textures = {};
90
93
  const promises = [];
91
94
  const base = window.document?.baseURI ?? window.location.href;
92
95
  subs.forEach((sub) => {
93
- const files = meta[sub]?.files ?? [];
96
+ const files = sub === "blind" ? (meta.blind ?? []).map((t) => t.files[0]) : meta[sub]?.files ?? [];
94
97
  textures[sub] = files.map((filename) => {
95
98
  const texture = new Asset(filename, "texture", {
96
99
  url: asset.options?.mapUrl?.(filename) ?? new URL(filename, new URL(url.load, base).toString()).toString(),
@@ -125,7 +128,7 @@ class SogParser {
125
128
  });
126
129
  combineProgress(asset, textureAssets);
127
130
  textureAssets.forEach((t) => assets.load(t));
128
- await Promise.allSettled(promises);
131
+ const results = await Promise.allSettled(promises);
129
132
  if (this._shouldAbort(asset, unloaded)) {
130
133
  textureAssets.forEach((t) => {
131
134
  assets.remove(t);
@@ -134,17 +137,27 @@ class SogParser {
134
137
  callback(null, null);
135
138
  return;
136
139
  }
140
+ const failed = results.findIndex((r) => r.status === "rejected");
141
+ if (failed !== -1) {
142
+ textureAssets.forEach((t) => {
143
+ assets.remove(t);
144
+ t.unload();
145
+ });
146
+ callback(`Error loading gsplat: failed to load ${textureAssets[failed].file.filename} in ${url.original}: ${results[failed].reason}`);
147
+ return;
148
+ }
137
149
  const data = new GSplatSogData();
138
150
  data.url = url.original;
139
151
  data.meta = meta;
140
152
  data.numSplats = meta.count;
141
153
  data.means_l = textures.means[0].resource;
142
154
  data.means_u = textures.means[1].resource;
143
- data.quats = textures.quats[0].resource;
155
+ data.quats = textures.quats[0]?.resource ?? null;
144
156
  data.scales = textures.scales[0].resource;
145
157
  data.sh0 = textures.sh0[0].resource;
146
158
  data.sh_centroids = textures.shN?.[0]?.resource;
147
159
  data.sh_labels = textures.shN?.[1]?.resource;
160
+ data.blind = textures.blind.map((t) => t.resource);
148
161
  data.shBands = GSplatSogData.calcBands(data.sh_centroids?.width);
149
162
  const decompress = asset.data?.decompress;
150
163
  if (!decompress) {
@@ -180,8 +193,11 @@ class SogParser {
180
193
  callback(null, resource);
181
194
  }
182
195
  load(url, callback, asset) {
196
+ const loadTextures = (meta) => {
197
+ this.loadTextures(url, callback, asset, meta).catch((err) => callback(`Error loading gsplat: ${url.original} [${err}]`));
198
+ };
183
199
  if (asset.data?.means) {
184
- this.loadTextures(url, callback, asset, asset.data);
200
+ loadTextures(asset.data);
185
201
  } else {
186
202
  if (typeof url === "string") {
187
203
  url = {
@@ -200,7 +216,7 @@ class SogParser {
200
216
  return;
201
217
  }
202
218
  if (!err) {
203
- this.loadTextures(url, callback, asset, meta);
219
+ loadTextures(meta);
204
220
  } else {
205
221
  callback(`Error loading gsplat meta: ${url.original} [${err}]`);
206
222
  }
@@ -28,6 +28,13 @@ export class GSplatData {
28
28
  * @type {boolean}
29
29
  */
30
30
  activated: boolean;
31
+ /**
32
+ * Application-defined data stored with the splat file, as in glTF's `extras`: the `extras`
33
+ * value of a decompressed SOG's meta.json. Undefined when the source has none.
34
+ *
35
+ * @type {*}
36
+ */
37
+ extras: any;
31
38
  getProp(name: any, elementName?: string): import("../../framework/parsers/ply.js").DataType;
32
39
  getElement(name: any): PlyElement;
33
40
  addProp(name: any, storage: any): void;
@@ -69,6 +69,7 @@ class GSplatData {
69
69
  numSplats;
70
70
  comments;
71
71
  activated = false;
72
+ extras;
72
73
  constructor(elements, comments = []) {
73
74
  this.elements = elements;
74
75
  this.numSplats = this.getElement("vertex").count;
@@ -171,6 +171,14 @@ export class GSplatResourceBase {
171
171
  * @ignore
172
172
  */
173
173
  get supportsWorkBufferGeometry(): boolean;
174
+ /**
175
+ * Application-defined data stored with the splat file, as in glTF's `extras`: the `extras`
176
+ * value of a SOG's meta.json. The engine attaches no meaning to it. Undefined when the file
177
+ * has none, and for formats that cannot carry it.
178
+ *
179
+ * @type {*}
180
+ */
181
+ get extras(): any;
174
182
  /**
175
183
  * Gets the number of splats in the resource.
176
184
  *
@@ -77,6 +77,9 @@ class GSplatResourceBase {
77
77
  get supportsWorkBufferGeometry() {
78
78
  return false;
79
79
  }
80
+ get extras() {
81
+ return void 0;
82
+ }
80
83
  static createMesh(device) {
81
84
  const splatInstanceSize = GSplatResourceBase.instanceSize;
82
85
  const meshPositions = new Float32Array(12 * splatInstanceSize);
@@ -22,7 +22,8 @@ export class GSplatResource extends GSplatResourceBase {
22
22
  /**
23
23
  * Updates pixel data of splatColor texture based on the supplied color components and opacity.
24
24
  * Assumes that the texture is using an RGBA format where RGB are color components influenced
25
- * by SH spherical harmonics and A is opacity after a sigmoid transformation.
25
+ * by SH spherical harmonics and A is opacity after a sigmoid transformation, plus the optional
26
+ * `opacity_excess` property: the opacity above 1 that merged (decimated) gaussians carry.
26
27
  *
27
28
  * @param {GSplatData} gsplatData - The source data
28
29
  * @ignore
@@ -57,6 +57,9 @@ class GSplatResource extends GSplatResourceBase {
57
57
  configureMaterialDefines(defines) {
58
58
  defines.set("SH_BANDS", this.shBands);
59
59
  }
60
+ get extras() {
61
+ return this.gsplatData.extras;
62
+ }
60
63
  updateColorData(gsplatData) {
61
64
  const texture = this.streams.getTexture("splatColor");
62
65
  if (!texture) {
@@ -68,13 +71,17 @@ class GSplatResource extends GSplatResourceBase {
68
71
  const cg = gsplatData.getProp("f_dc_1");
69
72
  const cb = gsplatData.getProp("f_dc_2");
70
73
  const ca = gsplatData.getProp("opacity");
74
+ const excess = gsplatData.getProp("opacity_excess");
71
75
  const activated = gsplatData.activated;
72
76
  const SH_C0 = 0.28209479177387814;
73
77
  for (let i = 0; i < this.numSplats; ++i) {
74
78
  const r = cr[i] * SH_C0 + 0.5;
75
79
  const g = cg[i] * SH_C0 + 0.5;
76
80
  const b = cb[i] * SH_C0 + 0.5;
77
- const a = activated ? ca[i] : 1 / (1 + Math.exp(-ca[i]));
81
+ let a = activated ? ca[i] : 1 / (1 + Math.exp(-ca[i]));
82
+ if (excess && excess[i] > 0) {
83
+ a = Math.min(a + excess[i], 1.5625);
84
+ }
78
85
  data[i * 4 + 0] = float2Half(r);
79
86
  data[i * 4 + 1] = float2Half(g);
80
87
  data[i * 4 + 2] = float2Half(b);
@@ -0,0 +1,55 @@
1
+ export type BlindField = {
2
+ /**
3
+ * - Index of the field's texture in `meta.blind`.
4
+ */
5
+ texture: number;
6
+ /**
7
+ * - The field name.
8
+ */
9
+ name: string;
10
+ /**
11
+ * - Shader identifier suffix derived from the name.
12
+ */
13
+ id: string;
14
+ /**
15
+ * - The encoding.
16
+ */
17
+ type: string;
18
+ /**
19
+ * - Index of the field's first byte in the texel (0 = R).
20
+ */
21
+ offset: number;
22
+ /**
23
+ * - Number of bytes.
24
+ */
25
+ bytes: number;
26
+ /**
27
+ * - Value of the smallest code (unorm encodings).
28
+ */
29
+ min: number;
30
+ /**
31
+ * - Value of the largest code (unorm encodings).
32
+ */
33
+ max: number;
34
+ };
35
+ /**
36
+ * Shader code for the blind field accessors, appended to the SOG read code: the
37
+ * `gsplatSogBlindVS` decoding helpers, then one accessor per field from the `sogBlindField`
38
+ * template. The textures are declared as streams `blind0`, `blind1`, ... whose generated
39
+ * `loadBlind<i>()` returns the RGBA8 texel as normalized floats.
40
+ *
41
+ * @param {BlindField[]} fields - The fields, from {@link parseBlindFields}.
42
+ * @param {boolean} wgsl - Generate WGSL (else GLSL).
43
+ * @returns {string} The accessor functions, empty when there are no fields.
44
+ */
45
+ export function blindAccessors(fields: BlindField[], wgsl: boolean): string;
46
+ /**
47
+ * The fields of a SOG meta's blind textures, each with its texture index, byte offset and shader
48
+ * identifier. Fields are packed in order, so each starts where the previous field of its texture
49
+ * ended. The data is assumed valid, as the tools writing it check it; debug builds report
50
+ * problems.
51
+ *
52
+ * @param {object} meta - The SOG meta.json.
53
+ * @returns {BlindField[]} The fields.
54
+ */
55
+ export function parseBlindFields(meta: object): BlindField[];
@@ -0,0 +1,55 @@
1
+ import glslBlindField from "../shader-lib/glsl/chunks/gsplat/vert/formats/sogBlindField.js";
2
+ import wgslBlindField from "../shader-lib/wgsl/chunks/gsplat/vert/formats/sogBlindField.js";
3
+ const BLIND_TYPE_BYTES = { u8: 1, u16: 2, u24: 3, u32: 4, f16: 2, f32: 4, unorm8: 1, unorm16: 2 };
4
+ const DEFAULT_RANGE = [0, 1];
5
+ const isIntegerType = (type) => type[0] === "u" && !type.startsWith("unorm");
6
+ const RE_ID = /\{id\}/g;
7
+ const RE_RETURN_TYPE = /\{returnType\}/g;
8
+ const RE_TEXTURE = /\{texture\}/g;
9
+ const RE_OFFSET = /\{offset\}/g;
10
+ const RE_BYTES = /\{bytes\}/g;
11
+ const RE_DECODE = /\{decode\}/g;
12
+ const blindFieldId = (name) => name.replace(/\W/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
13
+ const parseBlindFields = (meta) => {
14
+ const fields = [];
15
+ (meta.blind ?? []).forEach((texture, t) => {
16
+ let offset = 0;
17
+ for (const f of texture.fields) {
18
+ const bytes = BLIND_TYPE_BYTES[f.type];
19
+ const [min, max] = f.range ?? DEFAULT_RANGE;
20
+ fields.push({ texture: t, name: f.name, id: blindFieldId(f.name), type: f.type, offset, bytes, min, max });
21
+ offset += bytes;
22
+ }
23
+ });
24
+ return fields;
25
+ };
26
+ const floatLiteral = (v) => {
27
+ const s = String(v);
28
+ return /[.e]/i.test(s) ? s : `${s}.0`;
29
+ };
30
+ const blindAccessors = (fields, wgsl) => {
31
+ if (!fields.length) {
32
+ return "";
33
+ }
34
+ const template = wgsl ? wgslBlindField : glslBlindField;
35
+ const accessors = fields.map((f) => {
36
+ const integer = isIntegerType(f.type);
37
+ let decode = "bits";
38
+ if (f.type === "f16") {
39
+ decode = "sogBlindF16(bits)";
40
+ } else if (f.type === "f32") {
41
+ decode = "sogBlindF32(bits)";
42
+ } else if (!integer) {
43
+ const steps = f.type === "unorm8" ? "255.0" : "65535.0";
44
+ decode = `sogBlindUnorm(bits, ${steps}, ${floatLiteral(f.min)}, ${floatLiteral(f.max)})`;
45
+ }
46
+ return template.replace(RE_ID, f.id).replace(RE_RETURN_TYPE, integer ? wgsl ? "u32" : "uint" : wgsl ? "f32" : "float").replace(RE_TEXTURE, String(f.texture)).replace(RE_OFFSET, String(f.offset)).replace(RE_BYTES, String(f.bytes)).replace(RE_DECODE, decode);
47
+ });
48
+ return `
49
+ #include "gsplatSogBlindVS"
50
+ ${accessors.join("")}`;
51
+ };
52
+ export {
53
+ blindAccessors,
54
+ parseBlindFields
55
+ };
@@ -10,7 +10,13 @@ export class GSplatSogData {
10
10
  sh_centroids: any;
11
11
  sh_labels: any;
12
12
  /**
13
- * V2-only codebook LUT (256x1 RGBA32F): .r = scales, .g = sh0, .b = shN, .a unused.
13
+ * V3 per-gaussian blind data textures (RGBA8), one per `meta.blind` entry.
14
+ *
15
+ * @type {Texture[]}
16
+ */
17
+ blind: Texture[];
18
+ /**
19
+ * V2/V3 codebook LUT (256x1 RGBA32F): .r = scales, .g = sh0, .b = shN, .a unused.
14
20
  * Built from meta codebooks in prepareCodebook(). Null for V1 assets.
15
21
  *
16
22
  * @type {Texture|null}
@@ -49,8 +55,8 @@ export class GSplatSogData {
49
55
  decompress(): Promise<GSplatData>;
50
56
  generateCenters(): Promise<void>;
51
57
  /**
52
- * Creates the V2 codebook LUT texture. Packs the three 256-entry scalar codebooks
53
- * (scales, sh0, shN) into a single 256x1 RGBA32F texture:
58
+ * Creates the V2/V3 codebook LUT texture. Packs the 256-entry scalar codebooks into a
59
+ * single 256x1 RGBA32F texture:
54
60
  * - .r = scales codebook
55
61
  * - .g = sh0 codebook
56
62
  * - .b = shN codebook
@@ -29,6 +29,11 @@ const readImageDataAsync = (texture) => {
29
29
  immediate: true
30
30
  });
31
31
  };
32
+ const shCoeffs = (shBands) => ({ 1: 3, 2: 8, 3: 15, 4: 24 })[shBands] ?? 0;
33
+ const decodeSogOpacity = (b) => {
34
+ const s = b / 204;
35
+ return s * s;
36
+ };
32
37
  const resolve = (scope, values) => {
33
38
  for (const key in values) {
34
39
  scope.resolve(key).setValue(values[key]);
@@ -39,15 +44,18 @@ class GSplatSogIterator {
39
44
  const lerp = (a, b, t) => a * (1 - t) + b * t;
40
45
  const { meta, shBands } = data;
41
46
  const { means, scales, sh0, shN } = meta;
42
- const means_l_data = p && data.means_l._levels[0];
43
- const means_u_data = p && data.means_u._levels[0];
44
- const quats_data = r && data.quats._levels[0];
45
- const scales_data = s && data.scales._levels[0];
47
+ const v3 = meta.version === 3;
48
+ const codebooks = meta.version >= 2;
49
+ const means_l_data = (p || r && v3) && data.means_l._levels[0];
50
+ const means_u_data = (p || r && v3) && data.means_u._levels[0];
51
+ const quats_data = r && !v3 && data.quats._levels[0];
52
+ const scales_data = (s || r && v3) && data.scales._levels[0];
46
53
  const sh0_data = c && data.sh0._levels[0];
47
54
  const sh_labels_data = sh && data.sh_labels._levels[0];
48
55
  const sh_centroids_data = sh && data.sh_centroids._levels[0];
49
56
  const norm = Math.SQRT2;
50
- const coeffs = { 1: 3, 2: 8, 3: 15 }[shBands] ?? 0;
57
+ const coeffs = shCoeffs(shBands);
58
+ const shStride = shBands > 3 ? 24 : 15;
51
59
  this.read = (i) => {
52
60
  if (p) {
53
61
  const nx = lerp(means.mins[0], means.maxs[0], ((means_u_data[i * 4 + 0] << 8) + means_l_data[i * 4 + 0]) / 65535);
@@ -57,7 +65,15 @@ class GSplatSogIterator {
57
65
  p.y = Math.sign(ny) * (Math.exp(Math.abs(ny)) - 1);
58
66
  p.z = Math.sign(nz) * (Math.exp(Math.abs(nz)) - 1);
59
67
  }
60
- if (r) {
68
+ if (r && v3) {
69
+ const px = (means_l_data[i * 4 + 3] - 128) / 127;
70
+ const py = (means_u_data[i * 4 + 3] - 128) / 127;
71
+ const pz = (scales_data[i * 4 + 3] - 128) / 127;
72
+ const len = Math.sqrt(px * px + py * py + pz * pz);
73
+ const t = len * Math.PI * 0.5;
74
+ const k = len > 1e-12 ? Math.sin(t) / len : Math.PI * 0.5;
75
+ r.set(px * k, py * k, pz * k, Math.cos(t));
76
+ } else if (r) {
61
77
  const a = (quats_data[i * 4 + 0] / 255 - 0.5) * norm;
62
78
  const b = (quats_data[i * 4 + 1] / 255 - 0.5) * norm;
63
79
  const c2 = (quats_data[i * 4 + 2] / 255 - 0.5) * norm;
@@ -79,7 +95,7 @@ class GSplatSogIterator {
79
95
  }
80
96
  }
81
97
  if (s) {
82
- if (meta.version === 2) {
98
+ if (codebooks) {
83
99
  const sx = scales.codebook[scales_data[i * 4 + 0]];
84
100
  const sy = scales.codebook[scales_data[i * 4 + 1]];
85
101
  const sz = scales.codebook[scales_data[i * 4 + 2]];
@@ -92,11 +108,11 @@ class GSplatSogIterator {
92
108
  }
93
109
  }
94
110
  if (c) {
95
- if (meta.version === 2) {
111
+ if (codebooks) {
96
112
  const r2 = sh0.codebook[sh0_data[i * 4 + 0]];
97
113
  const g = sh0.codebook[sh0_data[i * 4 + 1]];
98
114
  const b = sh0.codebook[sh0_data[i * 4 + 2]];
99
- const a = sh0_data[i * 4 + 3] / 255;
115
+ const a = v3 ? decodeSogOpacity(sh0_data[i * 4 + 3]) : sh0_data[i * 4 + 3] / 255;
100
116
  c.set(
101
117
  0.5 + r2 * SH_C0,
102
118
  0.5 + g * SH_C0,
@@ -117,19 +133,19 @@ class GSplatSogIterator {
117
133
  }
118
134
  }
119
135
  if (sh) {
120
- const n = sh_labels_data[i * 4 + 0] + (sh_labels_data[i * 4 + 1] << 8);
136
+ const n = sh_labels_data[i * 4 + 0] + (sh_labels_data[i * 4 + 1] << 8) + (v3 ? sh_labels_data[i * 4 + 2] << 16 : 0);
121
137
  const u = n % 64 * coeffs;
122
138
  const v = Math.floor(n / 64);
123
- if (meta.version === 2) {
139
+ if (codebooks) {
124
140
  for (let j = 0; j < 3; ++j) {
125
141
  for (let k = 0; k < coeffs; ++k) {
126
- sh[j * 15 + k] = shN.codebook[sh_centroids_data[(u + k) * 4 + j + v * data.sh_centroids.width * 4]];
142
+ sh[j * shStride + k] = shN.codebook[sh_centroids_data[(u + k) * 4 + j + v * data.sh_centroids.width * 4]];
127
143
  }
128
144
  }
129
145
  } else {
130
146
  for (let j = 0; j < 3; ++j) {
131
147
  for (let k = 0; k < coeffs; ++k) {
132
- sh[j * 15 + k] = lerp(shN.mins, shN.maxs, sh_centroids_data[(u + k) * 4 + j + v * data.sh_centroids.width * 4] / 255);
148
+ sh[j * shStride + k] = lerp(shN.mins, shN.maxs, sh_centroids_data[(u + k) * 4 + j + v * data.sh_centroids.width * 4] / 255);
133
149
  }
134
150
  }
135
151
  }
@@ -147,6 +163,7 @@ class GSplatSogData {
147
163
  sh0;
148
164
  sh_centroids;
149
165
  sh_labels;
166
+ blind = [];
150
167
  codebookTexture = null;
151
168
  url = "";
152
169
  _centers = null;
@@ -162,12 +179,13 @@ class GSplatSogData {
162
179
  this.sh0?.destroy();
163
180
  this.sh_centroids?.destroy();
164
181
  this.sh_labels?.destroy();
182
+ this.blind.forEach((t) => t.destroy());
165
183
  this.codebookTexture?.destroy();
166
184
  this.codebookTexture = null;
167
185
  }
168
186
  // calculate the number of bands given the centroids texture width
169
187
  static calcBands(centroidsWidth) {
170
- const shBandsWidths = { 192: 1, 512: 2, 960: 3 };
188
+ const shBandsWidths = { 192: 1, 512: 2, 960: 3, 1536: 4 };
171
189
  return shBandsWidths[centroidsWidth] ?? 0;
172
190
  }
173
191
  destroy() {
@@ -228,22 +246,27 @@ class GSplatSogData {
228
246
  "rot_3"
229
247
  ];
230
248
  this._patchCodebooks();
231
- const { shBands } = this;
249
+ const { shBands, meta } = this;
250
+ const restCount = shBands > 3 ? 72 : 45;
232
251
  const { means_l, means_u, quats, scales, sh0, sh_labels, sh_centroids } = this;
233
252
  means_l._levels[0] = await readImageDataAsync(means_l);
234
253
  means_u._levels[0] = await readImageDataAsync(means_u);
235
- quats._levels[0] = await readImageDataAsync(quats);
254
+ if (quats) quats._levels[0] = await readImageDataAsync(quats);
236
255
  scales._levels[0] = await readImageDataAsync(scales);
237
256
  sh0._levels[0] = await readImageDataAsync(sh0);
238
257
  if (shBands > 0) {
239
258
  sh_labels._levels[0] = await readImageDataAsync(sh_labels);
240
259
  sh_centroids._levels[0] = await readImageDataAsync(sh_centroids);
241
260
  const shMembers = [];
242
- for (let i = 0; i < 45; ++i) {
261
+ for (let i = 0; i < restCount; ++i) {
243
262
  shMembers.push(`f_rest_${i}`);
244
263
  }
245
264
  members.splice(members.indexOf("f_dc_0") + 1, 0, ...shMembers);
246
265
  }
266
+ const hasExcess = meta.version === 3 && (meta.opacity?.max ?? 1) > 1;
267
+ if (hasExcess) {
268
+ members.push("opacity_excess");
269
+ }
247
270
  const data = {};
248
271
  members.forEach((name) => {
249
272
  data[name] = new Float32Array(this.numSplats);
@@ -252,7 +275,7 @@ class GSplatSogData {
252
275
  const r = new Quat();
253
276
  const s = new Vec3();
254
277
  const c = new Vec4();
255
- const sh = shBands > 0 ? new Float32Array(45) : null;
278
+ const sh = shBands > 0 ? new Float32Array(restCount) : null;
256
279
  const iter = this.createIter(p, r, s, c, sh);
257
280
  for (let i = 0; i < this.numSplats; ++i) {
258
281
  iter.read(i);
@@ -270,24 +293,30 @@ class GSplatSogData {
270
293
  data.f_dc_1[i] = (c.y - 0.5) / SH_C0;
271
294
  data.f_dc_2[i] = (c.z - 0.5) / SH_C0;
272
295
  data.opacity[i] = c.w <= 0 ? -40 : c.w >= 1 ? 40 : -Math.log(1 / c.w - 1);
296
+ if (hasExcess) {
297
+ data.opacity_excess[i] = c.w > 1 ? c.w - 1 : 0;
298
+ }
273
299
  if (sh) {
274
- for (let c2 = 0; c2 < 45; ++c2) {
300
+ for (let c2 = 0; c2 < restCount; ++c2) {
275
301
  data[`f_rest_${c2}`][i] = sh[c2];
276
302
  }
277
303
  }
278
304
  }
279
- return new GSplatData([{
305
+ const properties = members.map((name) => {
306
+ return {
307
+ name,
308
+ type: "float",
309
+ byteSize: 4,
310
+ storage: data[name]
311
+ };
312
+ });
313
+ const result = new GSplatData([{
280
314
  name: "vertex",
281
315
  count: this.numSplats,
282
- properties: members.map((name) => {
283
- return {
284
- name,
285
- type: "float",
286
- byteSize: 4,
287
- storage: data[name]
288
- };
289
- })
316
+ properties
290
317
  }]);
318
+ result.extras = meta.extras;
319
+ return result;
291
320
  }
292
321
  async generateCenters() {
293
322
  const { device, width, height } = this.means_l;
@@ -383,7 +412,7 @@ class GSplatSogData {
383
412
  const device = this.means_l?.device;
384
413
  if (this.destroyed || !device || device._destroyed) return;
385
414
  this._patchCodebooks();
386
- if (this.meta.version === 2) {
415
+ if (this.meta.version >= 2) {
387
416
  this._createCodebookTexture();
388
417
  }
389
418
  }
@@ -17,6 +17,14 @@ export class GSplatSogResource extends GSplatResourceBase {
17
17
  * @ignore
18
18
  */
19
19
  constructor(device: GraphicsDevice, gsplatData: GSplatSogData, options?: object);
20
+ /**
21
+ * The `SOG_BLIND_<name>` define of each blind field, built once so setting the material
22
+ * defines on every work buffer update allocates nothing.
23
+ *
24
+ * @type {string[]}
25
+ * @private
26
+ */
27
+ private _blindDefines;
20
28
  /**
21
29
  * Opts each of the owned source textures into releasing its CPU-side ImageBitmap after
22
30
  * upload. Called by the gsplat octree, which re-creates these resources from scratch on