@heliguy-xyz/splat-viewer 1.0.0-rc.25 → 1.0.0-rc.26

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 (24) hide show
  1. package/README.md +39 -0
  2. package/dist/web-component/splat-viewer.esm.js +601 -548
  3. package/dist/web-component/splat-viewer.esm.min.js +1 -1
  4. package/dist/web-component/splat-viewer.js +601 -548
  5. package/dist/web-component/splat-viewer.min.js +1 -1
  6. package/dist/web-component/types/web-component/SplatViewerCore.d.ts +1 -0
  7. package/dist/web-component/types/web-component/SplatViewerCore.d.ts.map +1 -1
  8. package/dist/web-component/types/web-component/SplatViewerElement.d.ts +2 -0
  9. package/dist/web-component/types/web-component/SplatViewerElement.d.ts.map +1 -1
  10. package/dist/web-component/types/web-component/types/attributes.d.ts +3 -0
  11. package/dist/web-component/types/web-component/types/attributes.d.ts.map +1 -1
  12. package/dist/web-component/types/web-component/types/core.d.ts +2 -0
  13. package/dist/web-component/types/web-component/types/core.d.ts.map +1 -1
  14. package/dist/web-component/types/web-component/utils/config.d.ts.map +1 -1
  15. package/dist/web-component/web-component/SplatViewerCore.d.ts +1 -0
  16. package/dist/web-component/web-component/SplatViewerCore.d.ts.map +1 -1
  17. package/dist/web-component/web-component/SplatViewerElement.d.ts +2 -0
  18. package/dist/web-component/web-component/SplatViewerElement.d.ts.map +1 -1
  19. package/dist/web-component/web-component/types/attributes.d.ts +3 -0
  20. package/dist/web-component/web-component/types/attributes.d.ts.map +1 -1
  21. package/dist/web-component/web-component/types/core.d.ts +2 -0
  22. package/dist/web-component/web-component/types/core.d.ts.map +1 -1
  23. package/dist/web-component/web-component/utils/config.d.ts.map +1 -1
  24. package/package.json +1 -1
@@ -139526,6 +139526,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
139526
139526
  enableStats: false,
139527
139527
  autoFocus: true,
139528
139528
  maxSplats: 2000000,
139529
+ previewMode: false,
139529
139530
  camera: {
139530
139531
  position: { x: 0, y: 0, z: 10 },
139531
139532
  target: { x: 0, y: 0, z: 0 },
@@ -139615,6 +139616,10 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
139615
139616
  if (enableStats !== null) {
139616
139617
  config.enableStats = parseBoolean(enableStats);
139617
139618
  }
139619
+ const previewMode = element.getAttribute('preview-mode');
139620
+ if (previewMode !== null) {
139621
+ config.previewMode = parseBoolean(previewMode);
139622
+ }
139618
139623
  // Parse number attributes
139619
139624
  const maxSplats = element.getAttribute('max-splats');
139620
139625
  if (maxSplats !== null) {
@@ -143168,222 +143173,222 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
143168
143173
  }
143169
143174
  }
143170
143175
 
143171
- const vertexShader$6 = /* glsl */ `
143172
- attribute vec2 vertex_position;
143173
- void main(void) {
143174
- gl_Position = vec4(vertex_position, 0.0, 1.0);
143175
- }
143176
- `;
143177
- const fragmentShader$6 = /* glsl */ `
143178
- uniform highp usampler2D transformA; // splat center x, y, z
143179
- uniform highp usampler2D splatTransform; // transform palette index
143180
- uniform sampler2D transformPalette; // palette of transforms
143181
- uniform sampler2D splatState; // per-splat state
143182
- uniform highp ivec3 splat_params; // texture width, texture height, num splats
143183
- uniform highp uint mode; // 0: selected, 1: visible
143184
-
143185
- // calculate min and max for a single column of splats
143186
- void main(void) {
143187
-
143188
- vec3 boundMin = vec3(1e6);
143189
- vec3 boundMax = vec3(-1e6);
143190
-
143191
- for (int id = 0; id < splat_params.y; id++) {
143192
- // calculate splatUV
143193
- ivec2 splatUV = ivec2(gl_FragCoord.x, id);
143194
-
143195
- // skip out-of-range splats
143196
- if ((splatUV.x + splatUV.y * splat_params.x) >= splat_params.z) {
143197
- continue;
143198
- }
143199
-
143200
- // read splat state
143201
- uint state = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
143202
-
143203
- // skip deleted or locked splats
143204
- if (((mode == 0u) && (state != 1u)) || ((mode == 1u) && ((state & 4u) != 0u))) {
143205
- continue;
143206
- }
143207
-
143208
- // read splat center
143209
- vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
143210
-
143211
- // apply optional per-splat transform
143212
- uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
143213
- if (transformIndex > 0u) {
143214
- // read transform matrix
143215
- int u = int(transformIndex % 512u) * 3;
143216
- int v = int(transformIndex / 512u);
143217
-
143218
- mat3x4 t;
143219
- t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
143220
- t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
143221
- t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
143222
-
143223
- center = vec4(center, 1.0) * t;
143224
- }
143225
-
143226
- boundMin = min(boundMin, mix(center, boundMin, isinf(center)));
143227
- boundMax = max(boundMax, mix(center, boundMax, isinf(center)));
143228
- }
143229
-
143230
- pcFragColor0 = vec4(boundMin, 0.0);
143231
- pcFragColor1 = vec4(boundMax, 0.0);
143232
- }
143233
- `;
143234
-
143235
- const vertexShader$5 = /* glsl */ `
143236
- attribute vec2 vertex_position;
143237
- void main(void) {
143238
- gl_Position = vec4(vertex_position, 0.0, 1.0);
143239
- }
143240
- `;
143241
- const fragmentShader$5 = /* glsl */ `
143242
- uniform highp usampler2D transformA; // splat center x, y, z
143243
- uniform highp usampler2D splatTransform; // transform palette index
143244
- uniform sampler2D transformPalette; // palette of transforms
143245
- uniform uvec2 splat_params; // splat texture width, num splats
143246
-
143247
- uniform mat4 matrix_model;
143248
- uniform mat4 matrix_viewProjection;
143249
-
143250
- uniform uvec2 output_params; // output width, height
143251
-
143252
- // 0: mask, 1: rect, 2: sphere
143253
- uniform int mode;
143254
-
143255
- // mask params
143256
- uniform sampler2D mask; // mask in alpha channel
143257
- uniform vec2 mask_params; // mask width, height
143258
-
143259
- // rect params
143260
- uniform vec4 rect_params; // rect x, y, width, height
143261
-
143262
- // sphere params
143263
- uniform vec4 sphere_params; // sphere x, y, z, radius
143264
-
143265
- // box params
143266
- uniform vec4 box_params; // box x, y, z
143267
- uniform vec4 aabb_params; // len x, y, z
143268
-
143269
- void main(void) {
143270
- // calculate output id
143271
- uvec2 outputUV = uvec2(gl_FragCoord);
143272
- uint outputId = (outputUV.x + outputUV.y * output_params.x) * 4u;
143273
-
143274
- vec4 clr = vec4(0.0);
143275
-
143276
- for (uint i = 0u; i < 4u; i++) {
143277
- uint id = outputId + i;
143278
-
143279
- if (id >= splat_params.y) {
143280
- continue;
143281
- }
143282
-
143283
- // calculate splatUV
143284
- ivec2 splatUV = ivec2(
143285
- int(id % splat_params.x),
143286
- int(id / splat_params.x)
143287
- );
143288
-
143289
- // read splat center
143290
- vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
143291
-
143292
- // apply optional per-splat transform
143293
- uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
143294
- if (transformIndex > 0u) {
143295
- // read transform matrix
143296
- int u = int(transformIndex % 512u) * 3;
143297
- int v = int(transformIndex / 512u);
143298
-
143299
- mat3x4 t;
143300
- t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
143301
- t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
143302
- t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
143303
-
143304
- center = vec4(center, 1.0) * t;
143305
- }
143306
-
143307
- // transform to clip space and discard if outside
143308
- vec3 world = (matrix_model * vec4(center, 1.0)).xyz;
143309
- vec4 clip = matrix_viewProjection * vec4(world, 1.0);
143310
- vec3 ndc = clip.xyz / clip.w;
143311
-
143312
- // skip offscreen fragments
143313
- if (!any(greaterThan(abs(ndc), vec3(1.0)))) {
143314
- if (mode == 0) {
143315
- // select by mask
143316
- ivec2 maskUV = ivec2((ndc.xy * vec2(0.5, -0.5) + 0.5) * mask_params);
143317
- clr[i] = texelFetch(mask, maskUV, 0).a < 1.0 ? 0.0 : 1.0;
143318
- } else if (mode == 1) {
143319
- // select by rect
143320
- clr[i] = all(greaterThan(ndc.xy * vec2(1.0, -1.0), rect_params.xy)) && all(lessThan(ndc.xy * vec2(1.0, -1.0), rect_params.zw)) ? 1.0 : 0.0;
143321
- } else if (mode == 2) {
143322
- // select by sphere
143323
- clr[i] = length(world - sphere_params.xyz) < sphere_params.w ? 1.0 : 0.0;
143324
- } else if (mode == 3) {
143325
- // select by box
143326
- vec3 relativePosition = world - box_params.xyz;
143327
- bool isInsideCube = true;
143328
- if (relativePosition.x < -aabb_params.x || relativePosition.x > aabb_params.x) {
143329
- isInsideCube = false;
143330
- }
143331
- if (relativePosition.y < -aabb_params.y || relativePosition.y > aabb_params.y) {
143332
- isInsideCube = false;
143333
- }
143334
- if (relativePosition.z < -aabb_params.z || relativePosition.z > aabb_params.z) {
143335
- isInsideCube = false;
143336
- }
143337
- clr[i] = isInsideCube ? 1.0 : 0.0;
143338
- }
143339
- }
143340
- }
143341
-
143342
- gl_FragColor = clr;
143343
- }
143344
- `;
143345
-
143346
- const vertexShader$4 = /* glsl */ `
143347
- attribute vec2 vertex_position;
143348
- void main(void) {
143349
- gl_Position = vec4(vertex_position, 0.0, 1.0);
143350
- }
143351
- `;
143352
- const fragmentShader$4 = /* glsl */ `
143353
- uniform highp usampler2D transformA; // splat center x, y, z
143354
- uniform highp usampler2D splatTransform; // transform palette index
143355
- uniform sampler2D transformPalette; // palette of transforms
143356
- uniform ivec2 splat_params; // splat texture width, num splats
143357
-
143358
- void main(void) {
143359
- // calculate output id
143360
- ivec2 splatUV = ivec2(gl_FragCoord);
143361
-
143362
- // skip if splat index is out of bounds
143363
- if (splatUV.x + splatUV.y * splat_params.x >= splat_params.y) {
143364
- discard;
143365
- }
143366
-
143367
- // read splat center
143368
- vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
143369
-
143370
- // apply optional per-splat transform
143371
- uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
143372
- if (transformIndex > 0u) {
143373
- // read transform matrix
143374
- int u = int(transformIndex % 512u) * 3;
143375
- int v = int(transformIndex / 512u);
143376
-
143377
- mat3x4 t;
143378
- t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
143379
- t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
143380
- t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
143381
-
143382
- center = vec4(center, 1.0) * t;
143383
- }
143384
-
143385
- gl_FragColor = vec4(center, 0.0);
143386
- }
143176
+ const vertexShader$6 = /* glsl */ `
143177
+ attribute vec2 vertex_position;
143178
+ void main(void) {
143179
+ gl_Position = vec4(vertex_position, 0.0, 1.0);
143180
+ }
143181
+ `;
143182
+ const fragmentShader$6 = /* glsl */ `
143183
+ uniform highp usampler2D transformA; // splat center x, y, z
143184
+ uniform highp usampler2D splatTransform; // transform palette index
143185
+ uniform sampler2D transformPalette; // palette of transforms
143186
+ uniform sampler2D splatState; // per-splat state
143187
+ uniform highp ivec3 splat_params; // texture width, texture height, num splats
143188
+ uniform highp uint mode; // 0: selected, 1: visible
143189
+
143190
+ // calculate min and max for a single column of splats
143191
+ void main(void) {
143192
+
143193
+ vec3 boundMin = vec3(1e6);
143194
+ vec3 boundMax = vec3(-1e6);
143195
+
143196
+ for (int id = 0; id < splat_params.y; id++) {
143197
+ // calculate splatUV
143198
+ ivec2 splatUV = ivec2(gl_FragCoord.x, id);
143199
+
143200
+ // skip out-of-range splats
143201
+ if ((splatUV.x + splatUV.y * splat_params.x) >= splat_params.z) {
143202
+ continue;
143203
+ }
143204
+
143205
+ // read splat state
143206
+ uint state = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
143207
+
143208
+ // skip deleted or locked splats
143209
+ if (((mode == 0u) && (state != 1u)) || ((mode == 1u) && ((state & 4u) != 0u))) {
143210
+ continue;
143211
+ }
143212
+
143213
+ // read splat center
143214
+ vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
143215
+
143216
+ // apply optional per-splat transform
143217
+ uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
143218
+ if (transformIndex > 0u) {
143219
+ // read transform matrix
143220
+ int u = int(transformIndex % 512u) * 3;
143221
+ int v = int(transformIndex / 512u);
143222
+
143223
+ mat3x4 t;
143224
+ t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
143225
+ t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
143226
+ t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
143227
+
143228
+ center = vec4(center, 1.0) * t;
143229
+ }
143230
+
143231
+ boundMin = min(boundMin, mix(center, boundMin, isinf(center)));
143232
+ boundMax = max(boundMax, mix(center, boundMax, isinf(center)));
143233
+ }
143234
+
143235
+ pcFragColor0 = vec4(boundMin, 0.0);
143236
+ pcFragColor1 = vec4(boundMax, 0.0);
143237
+ }
143238
+ `;
143239
+
143240
+ const vertexShader$5 = /* glsl */ `
143241
+ attribute vec2 vertex_position;
143242
+ void main(void) {
143243
+ gl_Position = vec4(vertex_position, 0.0, 1.0);
143244
+ }
143245
+ `;
143246
+ const fragmentShader$5 = /* glsl */ `
143247
+ uniform highp usampler2D transformA; // splat center x, y, z
143248
+ uniform highp usampler2D splatTransform; // transform palette index
143249
+ uniform sampler2D transformPalette; // palette of transforms
143250
+ uniform uvec2 splat_params; // splat texture width, num splats
143251
+
143252
+ uniform mat4 matrix_model;
143253
+ uniform mat4 matrix_viewProjection;
143254
+
143255
+ uniform uvec2 output_params; // output width, height
143256
+
143257
+ // 0: mask, 1: rect, 2: sphere
143258
+ uniform int mode;
143259
+
143260
+ // mask params
143261
+ uniform sampler2D mask; // mask in alpha channel
143262
+ uniform vec2 mask_params; // mask width, height
143263
+
143264
+ // rect params
143265
+ uniform vec4 rect_params; // rect x, y, width, height
143266
+
143267
+ // sphere params
143268
+ uniform vec4 sphere_params; // sphere x, y, z, radius
143269
+
143270
+ // box params
143271
+ uniform vec4 box_params; // box x, y, z
143272
+ uniform vec4 aabb_params; // len x, y, z
143273
+
143274
+ void main(void) {
143275
+ // calculate output id
143276
+ uvec2 outputUV = uvec2(gl_FragCoord);
143277
+ uint outputId = (outputUV.x + outputUV.y * output_params.x) * 4u;
143278
+
143279
+ vec4 clr = vec4(0.0);
143280
+
143281
+ for (uint i = 0u; i < 4u; i++) {
143282
+ uint id = outputId + i;
143283
+
143284
+ if (id >= splat_params.y) {
143285
+ continue;
143286
+ }
143287
+
143288
+ // calculate splatUV
143289
+ ivec2 splatUV = ivec2(
143290
+ int(id % splat_params.x),
143291
+ int(id / splat_params.x)
143292
+ );
143293
+
143294
+ // read splat center
143295
+ vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
143296
+
143297
+ // apply optional per-splat transform
143298
+ uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
143299
+ if (transformIndex > 0u) {
143300
+ // read transform matrix
143301
+ int u = int(transformIndex % 512u) * 3;
143302
+ int v = int(transformIndex / 512u);
143303
+
143304
+ mat3x4 t;
143305
+ t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
143306
+ t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
143307
+ t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
143308
+
143309
+ center = vec4(center, 1.0) * t;
143310
+ }
143311
+
143312
+ // transform to clip space and discard if outside
143313
+ vec3 world = (matrix_model * vec4(center, 1.0)).xyz;
143314
+ vec4 clip = matrix_viewProjection * vec4(world, 1.0);
143315
+ vec3 ndc = clip.xyz / clip.w;
143316
+
143317
+ // skip offscreen fragments
143318
+ if (!any(greaterThan(abs(ndc), vec3(1.0)))) {
143319
+ if (mode == 0) {
143320
+ // select by mask
143321
+ ivec2 maskUV = ivec2((ndc.xy * vec2(0.5, -0.5) + 0.5) * mask_params);
143322
+ clr[i] = texelFetch(mask, maskUV, 0).a < 1.0 ? 0.0 : 1.0;
143323
+ } else if (mode == 1) {
143324
+ // select by rect
143325
+ clr[i] = all(greaterThan(ndc.xy * vec2(1.0, -1.0), rect_params.xy)) && all(lessThan(ndc.xy * vec2(1.0, -1.0), rect_params.zw)) ? 1.0 : 0.0;
143326
+ } else if (mode == 2) {
143327
+ // select by sphere
143328
+ clr[i] = length(world - sphere_params.xyz) < sphere_params.w ? 1.0 : 0.0;
143329
+ } else if (mode == 3) {
143330
+ // select by box
143331
+ vec3 relativePosition = world - box_params.xyz;
143332
+ bool isInsideCube = true;
143333
+ if (relativePosition.x < -aabb_params.x || relativePosition.x > aabb_params.x) {
143334
+ isInsideCube = false;
143335
+ }
143336
+ if (relativePosition.y < -aabb_params.y || relativePosition.y > aabb_params.y) {
143337
+ isInsideCube = false;
143338
+ }
143339
+ if (relativePosition.z < -aabb_params.z || relativePosition.z > aabb_params.z) {
143340
+ isInsideCube = false;
143341
+ }
143342
+ clr[i] = isInsideCube ? 1.0 : 0.0;
143343
+ }
143344
+ }
143345
+ }
143346
+
143347
+ gl_FragColor = clr;
143348
+ }
143349
+ `;
143350
+
143351
+ const vertexShader$4 = /* glsl */ `
143352
+ attribute vec2 vertex_position;
143353
+ void main(void) {
143354
+ gl_Position = vec4(vertex_position, 0.0, 1.0);
143355
+ }
143356
+ `;
143357
+ const fragmentShader$4 = /* glsl */ `
143358
+ uniform highp usampler2D transformA; // splat center x, y, z
143359
+ uniform highp usampler2D splatTransform; // transform palette index
143360
+ uniform sampler2D transformPalette; // palette of transforms
143361
+ uniform ivec2 splat_params; // splat texture width, num splats
143362
+
143363
+ void main(void) {
143364
+ // calculate output id
143365
+ ivec2 splatUV = ivec2(gl_FragCoord);
143366
+
143367
+ // skip if splat index is out of bounds
143368
+ if (splatUV.x + splatUV.y * splat_params.x >= splat_params.y) {
143369
+ discard;
143370
+ }
143371
+
143372
+ // read splat center
143373
+ vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
143374
+
143375
+ // apply optional per-splat transform
143376
+ uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
143377
+ if (transformIndex > 0u) {
143378
+ // read transform matrix
143379
+ int u = int(transformIndex % 512u) * 3;
143380
+ int v = int(transformIndex / 512u);
143381
+
143382
+ mat3x4 t;
143383
+ t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
143384
+ t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
143385
+ t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
143386
+
143387
+ center = vec4(center, 1.0) * t;
143388
+ }
143389
+
143390
+ gl_FragColor = vec4(center, 0.0);
143391
+ }
143387
143392
  `;
143388
143393
 
143389
143394
  const v1 = new Vec3();
@@ -143420,18 +143425,18 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
143420
143425
  attributes: {
143421
143426
  vertex_position: SEMANTIC_POSITION
143422
143427
  },
143423
- vertexGLSL: `
143424
- attribute vec2 vertex_position;
143425
- void main(void) {
143426
- gl_Position = vec4(vertex_position, 0.0, 1.0);
143427
- }
143428
+ vertexGLSL: `
143429
+ attribute vec2 vertex_position;
143430
+ void main(void) {
143431
+ gl_Position = vec4(vertex_position, 0.0, 1.0);
143432
+ }
143428
143433
  `,
143429
- fragmentGLSL: `
143430
- uniform sampler2D colorTex;
143431
- void main(void) {
143432
- ivec2 texel = ivec2(gl_FragCoord.xy);
143433
- gl_FragColor = texelFetch(colorTex, texel, 0);
143434
- }
143434
+ fragmentGLSL: `
143435
+ uniform sampler2D colorTex;
143436
+ void main(void) {
143437
+ ivec2 texel = ivec2(gl_FragCoord.xy);
143438
+ gl_FragColor = texelFetch(colorTex, texel, 0);
143439
+ }
143435
143440
  `
143436
143441
  });
143437
143442
  // intersection test
@@ -144670,176 +144675,176 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
144670
144675
  }
144671
144676
  }
144672
144677
 
144673
- const vertexShader$3 = /* glsl*/ `
144674
- uniform vec3 near_origin;
144675
- uniform vec3 near_x;
144676
- uniform vec3 near_y;
144677
-
144678
- uniform vec3 far_origin;
144679
- uniform vec3 far_x;
144680
- uniform vec3 far_y;
144681
-
144682
- attribute vec2 vertex_position;
144683
-
144684
- varying vec3 worldFar;
144685
- varying vec3 worldNear;
144686
-
144687
- void main(void) {
144688
- gl_Position = vec4(vertex_position, 0.0, 1.0);
144689
-
144690
- vec2 p = vertex_position * 0.5 + 0.5;
144691
- worldNear = near_origin + near_x * p.x + near_y * p.y;
144692
- worldFar = far_origin + far_x * p.x + far_y * p.y;
144693
- }
144694
- `;
144695
- const fragmentShader$3 = /* glsl*/ `
144696
- uniform vec3 view_position;
144697
- uniform mat4 matrix_viewProjection;
144698
- uniform sampler2D blueNoiseTex32;
144699
-
144700
- uniform int plane; // 0: x (yz), 1: y (xz), 2: z (xy)
144701
-
144702
- vec4 planes[3] = vec4[3](
144703
- vec4(1.0, 0.0, 0.0, 0.0),
144704
- vec4(0.0, 1.0, 0.0, 0.0),
144705
- vec4(0.0, 0.0, 1.0, 0.0)
144706
- );
144707
-
144708
- vec3 colors[3] = vec3[3](
144709
- vec3(1.0, 0.2, 0.2),
144710
- vec3(0.2, 1.0, 0.2),
144711
- vec3(0.2, 0.2, 1.0)
144712
- );
144713
-
144714
- int axis0[3] = int[3](1, 0, 0);
144715
- int axis1[3] = int[3](2, 2, 1);
144716
-
144717
- varying vec3 worldNear;
144718
- varying vec3 worldFar;
144719
-
144720
- bool intersectPlane(inout float t, vec3 pos, vec3 dir, vec4 plane) {
144721
- float d = dot(dir, plane.xyz);
144722
- if (abs(d) < 1e-06) {
144723
- return false;
144724
- }
144725
-
144726
- float n = -(dot(pos, plane.xyz) + plane.w) / d;
144727
- if (n < 0.0) {
144728
- return false;
144729
- }
144730
-
144731
- t = n;
144732
-
144733
- return true;
144734
- }
144735
-
144736
- // https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8#1e7c
144737
- float pristineGrid(in vec2 uv, in vec2 ddx, in vec2 ddy, vec2 lineWidth) {
144738
- vec2 uvDeriv = vec2(length(vec2(ddx.x, ddy.x)), length(vec2(ddx.y, ddy.y)));
144739
- bvec2 invertLine = bvec2(lineWidth.x > 0.5, lineWidth.y > 0.5);
144740
- vec2 targetWidth = vec2(
144741
- invertLine.x ? 1.0 - lineWidth.x : lineWidth.x,
144742
- invertLine.y ? 1.0 - lineWidth.y : lineWidth.y
144743
- );
144744
- vec2 drawWidth = clamp(targetWidth, uvDeriv, vec2(0.5));
144745
- vec2 lineAA = uvDeriv * 1.5;
144746
- vec2 gridUV = abs(fract(uv) * 2.0 - 1.0);
144747
- gridUV.x = invertLine.x ? gridUV.x : 1.0 - gridUV.x;
144748
- gridUV.y = invertLine.y ? gridUV.y : 1.0 - gridUV.y;
144749
- vec2 grid2 = smoothstep(drawWidth + lineAA, drawWidth - lineAA, gridUV);
144750
-
144751
- grid2 *= clamp(targetWidth / drawWidth, 0.0, 1.0);
144752
- grid2 = mix(grid2, targetWidth, clamp(uvDeriv * 2.0 - 1.0, 0.0, 1.0));
144753
- grid2.x = invertLine.x ? 1.0 - grid2.x : grid2.x;
144754
- grid2.y = invertLine.y ? 1.0 - grid2.y : grid2.y;
144755
-
144756
- return mix(grid2.x, 1.0, grid2.y);
144757
- }
144758
-
144759
- float calcDepth(vec3 p) {
144760
- vec4 v = matrix_viewProjection * vec4(p, 1.0);
144761
- return (v.z / v.w) * 0.5 + 0.5;
144762
- }
144763
-
144764
- bool writeDepth(float alpha) {
144765
- vec2 uv = fract(gl_FragCoord.xy / 32.0);
144766
- float noise = texture2DLod(blueNoiseTex32, uv, 0.0).y;
144767
- return alpha > noise;
144768
- }
144769
-
144770
- void main(void) {
144771
- vec3 p = worldNear;
144772
- vec3 v = normalize(worldFar - worldNear);
144773
-
144774
- // intersect ray with the world xz plane
144775
- float t;
144776
- if (!intersectPlane(t, p, v, planes[plane])) {
144777
- discard;
144778
- }
144779
-
144780
- // calculate grid intersection
144781
- vec3 worldPos = p + v * t;
144782
- vec2 pos = plane == 0 ? worldPos.yz : (plane == 1 ? worldPos.xz : worldPos.xy);
144783
- vec2 ddx = dFdx(pos);
144784
- vec2 ddy = dFdy(pos);
144785
-
144786
- float epsilon = 1.0 / 255.0;
144787
-
144788
- // calculate fade
144789
- float fade = 1.0 - smoothstep(400.0, 1000.0, length(worldPos - view_position));
144790
- if (fade < epsilon) {
144791
- discard;
144792
- }
144793
-
144794
- vec2 levelPos;
144795
- float levelSize;
144796
- float levelAlpha;
144797
-
144798
- // 10m grid with colored main axes
144799
- levelPos = pos * 0.1;
144800
- levelSize = 2.0 / 1000.0;
144801
- levelAlpha = pristineGrid(levelPos, ddx * 0.1, ddy * 0.1, vec2(levelSize)) * fade;
144802
- if (levelAlpha > epsilon) {
144803
- vec3 color;
144804
- vec2 loc = abs(levelPos);
144805
- if (loc.x < levelSize) {
144806
- if (loc.y < levelSize) {
144807
- color = vec3(1.0);
144808
- } else {
144809
- color = colors[axis1[plane]];
144810
- }
144811
- } else if (loc.y < levelSize) {
144812
- color = colors[axis0[plane]];
144813
- } else {
144814
- color = vec3(0.9);
144815
- }
144816
- gl_FragColor = vec4(color, levelAlpha);
144817
- gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
144818
- return;
144819
- }
144820
-
144821
- // 1m grid
144822
- levelPos = pos;
144823
- levelSize = 1.0 / 100.0;
144824
- levelAlpha = pristineGrid(levelPos, ddx, ddy, vec2(levelSize)) * fade;
144825
- if (levelAlpha > epsilon) {
144826
- gl_FragColor = vec4(vec3(0.7), levelAlpha);
144827
- gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
144828
- return;
144829
- }
144830
-
144831
- // 0.1m grid
144832
- levelPos = pos * 10.0;
144833
- levelSize = 1.0 / 100.0;
144834
- levelAlpha = pristineGrid(levelPos, ddx * 10.0, ddy * 10.0, vec2(levelSize)) * fade;
144835
- if (levelAlpha > epsilon) {
144836
- gl_FragColor = vec4(vec3(0.7), levelAlpha);
144837
- gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
144838
- return;
144839
- }
144840
-
144841
- discard;
144842
- }
144678
+ const vertexShader$3 = /* glsl*/ `
144679
+ uniform vec3 near_origin;
144680
+ uniform vec3 near_x;
144681
+ uniform vec3 near_y;
144682
+
144683
+ uniform vec3 far_origin;
144684
+ uniform vec3 far_x;
144685
+ uniform vec3 far_y;
144686
+
144687
+ attribute vec2 vertex_position;
144688
+
144689
+ varying vec3 worldFar;
144690
+ varying vec3 worldNear;
144691
+
144692
+ void main(void) {
144693
+ gl_Position = vec4(vertex_position, 0.0, 1.0);
144694
+
144695
+ vec2 p = vertex_position * 0.5 + 0.5;
144696
+ worldNear = near_origin + near_x * p.x + near_y * p.y;
144697
+ worldFar = far_origin + far_x * p.x + far_y * p.y;
144698
+ }
144699
+ `;
144700
+ const fragmentShader$3 = /* glsl*/ `
144701
+ uniform vec3 view_position;
144702
+ uniform mat4 matrix_viewProjection;
144703
+ uniform sampler2D blueNoiseTex32;
144704
+
144705
+ uniform int plane; // 0: x (yz), 1: y (xz), 2: z (xy)
144706
+
144707
+ vec4 planes[3] = vec4[3](
144708
+ vec4(1.0, 0.0, 0.0, 0.0),
144709
+ vec4(0.0, 1.0, 0.0, 0.0),
144710
+ vec4(0.0, 0.0, 1.0, 0.0)
144711
+ );
144712
+
144713
+ vec3 colors[3] = vec3[3](
144714
+ vec3(1.0, 0.2, 0.2),
144715
+ vec3(0.2, 1.0, 0.2),
144716
+ vec3(0.2, 0.2, 1.0)
144717
+ );
144718
+
144719
+ int axis0[3] = int[3](1, 0, 0);
144720
+ int axis1[3] = int[3](2, 2, 1);
144721
+
144722
+ varying vec3 worldNear;
144723
+ varying vec3 worldFar;
144724
+
144725
+ bool intersectPlane(inout float t, vec3 pos, vec3 dir, vec4 plane) {
144726
+ float d = dot(dir, plane.xyz);
144727
+ if (abs(d) < 1e-06) {
144728
+ return false;
144729
+ }
144730
+
144731
+ float n = -(dot(pos, plane.xyz) + plane.w) / d;
144732
+ if (n < 0.0) {
144733
+ return false;
144734
+ }
144735
+
144736
+ t = n;
144737
+
144738
+ return true;
144739
+ }
144740
+
144741
+ // https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8#1e7c
144742
+ float pristineGrid(in vec2 uv, in vec2 ddx, in vec2 ddy, vec2 lineWidth) {
144743
+ vec2 uvDeriv = vec2(length(vec2(ddx.x, ddy.x)), length(vec2(ddx.y, ddy.y)));
144744
+ bvec2 invertLine = bvec2(lineWidth.x > 0.5, lineWidth.y > 0.5);
144745
+ vec2 targetWidth = vec2(
144746
+ invertLine.x ? 1.0 - lineWidth.x : lineWidth.x,
144747
+ invertLine.y ? 1.0 - lineWidth.y : lineWidth.y
144748
+ );
144749
+ vec2 drawWidth = clamp(targetWidth, uvDeriv, vec2(0.5));
144750
+ vec2 lineAA = uvDeriv * 1.5;
144751
+ vec2 gridUV = abs(fract(uv) * 2.0 - 1.0);
144752
+ gridUV.x = invertLine.x ? gridUV.x : 1.0 - gridUV.x;
144753
+ gridUV.y = invertLine.y ? gridUV.y : 1.0 - gridUV.y;
144754
+ vec2 grid2 = smoothstep(drawWidth + lineAA, drawWidth - lineAA, gridUV);
144755
+
144756
+ grid2 *= clamp(targetWidth / drawWidth, 0.0, 1.0);
144757
+ grid2 = mix(grid2, targetWidth, clamp(uvDeriv * 2.0 - 1.0, 0.0, 1.0));
144758
+ grid2.x = invertLine.x ? 1.0 - grid2.x : grid2.x;
144759
+ grid2.y = invertLine.y ? 1.0 - grid2.y : grid2.y;
144760
+
144761
+ return mix(grid2.x, 1.0, grid2.y);
144762
+ }
144763
+
144764
+ float calcDepth(vec3 p) {
144765
+ vec4 v = matrix_viewProjection * vec4(p, 1.0);
144766
+ return (v.z / v.w) * 0.5 + 0.5;
144767
+ }
144768
+
144769
+ bool writeDepth(float alpha) {
144770
+ vec2 uv = fract(gl_FragCoord.xy / 32.0);
144771
+ float noise = texture2DLod(blueNoiseTex32, uv, 0.0).y;
144772
+ return alpha > noise;
144773
+ }
144774
+
144775
+ void main(void) {
144776
+ vec3 p = worldNear;
144777
+ vec3 v = normalize(worldFar - worldNear);
144778
+
144779
+ // intersect ray with the world xz plane
144780
+ float t;
144781
+ if (!intersectPlane(t, p, v, planes[plane])) {
144782
+ discard;
144783
+ }
144784
+
144785
+ // calculate grid intersection
144786
+ vec3 worldPos = p + v * t;
144787
+ vec2 pos = plane == 0 ? worldPos.yz : (plane == 1 ? worldPos.xz : worldPos.xy);
144788
+ vec2 ddx = dFdx(pos);
144789
+ vec2 ddy = dFdy(pos);
144790
+
144791
+ float epsilon = 1.0 / 255.0;
144792
+
144793
+ // calculate fade
144794
+ float fade = 1.0 - smoothstep(400.0, 1000.0, length(worldPos - view_position));
144795
+ if (fade < epsilon) {
144796
+ discard;
144797
+ }
144798
+
144799
+ vec2 levelPos;
144800
+ float levelSize;
144801
+ float levelAlpha;
144802
+
144803
+ // 10m grid with colored main axes
144804
+ levelPos = pos * 0.1;
144805
+ levelSize = 2.0 / 1000.0;
144806
+ levelAlpha = pristineGrid(levelPos, ddx * 0.1, ddy * 0.1, vec2(levelSize)) * fade;
144807
+ if (levelAlpha > epsilon) {
144808
+ vec3 color;
144809
+ vec2 loc = abs(levelPos);
144810
+ if (loc.x < levelSize) {
144811
+ if (loc.y < levelSize) {
144812
+ color = vec3(1.0);
144813
+ } else {
144814
+ color = colors[axis1[plane]];
144815
+ }
144816
+ } else if (loc.y < levelSize) {
144817
+ color = colors[axis0[plane]];
144818
+ } else {
144819
+ color = vec3(0.9);
144820
+ }
144821
+ gl_FragColor = vec4(color, levelAlpha);
144822
+ gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
144823
+ return;
144824
+ }
144825
+
144826
+ // 1m grid
144827
+ levelPos = pos;
144828
+ levelSize = 1.0 / 100.0;
144829
+ levelAlpha = pristineGrid(levelPos, ddx, ddy, vec2(levelSize)) * fade;
144830
+ if (levelAlpha > epsilon) {
144831
+ gl_FragColor = vec4(vec3(0.7), levelAlpha);
144832
+ gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
144833
+ return;
144834
+ }
144835
+
144836
+ // 0.1m grid
144837
+ levelPos = pos * 10.0;
144838
+ levelSize = 1.0 / 100.0;
144839
+ levelAlpha = pristineGrid(levelPos, ddx * 10.0, ddy * 10.0, vec2(levelSize)) * fade;
144840
+ if (levelAlpha > epsilon) {
144841
+ gl_FragColor = vec4(vec3(0.7), levelAlpha);
144842
+ gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
144843
+ return;
144844
+ }
144845
+
144846
+ discard;
144847
+ }
144843
144848
  `;
144844
144849
 
144845
144850
  const resolve = (scope, values) => {
@@ -144910,36 +144915,36 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
144910
144915
  }
144911
144916
  }
144912
144917
 
144913
- const vertexShader$2 = /* glsl*/ `
144914
- attribute vec2 vertex_position;
144915
- void main(void) {
144916
- gl_Position = vec4(vertex_position, 0.0, 1.0);
144917
- }
144918
- `;
144919
- const fragmentShader$2 = /* glsl*/ `
144920
- uniform sampler2D outlineTexture;
144921
- uniform float alphaCutoff;
144922
- uniform vec4 clr;
144923
-
144924
- void main(void) {
144925
- ivec2 texel = ivec2(gl_FragCoord.xy);
144926
-
144927
- // skip solid pixels
144928
- if (texelFetch(outlineTexture, texel, 0).a > alphaCutoff) {
144929
- discard;
144930
- }
144931
-
144932
- for (int x = -2; x <= 2; x++) {
144933
- for (int y = -2; y <= 2; y++) {
144934
- if ((x != 0) && (y != 0) && (texelFetch(outlineTexture, texel + ivec2(x, y), 0).a > alphaCutoff)) {
144935
- gl_FragColor = clr;
144936
- return;
144937
- }
144938
- }
144939
- }
144940
-
144941
- discard;
144942
- }
144918
+ const vertexShader$2 = /* glsl*/ `
144919
+ attribute vec2 vertex_position;
144920
+ void main(void) {
144921
+ gl_Position = vec4(vertex_position, 0.0, 1.0);
144922
+ }
144923
+ `;
144924
+ const fragmentShader$2 = /* glsl*/ `
144925
+ uniform sampler2D outlineTexture;
144926
+ uniform float alphaCutoff;
144927
+ uniform vec4 clr;
144928
+
144929
+ void main(void) {
144930
+ ivec2 texel = ivec2(gl_FragCoord.xy);
144931
+
144932
+ // skip solid pixels
144933
+ if (texelFetch(outlineTexture, texel, 0).a > alphaCutoff) {
144934
+ discard;
144935
+ }
144936
+
144937
+ for (int x = -2; x <= 2; x++) {
144938
+ for (int y = -2; y <= 2; y++) {
144939
+ if ((x != 0) && (y != 0) && (texelFetch(outlineTexture, texel + ivec2(x, y), 0).a > alphaCutoff)) {
144940
+ gl_FragColor = clr;
144941
+ return;
144942
+ }
144943
+ }
144944
+ }
144945
+
144946
+ discard;
144947
+ }
144943
144948
  `;
144944
144949
 
144945
144950
  class Outline extends Element$1 {
@@ -145257,72 +145262,72 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
145257
145262
  }
145258
145263
  }
145259
145264
 
145260
- const vertexShader$1 = /* glsl */ `
145261
- attribute uint vertex_id;
145262
-
145263
- uniform mat4 matrix_model;
145264
- uniform mat4 matrix_viewProjection;
145265
-
145266
- uniform sampler2D splatState;
145267
- uniform highp usampler2D splatPosition;
145268
- uniform highp usampler2D splatTransform; // per-splat index into transform palette
145269
- uniform sampler2D transformPalette; // palette of transform matrices
145270
-
145271
- uniform uvec2 texParams;
145272
-
145273
- uniform float splatSize;
145274
- uniform vec4 selectedClr;
145275
- uniform vec4 unselectedClr;
145276
-
145277
- varying vec4 varying_color;
145278
-
145279
- // calculate the current splat index and uv
145280
- ivec2 calcSplatUV(uint index, uint width) {
145281
- return ivec2(int(index % width), int(index / width));
145282
- }
145283
-
145284
- void main(void) {
145285
- ivec2 splatUV = calcSplatUV(vertex_id, texParams.x);
145286
- uint splatState = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
145287
-
145288
- if ((splatState & 6u) != 0u) {
145289
- // deleted or locked (4 or 2)
145290
- gl_Position = vec4(0.0, 0.0, 2.0, 1.0);
145291
- gl_PointSize = 0.0;
145292
- } else {
145293
- mat4 model = matrix_model;
145294
-
145295
- // handle per-splat transform
145296
- uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
145297
- if (transformIndex > 0u) {
145298
- // read transform matrix
145299
- int u = int(transformIndex % 512u) * 3;
145300
- int v = int(transformIndex / 512u);
145301
-
145302
- mat4 t;
145303
- t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
145304
- t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
145305
- t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
145306
- t[3] = vec4(0.0, 0.0, 0.0, 1.0);
145307
-
145308
- model = matrix_model * transpose(t);
145309
- }
145310
-
145311
- varying_color = (splatState == 1u) ? selectedClr : unselectedClr;
145312
-
145313
- vec3 center = uintBitsToFloat(texelFetch(splatPosition, splatUV, 0).xyz);
145314
-
145315
- gl_Position = matrix_viewProjection * model * vec4(center, 1.0);
145316
- gl_PointSize = splatSize;
145317
- }
145318
- }
145319
- `;
145320
- const fragmentShader$1 = /* glsl */ `
145321
- varying vec4 varying_color;
145322
-
145323
- void main(void) {
145324
- gl_FragColor = varying_color;
145325
- }
145265
+ const vertexShader$1 = /* glsl */ `
145266
+ attribute uint vertex_id;
145267
+
145268
+ uniform mat4 matrix_model;
145269
+ uniform mat4 matrix_viewProjection;
145270
+
145271
+ uniform sampler2D splatState;
145272
+ uniform highp usampler2D splatPosition;
145273
+ uniform highp usampler2D splatTransform; // per-splat index into transform palette
145274
+ uniform sampler2D transformPalette; // palette of transform matrices
145275
+
145276
+ uniform uvec2 texParams;
145277
+
145278
+ uniform float splatSize;
145279
+ uniform vec4 selectedClr;
145280
+ uniform vec4 unselectedClr;
145281
+
145282
+ varying vec4 varying_color;
145283
+
145284
+ // calculate the current splat index and uv
145285
+ ivec2 calcSplatUV(uint index, uint width) {
145286
+ return ivec2(int(index % width), int(index / width));
145287
+ }
145288
+
145289
+ void main(void) {
145290
+ ivec2 splatUV = calcSplatUV(vertex_id, texParams.x);
145291
+ uint splatState = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
145292
+
145293
+ if ((splatState & 6u) != 0u) {
145294
+ // deleted or locked (4 or 2)
145295
+ gl_Position = vec4(0.0, 0.0, 2.0, 1.0);
145296
+ gl_PointSize = 0.0;
145297
+ } else {
145298
+ mat4 model = matrix_model;
145299
+
145300
+ // handle per-splat transform
145301
+ uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
145302
+ if (transformIndex > 0u) {
145303
+ // read transform matrix
145304
+ int u = int(transformIndex % 512u) * 3;
145305
+ int v = int(transformIndex / 512u);
145306
+
145307
+ mat4 t;
145308
+ t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
145309
+ t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
145310
+ t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
145311
+ t[3] = vec4(0.0, 0.0, 0.0, 1.0);
145312
+
145313
+ model = matrix_model * transpose(t);
145314
+ }
145315
+
145316
+ varying_color = (splatState == 1u) ? selectedClr : unselectedClr;
145317
+
145318
+ vec3 center = uintBitsToFloat(texelFetch(splatPosition, splatUV, 0).xyz);
145319
+
145320
+ gl_Position = matrix_viewProjection * model * vec4(center, 1.0);
145321
+ gl_PointSize = splatSize;
145322
+ }
145323
+ }
145324
+ `;
145325
+ const fragmentShader$1 = /* glsl */ `
145326
+ varying vec4 varying_color;
145327
+
145328
+ void main(void) {
145329
+ gl_FragColor = varying_color;
145330
+ }
145326
145331
  `;
145327
145332
 
145328
145333
  class SplatOverlay extends Element$1 {
@@ -145411,19 +145416,19 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
145411
145416
  }
145412
145417
  }
145413
145418
 
145414
- const vertexShader = /* glsl*/ `
145415
- attribute vec2 vertex_position;
145416
- void main(void) {
145417
- gl_Position = vec4(vertex_position, 0.0, 1.0);
145418
- }
145419
+ const vertexShader = /* glsl*/ `
145420
+ attribute vec2 vertex_position;
145421
+ void main(void) {
145422
+ gl_Position = vec4(vertex_position, 0.0, 1.0);
145423
+ }
145419
145424
  `;
145420
- const fragmentShader = /* glsl*/ `
145421
- uniform sampler2D blitTexture;
145422
- void main(void) {
145423
- ivec2 texel = ivec2(gl_FragCoord.xy);
145424
-
145425
- gl_FragColor = texelFetch(blitTexture, texel, 0);
145426
- }
145425
+ const fragmentShader = /* glsl*/ `
145426
+ uniform sampler2D blitTexture;
145427
+ void main(void) {
145428
+ ivec2 texel = ivec2(gl_FragCoord.xy);
145429
+
145430
+ gl_FragColor = texelFetch(blitTexture, texel, 0);
145431
+ }
145427
145432
  `;
145428
145433
 
145429
145434
  class Underlay extends Element$1 {
@@ -147700,6 +147705,7 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
147700
147705
  };
147701
147706
  this.enableStats = false;
147702
147707
  this.autoFocus = true;
147708
+ this.previewMode = false;
147703
147709
  this.isLoading = false;
147704
147710
  this.hasModel = false;
147705
147711
  this.error = null;
@@ -147752,6 +147758,11 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
147752
147758
  this.canvas = options.canvas || null;
147753
147759
  this.enableStats = options.enableStats || false;
147754
147760
  this.autoFocus = options.autoFocus !== false;
147761
+ this.previewMode = options.previewMode || false;
147762
+ // In preview mode, always enable auto-focus
147763
+ if (this.previewMode) {
147764
+ this.autoFocus = true;
147765
+ }
147755
147766
  this._navigationCubeConfig = options.navigationCube || null;
147756
147767
  if (options.onStatsUpdate !== undefined) {
147757
147768
  this._onStatsUpdate = options.onStatsUpdate;
@@ -147782,11 +147793,20 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
147782
147793
  const emitEvent = (type, detail) => {
147783
147794
  this.emit({ type, detail });
147784
147795
  };
147785
- this._supersplat = new SupersplatAdapter(this.canvas, this._navigationCubeConfig, emitEvent);
147796
+ this._supersplat = new SupersplatAdapter(this.canvas,
147797
+ // Disable navigation cube in preview mode
147798
+ this.previewMode ? null : this._navigationCubeConfig, emitEvent);
147786
147799
  this._supersplatReady = this._supersplat.init();
147787
147800
  this._supersplatReady
147788
147801
  ?.then(() => {
147789
- this._setupFlyCameraForSupersplat();
147802
+ // Disable camera controls in preview mode
147803
+ if (this.previewMode && this._supersplat) {
147804
+ this._supersplat.setCameraControlsEnabled?.(false);
147805
+ }
147806
+ // Only set up fly camera if not in preview mode
147807
+ if (!this.previewMode) {
147808
+ this._setupFlyCameraForSupersplat();
147809
+ }
147790
147810
  })
147791
147811
  .catch(error => {
147792
147812
  console.error('SplatViewerCore.init: Failed to set up fly camera for supersplat path', error);
@@ -147825,7 +147845,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
147825
147845
  // SuperSplat's PCApp omits ScriptComponentSystem, so `addComponent('script')`
147826
147846
  // will not produce `camera.script.create()`. We keep the attempt (in case
147827
147847
  // the underlying app changes), but also support a controller-based fallback.
147828
- if (cameraAny && !cameraAny.script && typeof cameraAny.addComponent === 'function') {
147848
+ if (cameraAny &&
147849
+ !cameraAny.script &&
147850
+ typeof cameraAny.addComponent === 'function') {
147829
147851
  try {
147830
147852
  cameraAny.addComponent('script');
147831
147853
  }
@@ -147851,7 +147873,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
147851
147873
  // Prefer script-based fly when available; fallback to controller otherwise.
147852
147874
  const canCreateScript = typeof cameraAny?.script?.create === 'function';
147853
147875
  if (canCreateScript) {
147854
- const created = cameraAny.script.create('flyCamera', { attributes: flyAttributes });
147876
+ const created = cameraAny.script.create('flyCamera', {
147877
+ attributes: flyAttributes,
147878
+ });
147855
147879
  this._fly = created;
147856
147880
  if (this._fly) {
147857
147881
  ;
@@ -149715,6 +149739,11 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
149715
149739
  // Camera Mode / Fly Camera API
149716
149740
  // ==========================================
149717
149741
  setCameraMode(mode) {
149742
+ // Prevent camera mode changes in preview mode
149743
+ if (this.previewMode) {
149744
+ console.warn('SplatViewerCore.setCameraMode: Camera controls are disabled in preview mode');
149745
+ return;
149746
+ }
149718
149747
  // supersplat-core path: manage mode switching explicitly (camera entity is updated by supersplat-core each frame)
149719
149748
  if (this._supersplat) {
149720
149749
  const prev = this._cameraMode;
@@ -149744,7 +149773,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
149744
149773
  try {
149745
149774
  const pos = this.entities.camera?.getPosition?.();
149746
149775
  if (pos) {
149747
- const posVec = pos.clone ? pos.clone() : new Vec3(pos.x || 0, pos.y || 0, pos.z || 0);
149776
+ const posVec = pos.clone
149777
+ ? pos.clone()
149778
+ : new Vec3(pos.x || 0, pos.y || 0, pos.z || 0);
149748
149779
  this.entities.camera?.setPosition?.(posVec);
149749
149780
  }
149750
149781
  const euler = this.entities.camera?.getEulerAngles?.();
@@ -149967,8 +149998,8 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
149967
149998
  panSensitivity: 1.0,
149968
149999
  zoomSensitivity: 0.1,
149969
150000
  };
149970
- // Add navigation cube configuration if available
149971
- if (this._navigationCubeConfig) {
150001
+ // Add navigation cube configuration if available (but not in preview mode)
150002
+ if (this._navigationCubeConfig && !this.previewMode) {
149972
150003
  orbitAttributes.enableNavigationCube =
149973
150004
  this._navigationCubeConfig.enabled || false;
149974
150005
  this.entities.camera._navigationCubeConfig =
@@ -149983,48 +150014,57 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
149983
150014
  detail: { type: interactionType },
149984
150015
  });
149985
150016
  };
150017
+ // Disable camera controls in preview mode
150018
+ if (this.previewMode && this._orbit) {
150019
+ const orbitAny = this._orbit;
150020
+ if (typeof orbitAny.setEnabled === 'function') {
150021
+ orbitAny.setEnabled(false);
150022
+ }
150023
+ }
149986
150024
  this.entities.camera.setPosition(0, 0, 10);
149987
150025
  this.entities.camera.lookAt(Vec3.ZERO);
149988
150026
  // ==============================
149989
- // Setup fly camera (disabled by default)
150027
+ // Setup fly camera (disabled by default, skipped in preview mode)
149990
150028
  // ==============================
149991
- try {
149992
- registerFlyCameraScript();
149993
- // Ensure script component exists (created above)
149994
- const flyAttributes = {
149995
- moveSpeed: DEFAULT_FLY_CAMERA_CONFIG.moveSpeed,
149996
- fastSpeedMultiplier: DEFAULT_FLY_CAMERA_CONFIG.fastSpeedMultiplier,
149997
- slowSpeedMultiplier: DEFAULT_FLY_CAMERA_CONFIG.slowSpeedMultiplier,
149998
- lookSensitivity: DEFAULT_FLY_CAMERA_CONFIG.lookSensitivity,
149999
- invertY: DEFAULT_FLY_CAMERA_CONFIG.invertY,
150000
- keyBindings: DEFAULT_FLY_CAMERA_CONFIG.keyBindings,
150001
- smoothing: DEFAULT_FLY_CAMERA_CONFIG.smoothing,
150002
- friction: DEFAULT_FLY_CAMERA_CONFIG.friction,
150003
- enableCollision: DEFAULT_FLY_CAMERA_CONFIG.enableCollision,
150004
- minHeight: DEFAULT_FLY_CAMERA_CONFIG.minHeight,
150005
- maxHeight: DEFAULT_FLY_CAMERA_CONFIG.maxHeight,
150006
- };
150007
- this._fly = this.entities.camera.script.create('flyCamera', {
150008
- attributes: flyAttributes,
150009
- });
150010
- // Wire event emission to core
150011
- if (this._fly) {
150012
- ;
150013
- this._fly.emitFlyEvent = (type, detail) => {
150014
- this.emit({ type: type, detail });
150029
+ if (!this.previewMode) {
150030
+ try {
150031
+ registerFlyCameraScript();
150032
+ // Ensure script component exists (created above)
150033
+ const flyAttributes = {
150034
+ moveSpeed: DEFAULT_FLY_CAMERA_CONFIG.moveSpeed,
150035
+ fastSpeedMultiplier: DEFAULT_FLY_CAMERA_CONFIG.fastSpeedMultiplier,
150036
+ slowSpeedMultiplier: DEFAULT_FLY_CAMERA_CONFIG.slowSpeedMultiplier,
150037
+ lookSensitivity: DEFAULT_FLY_CAMERA_CONFIG.lookSensitivity,
150038
+ invertY: DEFAULT_FLY_CAMERA_CONFIG.invertY,
150039
+ keyBindings: DEFAULT_FLY_CAMERA_CONFIG.keyBindings,
150040
+ smoothing: DEFAULT_FLY_CAMERA_CONFIG.smoothing,
150041
+ friction: DEFAULT_FLY_CAMERA_CONFIG.friction,
150042
+ enableCollision: DEFAULT_FLY_CAMERA_CONFIG.enableCollision,
150043
+ minHeight: DEFAULT_FLY_CAMERA_CONFIG.minHeight,
150044
+ maxHeight: DEFAULT_FLY_CAMERA_CONFIG.maxHeight,
150015
150045
  };
150046
+ this._fly = this.entities.camera.script.create('flyCamera', {
150047
+ attributes: flyAttributes,
150048
+ });
150049
+ // Wire event emission to core
150050
+ if (this._fly) {
150051
+ ;
150052
+ this._fly.emitFlyEvent = (type, detail) => {
150053
+ this.emit({ type: type, detail });
150054
+ };
150055
+ }
150056
+ // Deactivate fly by default; orbit is the initial mode
150057
+ if (this._fly?.deactivate) {
150058
+ this._fly.deactivate();
150059
+ }
150060
+ // Initialize camera mode manager
150061
+ this._cameraModeManager = new CameraModeManager(this.app, this.entities.camera, this._orbit, this._fly, (eventType, detail) => {
150062
+ this.emit({ type: eventType, detail });
150063
+ }, 'orbit');
150016
150064
  }
150017
- // Deactivate fly by default; orbit is the initial mode
150018
- if (this._fly?.deactivate) {
150019
- this._fly.deactivate();
150065
+ catch (e) {
150066
+ console.warn('Failed to set up fly camera', e);
150020
150067
  }
150021
- // Initialize camera mode manager
150022
- this._cameraModeManager = new CameraModeManager(this.app, this.entities.camera, this._orbit, this._fly, (eventType, detail) => {
150023
- this.emit({ type: eventType, detail });
150024
- }, 'orbit');
150025
- }
150026
- catch (e) {
150027
- console.warn('Failed to set up fly camera', e);
150028
150068
  }
150029
150069
  }
150030
150070
  _setupStats() {
@@ -150269,6 +150309,7 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
150269
150309
  'enable-stats',
150270
150310
  'auto-focus',
150271
150311
  'max-splats',
150312
+ 'preview-mode',
150272
150313
  'camera-position',
150273
150314
  'camera-target',
150274
150315
  'orbit-sensitivity',
@@ -150299,6 +150340,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
150299
150340
  get autoFocus() {
150300
150341
  return this.hasAttribute('auto-focus');
150301
150342
  }
150343
+ get previewMode() {
150344
+ return this.hasAttribute('preview-mode');
150345
+ }
150302
150346
  get maxSplats() {
150303
150347
  return this.getAttribute('max-splats');
150304
150348
  }
@@ -150376,6 +150420,14 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
150376
150420
  this.removeAttribute('auto-focus');
150377
150421
  }
150378
150422
  }
150423
+ set previewMode(value) {
150424
+ if (value) {
150425
+ this.setAttribute('preview-mode', '');
150426
+ }
150427
+ else {
150428
+ this.removeAttribute('preview-mode');
150429
+ }
150430
+ }
150379
150431
  set maxSplats(value) {
150380
150432
  if (value === null) {
150381
150433
  this.removeAttribute('max-splats');
@@ -150557,6 +150609,7 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
150557
150609
  return value.length > 0;
150558
150610
  case 'enable-stats':
150559
150611
  case 'auto-focus':
150612
+ case 'preview-mode':
150560
150613
  case 'enable-navigation-cube':
150561
150614
  // Boolean attributes - any value is valid
150562
150615
  return true;
@@ -151503,7 +151556,7 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
151503
151556
  if (!this._core) {
151504
151557
  throw new Error('SplatViewerElement: Core not initialized. Call connectedCallback first.');
151505
151558
  }
151506
- return this._core.selectSplatsInSphere(center, radius, modelId, addToSelection);
151559
+ return this._core.selectSplatsInSphere(new Vec3(center.x, center.y, center.z), radius, modelId, addToSelection);
151507
151560
  }
151508
151561
  clearSplatSelection() {
151509
151562
  if (!this._core) {