@heliguy-xyz/splat-viewer 1.0.0-rc.25 → 1.0.0-rc.27
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/README.md +39 -0
- package/dist/web-component/splat-viewer.esm.js +684 -562
- package/dist/web-component/splat-viewer.esm.min.js +1 -1
- package/dist/web-component/splat-viewer.js +684 -562
- package/dist/web-component/splat-viewer.min.js +1 -1
- package/dist/web-component/supersplat-core/controllers.d.ts +5 -0
- package/dist/web-component/supersplat-core/controllers.d.ts.map +1 -1
- package/dist/web-component/supersplat-core/splat.d.ts.map +1 -1
- package/dist/web-component/types/supersplat-core/controllers.d.ts +5 -0
- package/dist/web-component/types/supersplat-core/controllers.d.ts.map +1 -1
- package/dist/web-component/types/supersplat-core/splat.d.ts.map +1 -1
- package/dist/web-component/types/web-component/OrbitCameraScript.d.ts.map +1 -1
- package/dist/web-component/types/web-component/SplatViewerCore.d.ts +1 -0
- package/dist/web-component/types/web-component/SplatViewerCore.d.ts.map +1 -1
- package/dist/web-component/types/web-component/SplatViewerElement.d.ts +2 -0
- package/dist/web-component/types/web-component/SplatViewerElement.d.ts.map +1 -1
- package/dist/web-component/types/web-component/SupersplatAdapter.d.ts +9 -0
- package/dist/web-component/types/web-component/SupersplatAdapter.d.ts.map +1 -1
- package/dist/web-component/types/web-component/types/attributes.d.ts +3 -0
- package/dist/web-component/types/web-component/types/attributes.d.ts.map +1 -1
- package/dist/web-component/types/web-component/types/core.d.ts +2 -0
- package/dist/web-component/types/web-component/types/core.d.ts.map +1 -1
- package/dist/web-component/types/web-component/utils/config.d.ts +1 -0
- package/dist/web-component/types/web-component/utils/config.d.ts.map +1 -1
- package/dist/web-component/web-component/OrbitCameraScript.d.ts.map +1 -1
- package/dist/web-component/web-component/SplatViewerCore.d.ts +1 -0
- package/dist/web-component/web-component/SplatViewerCore.d.ts.map +1 -1
- package/dist/web-component/web-component/SplatViewerElement.d.ts +2 -0
- package/dist/web-component/web-component/SplatViewerElement.d.ts.map +1 -1
- package/dist/web-component/web-component/SupersplatAdapter.d.ts +9 -0
- package/dist/web-component/web-component/SupersplatAdapter.d.ts.map +1 -1
- package/dist/web-component/web-component/types/attributes.d.ts +3 -0
- package/dist/web-component/web-component/types/attributes.d.ts.map +1 -1
- package/dist/web-component/web-component/types/core.d.ts +2 -0
- package/dist/web-component/web-component/types/core.d.ts.map +1 -1
- package/dist/web-component/web-component/utils/config.d.ts +1 -0
- package/dist/web-component/web-component/utils/config.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -139519,6 +139519,7 @@ const DEFAULT_CONFIG = {
|
|
|
139519
139519
|
enableStats: false,
|
|
139520
139520
|
autoFocus: true,
|
|
139521
139521
|
maxSplats: 2000000,
|
|
139522
|
+
previewMode: false,
|
|
139522
139523
|
camera: {
|
|
139523
139524
|
position: { x: 0, y: 0, z: 10 },
|
|
139524
139525
|
target: { x: 0, y: 0, z: 0 },
|
|
@@ -139556,11 +139557,15 @@ function parseJsonSafely(jsonString) {
|
|
|
139556
139557
|
}
|
|
139557
139558
|
/**
|
|
139558
139559
|
* Convert a string to a boolean value
|
|
139560
|
+
* For HTML boolean attributes, an empty string means the attribute is present (true)
|
|
139559
139561
|
*/
|
|
139560
139562
|
function parseBoolean(value) {
|
|
139561
139563
|
if (typeof value === 'boolean')
|
|
139562
139564
|
return value;
|
|
139563
139565
|
if (typeof value === 'string') {
|
|
139566
|
+
// Empty string means attribute is present without value (should be true for boolean attributes)
|
|
139567
|
+
if (value === '')
|
|
139568
|
+
return true;
|
|
139564
139569
|
return value.toLowerCase() === 'true' || value === '1';
|
|
139565
139570
|
}
|
|
139566
139571
|
return false;
|
|
@@ -139608,6 +139613,10 @@ function getConfigFromAttributes(element) {
|
|
|
139608
139613
|
if (enableStats !== null) {
|
|
139609
139614
|
config.enableStats = parseBoolean(enableStats);
|
|
139610
139615
|
}
|
|
139616
|
+
const previewMode = element.getAttribute('preview-mode');
|
|
139617
|
+
if (previewMode !== null) {
|
|
139618
|
+
config.previewMode = parseBoolean(previewMode);
|
|
139619
|
+
}
|
|
139611
139620
|
// Parse number attributes
|
|
139612
139621
|
const maxSplats = element.getAttribute('max-splats');
|
|
139613
139622
|
if (maxSplats !== null) {
|
|
@@ -140447,6 +140456,10 @@ function registerOrbitCameraScript() {
|
|
|
140447
140456
|
this.isPanning = false;
|
|
140448
140457
|
// Allow host to temporarily disable camera input (e.g., while dragging gizmos)
|
|
140449
140458
|
this._inputEnabled = true;
|
|
140459
|
+
// Granular control over specific input types
|
|
140460
|
+
this._orbitEnabled = true;
|
|
140461
|
+
this._panEnabled = true;
|
|
140462
|
+
this._zoomEnabled = true;
|
|
140450
140463
|
// Setup context menu prevention
|
|
140451
140464
|
this.setupContextMenuPrevention();
|
|
140452
140465
|
// Use PlayCanvas mouse events for reliable input handling
|
|
@@ -140484,6 +140497,19 @@ function registerOrbitCameraScript() {
|
|
|
140484
140497
|
this.isPanning = false;
|
|
140485
140498
|
}
|
|
140486
140499
|
};
|
|
140500
|
+
OrbitCamera.prototype.setInputControls = function (options) {
|
|
140501
|
+
if (options.orbit !== undefined)
|
|
140502
|
+
this._orbitEnabled = !!options.orbit;
|
|
140503
|
+
if (options.pan !== undefined)
|
|
140504
|
+
this._panEnabled = !!options.pan;
|
|
140505
|
+
if (options.zoom !== undefined)
|
|
140506
|
+
this._zoomEnabled = !!options.zoom;
|
|
140507
|
+
// Clear any in-progress interactions if being disabled
|
|
140508
|
+
if (this._orbitEnabled === false)
|
|
140509
|
+
this.isOrbiting = false;
|
|
140510
|
+
if (this._panEnabled === false)
|
|
140511
|
+
this.isPanning = false;
|
|
140512
|
+
};
|
|
140487
140513
|
OrbitCamera.prototype.update = function (dt) {
|
|
140488
140514
|
// Update navigation cube if enabled
|
|
140489
140515
|
if (this.navigationCube &&
|
|
@@ -140500,12 +140526,13 @@ function registerOrbitCameraScript() {
|
|
|
140500
140526
|
typeof this.navigationCube.cancelTransition === 'function') {
|
|
140501
140527
|
this.navigationCube.cancelTransition('manual-interaction');
|
|
140502
140528
|
}
|
|
140503
|
-
if (event.button === MOUSEBUTTON_LEFT) {
|
|
140529
|
+
if (event.button === MOUSEBUTTON_LEFT && this._orbitEnabled !== false) {
|
|
140504
140530
|
this.isOrbiting = true;
|
|
140505
140531
|
this.emitInteractionEvent?.('interaction-start', 'rotate');
|
|
140506
140532
|
}
|
|
140507
|
-
else if (event.button === MOUSEBUTTON_RIGHT ||
|
|
140508
|
-
event.button === MOUSEBUTTON_MIDDLE)
|
|
140533
|
+
else if ((event.button === MOUSEBUTTON_RIGHT ||
|
|
140534
|
+
event.button === MOUSEBUTTON_MIDDLE) &&
|
|
140535
|
+
this._panEnabled !== false) {
|
|
140509
140536
|
this.isPanning = true;
|
|
140510
140537
|
this.emitInteractionEvent?.('interaction-start', 'pan');
|
|
140511
140538
|
}
|
|
@@ -140553,7 +140580,7 @@ function registerOrbitCameraScript() {
|
|
|
140553
140580
|
}
|
|
140554
140581
|
};
|
|
140555
140582
|
OrbitCamera.prototype.onMouseWheel = function (event) {
|
|
140556
|
-
if (this._inputEnabled === false)
|
|
140583
|
+
if (this._inputEnabled === false || this._zoomEnabled === false)
|
|
140557
140584
|
return;
|
|
140558
140585
|
// Cancel any ongoing navigation cube transition when manual zoom interaction starts
|
|
140559
140586
|
if (this.navigationCube &&
|
|
@@ -142689,6 +142716,10 @@ class Splat extends Element$1 {
|
|
|
142689
142716
|
this.entity.setEulerAngles(orientation);
|
|
142690
142717
|
this.entity.addComponent('gsplat', { asset });
|
|
142691
142718
|
const instance = this.entity.gsplat.instance;
|
|
142719
|
+
// Check if the gsplat component initialized properly
|
|
142720
|
+
if (!instance || !instance.meshInstance) {
|
|
142721
|
+
throw new Error('Failed to initialize gsplat component. The file may not contain valid Gaussian Splatting data.');
|
|
142722
|
+
}
|
|
142692
142723
|
// use custom render order distance calculation for splats
|
|
142693
142724
|
instance.meshInstance.calculateSortDistance = (meshInstance, pos, dir) => {
|
|
142694
142725
|
const bound = this.localBound;
|
|
@@ -143161,222 +143192,222 @@ class AssetLoader {
|
|
|
143161
143192
|
}
|
|
143162
143193
|
}
|
|
143163
143194
|
|
|
143164
|
-
const vertexShader$6 = /* glsl */ `
|
|
143165
|
-
attribute vec2 vertex_position;
|
|
143166
|
-
void main(void) {
|
|
143167
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143168
|
-
}
|
|
143169
|
-
`;
|
|
143170
|
-
const fragmentShader$6 = /* glsl */ `
|
|
143171
|
-
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143172
|
-
uniform highp usampler2D splatTransform; // transform palette index
|
|
143173
|
-
uniform sampler2D transformPalette; // palette of transforms
|
|
143174
|
-
uniform sampler2D splatState; // per-splat state
|
|
143175
|
-
uniform highp ivec3 splat_params; // texture width, texture height, num splats
|
|
143176
|
-
uniform highp uint mode; // 0: selected, 1: visible
|
|
143177
|
-
|
|
143178
|
-
// calculate min and max for a single column of splats
|
|
143179
|
-
void main(void) {
|
|
143180
|
-
|
|
143181
|
-
vec3 boundMin = vec3(1e6);
|
|
143182
|
-
vec3 boundMax = vec3(-1e6);
|
|
143183
|
-
|
|
143184
|
-
for (int id = 0; id < splat_params.y; id++) {
|
|
143185
|
-
// calculate splatUV
|
|
143186
|
-
ivec2 splatUV = ivec2(gl_FragCoord.x, id);
|
|
143187
|
-
|
|
143188
|
-
// skip out-of-range splats
|
|
143189
|
-
if ((splatUV.x + splatUV.y * splat_params.x) >= splat_params.z) {
|
|
143190
|
-
continue;
|
|
143191
|
-
}
|
|
143192
|
-
|
|
143193
|
-
// read splat state
|
|
143194
|
-
uint state = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
|
|
143195
|
-
|
|
143196
|
-
// skip deleted or locked splats
|
|
143197
|
-
if (((mode == 0u) && (state != 1u)) || ((mode == 1u) && ((state & 4u) != 0u))) {
|
|
143198
|
-
continue;
|
|
143199
|
-
}
|
|
143200
|
-
|
|
143201
|
-
// read splat center
|
|
143202
|
-
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143203
|
-
|
|
143204
|
-
// apply optional per-splat transform
|
|
143205
|
-
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143206
|
-
if (transformIndex > 0u) {
|
|
143207
|
-
// read transform matrix
|
|
143208
|
-
int u = int(transformIndex % 512u) * 3;
|
|
143209
|
-
int v = int(transformIndex / 512u);
|
|
143210
|
-
|
|
143211
|
-
mat3x4 t;
|
|
143212
|
-
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143213
|
-
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143214
|
-
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143215
|
-
|
|
143216
|
-
center = vec4(center, 1.0) * t;
|
|
143217
|
-
}
|
|
143218
|
-
|
|
143219
|
-
boundMin = min(boundMin, mix(center, boundMin, isinf(center)));
|
|
143220
|
-
boundMax = max(boundMax, mix(center, boundMax, isinf(center)));
|
|
143221
|
-
}
|
|
143222
|
-
|
|
143223
|
-
pcFragColor0 = vec4(boundMin, 0.0);
|
|
143224
|
-
pcFragColor1 = vec4(boundMax, 0.0);
|
|
143225
|
-
}
|
|
143226
|
-
`;
|
|
143227
|
-
|
|
143228
|
-
const vertexShader$5 = /* glsl */ `
|
|
143229
|
-
attribute vec2 vertex_position;
|
|
143230
|
-
void main(void) {
|
|
143231
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143232
|
-
}
|
|
143233
|
-
`;
|
|
143234
|
-
const fragmentShader$5 = /* glsl */ `
|
|
143235
|
-
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143236
|
-
uniform highp usampler2D splatTransform; // transform palette index
|
|
143237
|
-
uniform sampler2D transformPalette; // palette of transforms
|
|
143238
|
-
uniform uvec2 splat_params; // splat texture width, num splats
|
|
143239
|
-
|
|
143240
|
-
uniform mat4 matrix_model;
|
|
143241
|
-
uniform mat4 matrix_viewProjection;
|
|
143242
|
-
|
|
143243
|
-
uniform uvec2 output_params; // output width, height
|
|
143244
|
-
|
|
143245
|
-
// 0: mask, 1: rect, 2: sphere
|
|
143246
|
-
uniform int mode;
|
|
143247
|
-
|
|
143248
|
-
// mask params
|
|
143249
|
-
uniform sampler2D mask; // mask in alpha channel
|
|
143250
|
-
uniform vec2 mask_params; // mask width, height
|
|
143251
|
-
|
|
143252
|
-
// rect params
|
|
143253
|
-
uniform vec4 rect_params; // rect x, y, width, height
|
|
143254
|
-
|
|
143255
|
-
// sphere params
|
|
143256
|
-
uniform vec4 sphere_params; // sphere x, y, z, radius
|
|
143257
|
-
|
|
143258
|
-
// box params
|
|
143259
|
-
uniform vec4 box_params; // box x, y, z
|
|
143260
|
-
uniform vec4 aabb_params; // len x, y, z
|
|
143261
|
-
|
|
143262
|
-
void main(void) {
|
|
143263
|
-
// calculate output id
|
|
143264
|
-
uvec2 outputUV = uvec2(gl_FragCoord);
|
|
143265
|
-
uint outputId = (outputUV.x + outputUV.y * output_params.x) * 4u;
|
|
143266
|
-
|
|
143267
|
-
vec4 clr = vec4(0.0);
|
|
143268
|
-
|
|
143269
|
-
for (uint i = 0u; i < 4u; i++) {
|
|
143270
|
-
uint id = outputId + i;
|
|
143271
|
-
|
|
143272
|
-
if (id >= splat_params.y) {
|
|
143273
|
-
continue;
|
|
143274
|
-
}
|
|
143275
|
-
|
|
143276
|
-
// calculate splatUV
|
|
143277
|
-
ivec2 splatUV = ivec2(
|
|
143278
|
-
int(id % splat_params.x),
|
|
143279
|
-
int(id / splat_params.x)
|
|
143280
|
-
);
|
|
143281
|
-
|
|
143282
|
-
// read splat center
|
|
143283
|
-
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143284
|
-
|
|
143285
|
-
// apply optional per-splat transform
|
|
143286
|
-
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143287
|
-
if (transformIndex > 0u) {
|
|
143288
|
-
// read transform matrix
|
|
143289
|
-
int u = int(transformIndex % 512u) * 3;
|
|
143290
|
-
int v = int(transformIndex / 512u);
|
|
143291
|
-
|
|
143292
|
-
mat3x4 t;
|
|
143293
|
-
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143294
|
-
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143295
|
-
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143296
|
-
|
|
143297
|
-
center = vec4(center, 1.0) * t;
|
|
143298
|
-
}
|
|
143299
|
-
|
|
143300
|
-
// transform to clip space and discard if outside
|
|
143301
|
-
vec3 world = (matrix_model * vec4(center, 1.0)).xyz;
|
|
143302
|
-
vec4 clip = matrix_viewProjection * vec4(world, 1.0);
|
|
143303
|
-
vec3 ndc = clip.xyz / clip.w;
|
|
143304
|
-
|
|
143305
|
-
// skip offscreen fragments
|
|
143306
|
-
if (!any(greaterThan(abs(ndc), vec3(1.0)))) {
|
|
143307
|
-
if (mode == 0) {
|
|
143308
|
-
// select by mask
|
|
143309
|
-
ivec2 maskUV = ivec2((ndc.xy * vec2(0.5, -0.5) + 0.5) * mask_params);
|
|
143310
|
-
clr[i] = texelFetch(mask, maskUV, 0).a < 1.0 ? 0.0 : 1.0;
|
|
143311
|
-
} else if (mode == 1) {
|
|
143312
|
-
// select by rect
|
|
143313
|
-
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;
|
|
143314
|
-
} else if (mode == 2) {
|
|
143315
|
-
// select by sphere
|
|
143316
|
-
clr[i] = length(world - sphere_params.xyz) < sphere_params.w ? 1.0 : 0.0;
|
|
143317
|
-
} else if (mode == 3) {
|
|
143318
|
-
// select by box
|
|
143319
|
-
vec3 relativePosition = world - box_params.xyz;
|
|
143320
|
-
bool isInsideCube = true;
|
|
143321
|
-
if (relativePosition.x < -aabb_params.x || relativePosition.x > aabb_params.x) {
|
|
143322
|
-
isInsideCube = false;
|
|
143323
|
-
}
|
|
143324
|
-
if (relativePosition.y < -aabb_params.y || relativePosition.y > aabb_params.y) {
|
|
143325
|
-
isInsideCube = false;
|
|
143326
|
-
}
|
|
143327
|
-
if (relativePosition.z < -aabb_params.z || relativePosition.z > aabb_params.z) {
|
|
143328
|
-
isInsideCube = false;
|
|
143329
|
-
}
|
|
143330
|
-
clr[i] = isInsideCube ? 1.0 : 0.0;
|
|
143331
|
-
}
|
|
143332
|
-
}
|
|
143333
|
-
}
|
|
143334
|
-
|
|
143335
|
-
gl_FragColor = clr;
|
|
143336
|
-
}
|
|
143337
|
-
`;
|
|
143338
|
-
|
|
143339
|
-
const vertexShader$4 = /* glsl */ `
|
|
143340
|
-
attribute vec2 vertex_position;
|
|
143341
|
-
void main(void) {
|
|
143342
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143343
|
-
}
|
|
143344
|
-
`;
|
|
143345
|
-
const fragmentShader$4 = /* glsl */ `
|
|
143346
|
-
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143347
|
-
uniform highp usampler2D splatTransform; // transform palette index
|
|
143348
|
-
uniform sampler2D transformPalette; // palette of transforms
|
|
143349
|
-
uniform ivec2 splat_params; // splat texture width, num splats
|
|
143350
|
-
|
|
143351
|
-
void main(void) {
|
|
143352
|
-
// calculate output id
|
|
143353
|
-
ivec2 splatUV = ivec2(gl_FragCoord);
|
|
143354
|
-
|
|
143355
|
-
// skip if splat index is out of bounds
|
|
143356
|
-
if (splatUV.x + splatUV.y * splat_params.x >= splat_params.y) {
|
|
143357
|
-
discard;
|
|
143358
|
-
}
|
|
143359
|
-
|
|
143360
|
-
// read splat center
|
|
143361
|
-
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143362
|
-
|
|
143363
|
-
// apply optional per-splat transform
|
|
143364
|
-
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143365
|
-
if (transformIndex > 0u) {
|
|
143366
|
-
// read transform matrix
|
|
143367
|
-
int u = int(transformIndex % 512u) * 3;
|
|
143368
|
-
int v = int(transformIndex / 512u);
|
|
143369
|
-
|
|
143370
|
-
mat3x4 t;
|
|
143371
|
-
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143372
|
-
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143373
|
-
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143374
|
-
|
|
143375
|
-
center = vec4(center, 1.0) * t;
|
|
143376
|
-
}
|
|
143377
|
-
|
|
143378
|
-
gl_FragColor = vec4(center, 0.0);
|
|
143379
|
-
}
|
|
143195
|
+
const vertexShader$6 = /* glsl */ `
|
|
143196
|
+
attribute vec2 vertex_position;
|
|
143197
|
+
void main(void) {
|
|
143198
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143199
|
+
}
|
|
143200
|
+
`;
|
|
143201
|
+
const fragmentShader$6 = /* glsl */ `
|
|
143202
|
+
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143203
|
+
uniform highp usampler2D splatTransform; // transform palette index
|
|
143204
|
+
uniform sampler2D transformPalette; // palette of transforms
|
|
143205
|
+
uniform sampler2D splatState; // per-splat state
|
|
143206
|
+
uniform highp ivec3 splat_params; // texture width, texture height, num splats
|
|
143207
|
+
uniform highp uint mode; // 0: selected, 1: visible
|
|
143208
|
+
|
|
143209
|
+
// calculate min and max for a single column of splats
|
|
143210
|
+
void main(void) {
|
|
143211
|
+
|
|
143212
|
+
vec3 boundMin = vec3(1e6);
|
|
143213
|
+
vec3 boundMax = vec3(-1e6);
|
|
143214
|
+
|
|
143215
|
+
for (int id = 0; id < splat_params.y; id++) {
|
|
143216
|
+
// calculate splatUV
|
|
143217
|
+
ivec2 splatUV = ivec2(gl_FragCoord.x, id);
|
|
143218
|
+
|
|
143219
|
+
// skip out-of-range splats
|
|
143220
|
+
if ((splatUV.x + splatUV.y * splat_params.x) >= splat_params.z) {
|
|
143221
|
+
continue;
|
|
143222
|
+
}
|
|
143223
|
+
|
|
143224
|
+
// read splat state
|
|
143225
|
+
uint state = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
|
|
143226
|
+
|
|
143227
|
+
// skip deleted or locked splats
|
|
143228
|
+
if (((mode == 0u) && (state != 1u)) || ((mode == 1u) && ((state & 4u) != 0u))) {
|
|
143229
|
+
continue;
|
|
143230
|
+
}
|
|
143231
|
+
|
|
143232
|
+
// read splat center
|
|
143233
|
+
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143234
|
+
|
|
143235
|
+
// apply optional per-splat transform
|
|
143236
|
+
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143237
|
+
if (transformIndex > 0u) {
|
|
143238
|
+
// read transform matrix
|
|
143239
|
+
int u = int(transformIndex % 512u) * 3;
|
|
143240
|
+
int v = int(transformIndex / 512u);
|
|
143241
|
+
|
|
143242
|
+
mat3x4 t;
|
|
143243
|
+
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143244
|
+
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143245
|
+
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143246
|
+
|
|
143247
|
+
center = vec4(center, 1.0) * t;
|
|
143248
|
+
}
|
|
143249
|
+
|
|
143250
|
+
boundMin = min(boundMin, mix(center, boundMin, isinf(center)));
|
|
143251
|
+
boundMax = max(boundMax, mix(center, boundMax, isinf(center)));
|
|
143252
|
+
}
|
|
143253
|
+
|
|
143254
|
+
pcFragColor0 = vec4(boundMin, 0.0);
|
|
143255
|
+
pcFragColor1 = vec4(boundMax, 0.0);
|
|
143256
|
+
}
|
|
143257
|
+
`;
|
|
143258
|
+
|
|
143259
|
+
const vertexShader$5 = /* glsl */ `
|
|
143260
|
+
attribute vec2 vertex_position;
|
|
143261
|
+
void main(void) {
|
|
143262
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143263
|
+
}
|
|
143264
|
+
`;
|
|
143265
|
+
const fragmentShader$5 = /* glsl */ `
|
|
143266
|
+
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143267
|
+
uniform highp usampler2D splatTransform; // transform palette index
|
|
143268
|
+
uniform sampler2D transformPalette; // palette of transforms
|
|
143269
|
+
uniform uvec2 splat_params; // splat texture width, num splats
|
|
143270
|
+
|
|
143271
|
+
uniform mat4 matrix_model;
|
|
143272
|
+
uniform mat4 matrix_viewProjection;
|
|
143273
|
+
|
|
143274
|
+
uniform uvec2 output_params; // output width, height
|
|
143275
|
+
|
|
143276
|
+
// 0: mask, 1: rect, 2: sphere
|
|
143277
|
+
uniform int mode;
|
|
143278
|
+
|
|
143279
|
+
// mask params
|
|
143280
|
+
uniform sampler2D mask; // mask in alpha channel
|
|
143281
|
+
uniform vec2 mask_params; // mask width, height
|
|
143282
|
+
|
|
143283
|
+
// rect params
|
|
143284
|
+
uniform vec4 rect_params; // rect x, y, width, height
|
|
143285
|
+
|
|
143286
|
+
// sphere params
|
|
143287
|
+
uniform vec4 sphere_params; // sphere x, y, z, radius
|
|
143288
|
+
|
|
143289
|
+
// box params
|
|
143290
|
+
uniform vec4 box_params; // box x, y, z
|
|
143291
|
+
uniform vec4 aabb_params; // len x, y, z
|
|
143292
|
+
|
|
143293
|
+
void main(void) {
|
|
143294
|
+
// calculate output id
|
|
143295
|
+
uvec2 outputUV = uvec2(gl_FragCoord);
|
|
143296
|
+
uint outputId = (outputUV.x + outputUV.y * output_params.x) * 4u;
|
|
143297
|
+
|
|
143298
|
+
vec4 clr = vec4(0.0);
|
|
143299
|
+
|
|
143300
|
+
for (uint i = 0u; i < 4u; i++) {
|
|
143301
|
+
uint id = outputId + i;
|
|
143302
|
+
|
|
143303
|
+
if (id >= splat_params.y) {
|
|
143304
|
+
continue;
|
|
143305
|
+
}
|
|
143306
|
+
|
|
143307
|
+
// calculate splatUV
|
|
143308
|
+
ivec2 splatUV = ivec2(
|
|
143309
|
+
int(id % splat_params.x),
|
|
143310
|
+
int(id / splat_params.x)
|
|
143311
|
+
);
|
|
143312
|
+
|
|
143313
|
+
// read splat center
|
|
143314
|
+
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143315
|
+
|
|
143316
|
+
// apply optional per-splat transform
|
|
143317
|
+
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143318
|
+
if (transformIndex > 0u) {
|
|
143319
|
+
// read transform matrix
|
|
143320
|
+
int u = int(transformIndex % 512u) * 3;
|
|
143321
|
+
int v = int(transformIndex / 512u);
|
|
143322
|
+
|
|
143323
|
+
mat3x4 t;
|
|
143324
|
+
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143325
|
+
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143326
|
+
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143327
|
+
|
|
143328
|
+
center = vec4(center, 1.0) * t;
|
|
143329
|
+
}
|
|
143330
|
+
|
|
143331
|
+
// transform to clip space and discard if outside
|
|
143332
|
+
vec3 world = (matrix_model * vec4(center, 1.0)).xyz;
|
|
143333
|
+
vec4 clip = matrix_viewProjection * vec4(world, 1.0);
|
|
143334
|
+
vec3 ndc = clip.xyz / clip.w;
|
|
143335
|
+
|
|
143336
|
+
// skip offscreen fragments
|
|
143337
|
+
if (!any(greaterThan(abs(ndc), vec3(1.0)))) {
|
|
143338
|
+
if (mode == 0) {
|
|
143339
|
+
// select by mask
|
|
143340
|
+
ivec2 maskUV = ivec2((ndc.xy * vec2(0.5, -0.5) + 0.5) * mask_params);
|
|
143341
|
+
clr[i] = texelFetch(mask, maskUV, 0).a < 1.0 ? 0.0 : 1.0;
|
|
143342
|
+
} else if (mode == 1) {
|
|
143343
|
+
// select by rect
|
|
143344
|
+
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;
|
|
143345
|
+
} else if (mode == 2) {
|
|
143346
|
+
// select by sphere
|
|
143347
|
+
clr[i] = length(world - sphere_params.xyz) < sphere_params.w ? 1.0 : 0.0;
|
|
143348
|
+
} else if (mode == 3) {
|
|
143349
|
+
// select by box
|
|
143350
|
+
vec3 relativePosition = world - box_params.xyz;
|
|
143351
|
+
bool isInsideCube = true;
|
|
143352
|
+
if (relativePosition.x < -aabb_params.x || relativePosition.x > aabb_params.x) {
|
|
143353
|
+
isInsideCube = false;
|
|
143354
|
+
}
|
|
143355
|
+
if (relativePosition.y < -aabb_params.y || relativePosition.y > aabb_params.y) {
|
|
143356
|
+
isInsideCube = false;
|
|
143357
|
+
}
|
|
143358
|
+
if (relativePosition.z < -aabb_params.z || relativePosition.z > aabb_params.z) {
|
|
143359
|
+
isInsideCube = false;
|
|
143360
|
+
}
|
|
143361
|
+
clr[i] = isInsideCube ? 1.0 : 0.0;
|
|
143362
|
+
}
|
|
143363
|
+
}
|
|
143364
|
+
}
|
|
143365
|
+
|
|
143366
|
+
gl_FragColor = clr;
|
|
143367
|
+
}
|
|
143368
|
+
`;
|
|
143369
|
+
|
|
143370
|
+
const vertexShader$4 = /* glsl */ `
|
|
143371
|
+
attribute vec2 vertex_position;
|
|
143372
|
+
void main(void) {
|
|
143373
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143374
|
+
}
|
|
143375
|
+
`;
|
|
143376
|
+
const fragmentShader$4 = /* glsl */ `
|
|
143377
|
+
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143378
|
+
uniform highp usampler2D splatTransform; // transform palette index
|
|
143379
|
+
uniform sampler2D transformPalette; // palette of transforms
|
|
143380
|
+
uniform ivec2 splat_params; // splat texture width, num splats
|
|
143381
|
+
|
|
143382
|
+
void main(void) {
|
|
143383
|
+
// calculate output id
|
|
143384
|
+
ivec2 splatUV = ivec2(gl_FragCoord);
|
|
143385
|
+
|
|
143386
|
+
// skip if splat index is out of bounds
|
|
143387
|
+
if (splatUV.x + splatUV.y * splat_params.x >= splat_params.y) {
|
|
143388
|
+
discard;
|
|
143389
|
+
}
|
|
143390
|
+
|
|
143391
|
+
// read splat center
|
|
143392
|
+
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143393
|
+
|
|
143394
|
+
// apply optional per-splat transform
|
|
143395
|
+
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143396
|
+
if (transformIndex > 0u) {
|
|
143397
|
+
// read transform matrix
|
|
143398
|
+
int u = int(transformIndex % 512u) * 3;
|
|
143399
|
+
int v = int(transformIndex / 512u);
|
|
143400
|
+
|
|
143401
|
+
mat3x4 t;
|
|
143402
|
+
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143403
|
+
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143404
|
+
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143405
|
+
|
|
143406
|
+
center = vec4(center, 1.0) * t;
|
|
143407
|
+
}
|
|
143408
|
+
|
|
143409
|
+
gl_FragColor = vec4(center, 0.0);
|
|
143410
|
+
}
|
|
143380
143411
|
`;
|
|
143381
143412
|
|
|
143382
143413
|
const v1 = new Vec3();
|
|
@@ -143413,18 +143444,18 @@ class DataProcessor {
|
|
|
143413
143444
|
attributes: {
|
|
143414
143445
|
vertex_position: SEMANTIC_POSITION
|
|
143415
143446
|
},
|
|
143416
|
-
vertexGLSL: `
|
|
143417
|
-
attribute vec2 vertex_position;
|
|
143418
|
-
void main(void) {
|
|
143419
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143420
|
-
}
|
|
143447
|
+
vertexGLSL: `
|
|
143448
|
+
attribute vec2 vertex_position;
|
|
143449
|
+
void main(void) {
|
|
143450
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143451
|
+
}
|
|
143421
143452
|
`,
|
|
143422
|
-
fragmentGLSL: `
|
|
143423
|
-
uniform sampler2D colorTex;
|
|
143424
|
-
void main(void) {
|
|
143425
|
-
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
143426
|
-
gl_FragColor = texelFetch(colorTex, texel, 0);
|
|
143427
|
-
}
|
|
143453
|
+
fragmentGLSL: `
|
|
143454
|
+
uniform sampler2D colorTex;
|
|
143455
|
+
void main(void) {
|
|
143456
|
+
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
143457
|
+
gl_FragColor = texelFetch(colorTex, texel, 0);
|
|
143458
|
+
}
|
|
143428
143459
|
`
|
|
143429
143460
|
});
|
|
143430
143461
|
// intersection test
|
|
@@ -143797,6 +143828,10 @@ class PointerController {
|
|
|
143797
143828
|
};
|
|
143798
143829
|
// Allow temporarily disabling camera controls (e.g. while dragging gizmos).
|
|
143799
143830
|
let enabled = true;
|
|
143831
|
+
// Granular control over specific input types
|
|
143832
|
+
let orbitEnabled = true;
|
|
143833
|
+
let panEnabled = true;
|
|
143834
|
+
let zoomEnabled = true;
|
|
143800
143835
|
const resetState = () => {
|
|
143801
143836
|
pressedButton = -1;
|
|
143802
143837
|
touches = [];
|
|
@@ -143903,13 +143938,13 @@ class PointerController {
|
|
|
143903
143938
|
(event.shiftKey || event.ctrlKey ? 'orbit' :
|
|
143904
143939
|
(event.altKey || event.metaKey ? 'zoom' : null)) :
|
|
143905
143940
|
null;
|
|
143906
|
-
if (mod === 'orbit' || (mod === null && pressedButton === 0)) {
|
|
143941
|
+
if ((mod === 'orbit' || (mod === null && pressedButton === 0)) && orbitEnabled) {
|
|
143907
143942
|
orbit(dx, dy);
|
|
143908
143943
|
}
|
|
143909
|
-
else if (mod === 'zoom' || (mod === null && pressedButton === 1)) {
|
|
143944
|
+
else if ((mod === 'zoom' || (mod === null && pressedButton === 1)) && zoomEnabled) {
|
|
143910
143945
|
zoom(dy * -0.02);
|
|
143911
143946
|
}
|
|
143912
|
-
else if (mod === 'pan' || (mod === null && pressedButton === 2)) {
|
|
143947
|
+
else if ((mod === 'pan' || (mod === null && pressedButton === 2)) && panEnabled) {
|
|
143913
143948
|
pan(x, y, dx, dy);
|
|
143914
143949
|
}
|
|
143915
143950
|
}
|
|
@@ -143920,7 +143955,9 @@ class PointerController {
|
|
|
143920
143955
|
const dy = event.offsetY - touch.y;
|
|
143921
143956
|
touch.x = event.offsetX;
|
|
143922
143957
|
touch.y = event.offsetY;
|
|
143923
|
-
|
|
143958
|
+
if (orbitEnabled) {
|
|
143959
|
+
orbit(dx, dy);
|
|
143960
|
+
}
|
|
143924
143961
|
}
|
|
143925
143962
|
else if (touches.length === 2) {
|
|
143926
143963
|
const touch = touches[touches.map(t => t.id).indexOf(event.pointerId)];
|
|
@@ -143929,8 +143966,12 @@ class PointerController {
|
|
|
143929
143966
|
const mx = (touches[0].x + touches[1].x) * 0.5;
|
|
143930
143967
|
const my = (touches[0].y + touches[1].y) * 0.5;
|
|
143931
143968
|
const ml = dist(touches[0].x, touches[0].y, touches[1].x, touches[1].y);
|
|
143932
|
-
|
|
143933
|
-
|
|
143969
|
+
if (panEnabled) {
|
|
143970
|
+
pan(mx, my, (mx - midx), (my - midy));
|
|
143971
|
+
}
|
|
143972
|
+
if (zoomEnabled) {
|
|
143973
|
+
zoom((ml - midlen) * 0.01);
|
|
143974
|
+
}
|
|
143934
143975
|
midx = mx;
|
|
143935
143976
|
midy = my;
|
|
143936
143977
|
midlen = ml;
|
|
@@ -143948,16 +143989,20 @@ class PointerController {
|
|
|
143948
143989
|
return;
|
|
143949
143990
|
const { deltaX, deltaY } = event;
|
|
143950
143991
|
if (isMouseEvent(deltaX, deltaY)) {
|
|
143951
|
-
|
|
143992
|
+
if (zoomEnabled)
|
|
143993
|
+
zoom(deltaY * -2e-3);
|
|
143952
143994
|
}
|
|
143953
143995
|
else if (event.ctrlKey || event.metaKey) {
|
|
143954
|
-
|
|
143996
|
+
if (zoomEnabled)
|
|
143997
|
+
zoom(deltaY * -0.02);
|
|
143955
143998
|
}
|
|
143956
143999
|
else if (event.shiftKey) {
|
|
143957
|
-
|
|
144000
|
+
if (panEnabled)
|
|
144001
|
+
pan(event.offsetX, event.offsetY, deltaX, deltaY);
|
|
143958
144002
|
}
|
|
143959
144003
|
else {
|
|
143960
|
-
|
|
144004
|
+
if (orbitEnabled)
|
|
144005
|
+
orbit(deltaX, deltaY);
|
|
143961
144006
|
}
|
|
143962
144007
|
event.preventDefault();
|
|
143963
144008
|
};
|
|
@@ -144025,6 +144070,14 @@ class PointerController {
|
|
|
144025
144070
|
resetState();
|
|
144026
144071
|
}
|
|
144027
144072
|
};
|
|
144073
|
+
this.setInputControls = (options) => {
|
|
144074
|
+
if (options.orbit !== undefined)
|
|
144075
|
+
orbitEnabled = !!options.orbit;
|
|
144076
|
+
if (options.pan !== undefined)
|
|
144077
|
+
panEnabled = !!options.pan;
|
|
144078
|
+
if (options.zoom !== undefined)
|
|
144079
|
+
zoomEnabled = !!options.zoom;
|
|
144080
|
+
};
|
|
144028
144081
|
}
|
|
144029
144082
|
}
|
|
144030
144083
|
|
|
@@ -144663,176 +144716,176 @@ class Camera extends Element$1 {
|
|
|
144663
144716
|
}
|
|
144664
144717
|
}
|
|
144665
144718
|
|
|
144666
|
-
const vertexShader$3 = /* glsl*/ `
|
|
144667
|
-
uniform vec3 near_origin;
|
|
144668
|
-
uniform vec3 near_x;
|
|
144669
|
-
uniform vec3 near_y;
|
|
144670
|
-
|
|
144671
|
-
uniform vec3 far_origin;
|
|
144672
|
-
uniform vec3 far_x;
|
|
144673
|
-
uniform vec3 far_y;
|
|
144674
|
-
|
|
144675
|
-
attribute vec2 vertex_position;
|
|
144676
|
-
|
|
144677
|
-
varying vec3 worldFar;
|
|
144678
|
-
varying vec3 worldNear;
|
|
144679
|
-
|
|
144680
|
-
void main(void) {
|
|
144681
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
144682
|
-
|
|
144683
|
-
vec2 p = vertex_position * 0.5 + 0.5;
|
|
144684
|
-
worldNear = near_origin + near_x * p.x + near_y * p.y;
|
|
144685
|
-
worldFar = far_origin + far_x * p.x + far_y * p.y;
|
|
144686
|
-
}
|
|
144687
|
-
`;
|
|
144688
|
-
const fragmentShader$3 = /* glsl*/ `
|
|
144689
|
-
uniform vec3 view_position;
|
|
144690
|
-
uniform mat4 matrix_viewProjection;
|
|
144691
|
-
uniform sampler2D blueNoiseTex32;
|
|
144692
|
-
|
|
144693
|
-
uniform int plane; // 0: x (yz), 1: y (xz), 2: z (xy)
|
|
144694
|
-
|
|
144695
|
-
vec4 planes[3] = vec4[3](
|
|
144696
|
-
vec4(1.0, 0.0, 0.0, 0.0),
|
|
144697
|
-
vec4(0.0, 1.0, 0.0, 0.0),
|
|
144698
|
-
vec4(0.0, 0.0, 1.0, 0.0)
|
|
144699
|
-
);
|
|
144700
|
-
|
|
144701
|
-
vec3 colors[3] = vec3[3](
|
|
144702
|
-
vec3(1.0, 0.2, 0.2),
|
|
144703
|
-
vec3(0.2, 1.0, 0.2),
|
|
144704
|
-
vec3(0.2, 0.2, 1.0)
|
|
144705
|
-
);
|
|
144706
|
-
|
|
144707
|
-
int axis0[3] = int[3](1, 0, 0);
|
|
144708
|
-
int axis1[3] = int[3](2, 2, 1);
|
|
144709
|
-
|
|
144710
|
-
varying vec3 worldNear;
|
|
144711
|
-
varying vec3 worldFar;
|
|
144712
|
-
|
|
144713
|
-
bool intersectPlane(inout float t, vec3 pos, vec3 dir, vec4 plane) {
|
|
144714
|
-
float d = dot(dir, plane.xyz);
|
|
144715
|
-
if (abs(d) < 1e-06) {
|
|
144716
|
-
return false;
|
|
144717
|
-
}
|
|
144718
|
-
|
|
144719
|
-
float n = -(dot(pos, plane.xyz) + plane.w) / d;
|
|
144720
|
-
if (n < 0.0) {
|
|
144721
|
-
return false;
|
|
144722
|
-
}
|
|
144723
|
-
|
|
144724
|
-
t = n;
|
|
144725
|
-
|
|
144726
|
-
return true;
|
|
144727
|
-
}
|
|
144728
|
-
|
|
144729
|
-
// https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8#1e7c
|
|
144730
|
-
float pristineGrid(in vec2 uv, in vec2 ddx, in vec2 ddy, vec2 lineWidth) {
|
|
144731
|
-
vec2 uvDeriv = vec2(length(vec2(ddx.x, ddy.x)), length(vec2(ddx.y, ddy.y)));
|
|
144732
|
-
bvec2 invertLine = bvec2(lineWidth.x > 0.5, lineWidth.y > 0.5);
|
|
144733
|
-
vec2 targetWidth = vec2(
|
|
144734
|
-
invertLine.x ? 1.0 - lineWidth.x : lineWidth.x,
|
|
144735
|
-
invertLine.y ? 1.0 - lineWidth.y : lineWidth.y
|
|
144736
|
-
);
|
|
144737
|
-
vec2 drawWidth = clamp(targetWidth, uvDeriv, vec2(0.5));
|
|
144738
|
-
vec2 lineAA = uvDeriv * 1.5;
|
|
144739
|
-
vec2 gridUV = abs(fract(uv) * 2.0 - 1.0);
|
|
144740
|
-
gridUV.x = invertLine.x ? gridUV.x : 1.0 - gridUV.x;
|
|
144741
|
-
gridUV.y = invertLine.y ? gridUV.y : 1.0 - gridUV.y;
|
|
144742
|
-
vec2 grid2 = smoothstep(drawWidth + lineAA, drawWidth - lineAA, gridUV);
|
|
144743
|
-
|
|
144744
|
-
grid2 *= clamp(targetWidth / drawWidth, 0.0, 1.0);
|
|
144745
|
-
grid2 = mix(grid2, targetWidth, clamp(uvDeriv * 2.0 - 1.0, 0.0, 1.0));
|
|
144746
|
-
grid2.x = invertLine.x ? 1.0 - grid2.x : grid2.x;
|
|
144747
|
-
grid2.y = invertLine.y ? 1.0 - grid2.y : grid2.y;
|
|
144748
|
-
|
|
144749
|
-
return mix(grid2.x, 1.0, grid2.y);
|
|
144750
|
-
}
|
|
144751
|
-
|
|
144752
|
-
float calcDepth(vec3 p) {
|
|
144753
|
-
vec4 v = matrix_viewProjection * vec4(p, 1.0);
|
|
144754
|
-
return (v.z / v.w) * 0.5 + 0.5;
|
|
144755
|
-
}
|
|
144756
|
-
|
|
144757
|
-
bool writeDepth(float alpha) {
|
|
144758
|
-
vec2 uv = fract(gl_FragCoord.xy / 32.0);
|
|
144759
|
-
float noise = texture2DLod(blueNoiseTex32, uv, 0.0).y;
|
|
144760
|
-
return alpha > noise;
|
|
144761
|
-
}
|
|
144762
|
-
|
|
144763
|
-
void main(void) {
|
|
144764
|
-
vec3 p = worldNear;
|
|
144765
|
-
vec3 v = normalize(worldFar - worldNear);
|
|
144766
|
-
|
|
144767
|
-
// intersect ray with the world xz plane
|
|
144768
|
-
float t;
|
|
144769
|
-
if (!intersectPlane(t, p, v, planes[plane])) {
|
|
144770
|
-
discard;
|
|
144771
|
-
}
|
|
144772
|
-
|
|
144773
|
-
// calculate grid intersection
|
|
144774
|
-
vec3 worldPos = p + v * t;
|
|
144775
|
-
vec2 pos = plane == 0 ? worldPos.yz : (plane == 1 ? worldPos.xz : worldPos.xy);
|
|
144776
|
-
vec2 ddx = dFdx(pos);
|
|
144777
|
-
vec2 ddy = dFdy(pos);
|
|
144778
|
-
|
|
144779
|
-
float epsilon = 1.0 / 255.0;
|
|
144780
|
-
|
|
144781
|
-
// calculate fade
|
|
144782
|
-
float fade = 1.0 - smoothstep(400.0, 1000.0, length(worldPos - view_position));
|
|
144783
|
-
if (fade < epsilon) {
|
|
144784
|
-
discard;
|
|
144785
|
-
}
|
|
144786
|
-
|
|
144787
|
-
vec2 levelPos;
|
|
144788
|
-
float levelSize;
|
|
144789
|
-
float levelAlpha;
|
|
144790
|
-
|
|
144791
|
-
// 10m grid with colored main axes
|
|
144792
|
-
levelPos = pos * 0.1;
|
|
144793
|
-
levelSize = 2.0 / 1000.0;
|
|
144794
|
-
levelAlpha = pristineGrid(levelPos, ddx * 0.1, ddy * 0.1, vec2(levelSize)) * fade;
|
|
144795
|
-
if (levelAlpha > epsilon) {
|
|
144796
|
-
vec3 color;
|
|
144797
|
-
vec2 loc = abs(levelPos);
|
|
144798
|
-
if (loc.x < levelSize) {
|
|
144799
|
-
if (loc.y < levelSize) {
|
|
144800
|
-
color = vec3(1.0);
|
|
144801
|
-
} else {
|
|
144802
|
-
color = colors[axis1[plane]];
|
|
144803
|
-
}
|
|
144804
|
-
} else if (loc.y < levelSize) {
|
|
144805
|
-
color = colors[axis0[plane]];
|
|
144806
|
-
} else {
|
|
144807
|
-
color = vec3(0.9);
|
|
144808
|
-
}
|
|
144809
|
-
gl_FragColor = vec4(color, levelAlpha);
|
|
144810
|
-
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144811
|
-
return;
|
|
144812
|
-
}
|
|
144813
|
-
|
|
144814
|
-
// 1m grid
|
|
144815
|
-
levelPos = pos;
|
|
144816
|
-
levelSize = 1.0 / 100.0;
|
|
144817
|
-
levelAlpha = pristineGrid(levelPos, ddx, ddy, vec2(levelSize)) * fade;
|
|
144818
|
-
if (levelAlpha > epsilon) {
|
|
144819
|
-
gl_FragColor = vec4(vec3(0.7), levelAlpha);
|
|
144820
|
-
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144821
|
-
return;
|
|
144822
|
-
}
|
|
144823
|
-
|
|
144824
|
-
// 0.1m grid
|
|
144825
|
-
levelPos = pos * 10.0;
|
|
144826
|
-
levelSize = 1.0 / 100.0;
|
|
144827
|
-
levelAlpha = pristineGrid(levelPos, ddx * 10.0, ddy * 10.0, vec2(levelSize)) * fade;
|
|
144828
|
-
if (levelAlpha > epsilon) {
|
|
144829
|
-
gl_FragColor = vec4(vec3(0.7), levelAlpha);
|
|
144830
|
-
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144831
|
-
return;
|
|
144832
|
-
}
|
|
144833
|
-
|
|
144834
|
-
discard;
|
|
144835
|
-
}
|
|
144719
|
+
const vertexShader$3 = /* glsl*/ `
|
|
144720
|
+
uniform vec3 near_origin;
|
|
144721
|
+
uniform vec3 near_x;
|
|
144722
|
+
uniform vec3 near_y;
|
|
144723
|
+
|
|
144724
|
+
uniform vec3 far_origin;
|
|
144725
|
+
uniform vec3 far_x;
|
|
144726
|
+
uniform vec3 far_y;
|
|
144727
|
+
|
|
144728
|
+
attribute vec2 vertex_position;
|
|
144729
|
+
|
|
144730
|
+
varying vec3 worldFar;
|
|
144731
|
+
varying vec3 worldNear;
|
|
144732
|
+
|
|
144733
|
+
void main(void) {
|
|
144734
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
144735
|
+
|
|
144736
|
+
vec2 p = vertex_position * 0.5 + 0.5;
|
|
144737
|
+
worldNear = near_origin + near_x * p.x + near_y * p.y;
|
|
144738
|
+
worldFar = far_origin + far_x * p.x + far_y * p.y;
|
|
144739
|
+
}
|
|
144740
|
+
`;
|
|
144741
|
+
const fragmentShader$3 = /* glsl*/ `
|
|
144742
|
+
uniform vec3 view_position;
|
|
144743
|
+
uniform mat4 matrix_viewProjection;
|
|
144744
|
+
uniform sampler2D blueNoiseTex32;
|
|
144745
|
+
|
|
144746
|
+
uniform int plane; // 0: x (yz), 1: y (xz), 2: z (xy)
|
|
144747
|
+
|
|
144748
|
+
vec4 planes[3] = vec4[3](
|
|
144749
|
+
vec4(1.0, 0.0, 0.0, 0.0),
|
|
144750
|
+
vec4(0.0, 1.0, 0.0, 0.0),
|
|
144751
|
+
vec4(0.0, 0.0, 1.0, 0.0)
|
|
144752
|
+
);
|
|
144753
|
+
|
|
144754
|
+
vec3 colors[3] = vec3[3](
|
|
144755
|
+
vec3(1.0, 0.2, 0.2),
|
|
144756
|
+
vec3(0.2, 1.0, 0.2),
|
|
144757
|
+
vec3(0.2, 0.2, 1.0)
|
|
144758
|
+
);
|
|
144759
|
+
|
|
144760
|
+
int axis0[3] = int[3](1, 0, 0);
|
|
144761
|
+
int axis1[3] = int[3](2, 2, 1);
|
|
144762
|
+
|
|
144763
|
+
varying vec3 worldNear;
|
|
144764
|
+
varying vec3 worldFar;
|
|
144765
|
+
|
|
144766
|
+
bool intersectPlane(inout float t, vec3 pos, vec3 dir, vec4 plane) {
|
|
144767
|
+
float d = dot(dir, plane.xyz);
|
|
144768
|
+
if (abs(d) < 1e-06) {
|
|
144769
|
+
return false;
|
|
144770
|
+
}
|
|
144771
|
+
|
|
144772
|
+
float n = -(dot(pos, plane.xyz) + plane.w) / d;
|
|
144773
|
+
if (n < 0.0) {
|
|
144774
|
+
return false;
|
|
144775
|
+
}
|
|
144776
|
+
|
|
144777
|
+
t = n;
|
|
144778
|
+
|
|
144779
|
+
return true;
|
|
144780
|
+
}
|
|
144781
|
+
|
|
144782
|
+
// https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8#1e7c
|
|
144783
|
+
float pristineGrid(in vec2 uv, in vec2 ddx, in vec2 ddy, vec2 lineWidth) {
|
|
144784
|
+
vec2 uvDeriv = vec2(length(vec2(ddx.x, ddy.x)), length(vec2(ddx.y, ddy.y)));
|
|
144785
|
+
bvec2 invertLine = bvec2(lineWidth.x > 0.5, lineWidth.y > 0.5);
|
|
144786
|
+
vec2 targetWidth = vec2(
|
|
144787
|
+
invertLine.x ? 1.0 - lineWidth.x : lineWidth.x,
|
|
144788
|
+
invertLine.y ? 1.0 - lineWidth.y : lineWidth.y
|
|
144789
|
+
);
|
|
144790
|
+
vec2 drawWidth = clamp(targetWidth, uvDeriv, vec2(0.5));
|
|
144791
|
+
vec2 lineAA = uvDeriv * 1.5;
|
|
144792
|
+
vec2 gridUV = abs(fract(uv) * 2.0 - 1.0);
|
|
144793
|
+
gridUV.x = invertLine.x ? gridUV.x : 1.0 - gridUV.x;
|
|
144794
|
+
gridUV.y = invertLine.y ? gridUV.y : 1.0 - gridUV.y;
|
|
144795
|
+
vec2 grid2 = smoothstep(drawWidth + lineAA, drawWidth - lineAA, gridUV);
|
|
144796
|
+
|
|
144797
|
+
grid2 *= clamp(targetWidth / drawWidth, 0.0, 1.0);
|
|
144798
|
+
grid2 = mix(grid2, targetWidth, clamp(uvDeriv * 2.0 - 1.0, 0.0, 1.0));
|
|
144799
|
+
grid2.x = invertLine.x ? 1.0 - grid2.x : grid2.x;
|
|
144800
|
+
grid2.y = invertLine.y ? 1.0 - grid2.y : grid2.y;
|
|
144801
|
+
|
|
144802
|
+
return mix(grid2.x, 1.0, grid2.y);
|
|
144803
|
+
}
|
|
144804
|
+
|
|
144805
|
+
float calcDepth(vec3 p) {
|
|
144806
|
+
vec4 v = matrix_viewProjection * vec4(p, 1.0);
|
|
144807
|
+
return (v.z / v.w) * 0.5 + 0.5;
|
|
144808
|
+
}
|
|
144809
|
+
|
|
144810
|
+
bool writeDepth(float alpha) {
|
|
144811
|
+
vec2 uv = fract(gl_FragCoord.xy / 32.0);
|
|
144812
|
+
float noise = texture2DLod(blueNoiseTex32, uv, 0.0).y;
|
|
144813
|
+
return alpha > noise;
|
|
144814
|
+
}
|
|
144815
|
+
|
|
144816
|
+
void main(void) {
|
|
144817
|
+
vec3 p = worldNear;
|
|
144818
|
+
vec3 v = normalize(worldFar - worldNear);
|
|
144819
|
+
|
|
144820
|
+
// intersect ray with the world xz plane
|
|
144821
|
+
float t;
|
|
144822
|
+
if (!intersectPlane(t, p, v, planes[plane])) {
|
|
144823
|
+
discard;
|
|
144824
|
+
}
|
|
144825
|
+
|
|
144826
|
+
// calculate grid intersection
|
|
144827
|
+
vec3 worldPos = p + v * t;
|
|
144828
|
+
vec2 pos = plane == 0 ? worldPos.yz : (plane == 1 ? worldPos.xz : worldPos.xy);
|
|
144829
|
+
vec2 ddx = dFdx(pos);
|
|
144830
|
+
vec2 ddy = dFdy(pos);
|
|
144831
|
+
|
|
144832
|
+
float epsilon = 1.0 / 255.0;
|
|
144833
|
+
|
|
144834
|
+
// calculate fade
|
|
144835
|
+
float fade = 1.0 - smoothstep(400.0, 1000.0, length(worldPos - view_position));
|
|
144836
|
+
if (fade < epsilon) {
|
|
144837
|
+
discard;
|
|
144838
|
+
}
|
|
144839
|
+
|
|
144840
|
+
vec2 levelPos;
|
|
144841
|
+
float levelSize;
|
|
144842
|
+
float levelAlpha;
|
|
144843
|
+
|
|
144844
|
+
// 10m grid with colored main axes
|
|
144845
|
+
levelPos = pos * 0.1;
|
|
144846
|
+
levelSize = 2.0 / 1000.0;
|
|
144847
|
+
levelAlpha = pristineGrid(levelPos, ddx * 0.1, ddy * 0.1, vec2(levelSize)) * fade;
|
|
144848
|
+
if (levelAlpha > epsilon) {
|
|
144849
|
+
vec3 color;
|
|
144850
|
+
vec2 loc = abs(levelPos);
|
|
144851
|
+
if (loc.x < levelSize) {
|
|
144852
|
+
if (loc.y < levelSize) {
|
|
144853
|
+
color = vec3(1.0);
|
|
144854
|
+
} else {
|
|
144855
|
+
color = colors[axis1[plane]];
|
|
144856
|
+
}
|
|
144857
|
+
} else if (loc.y < levelSize) {
|
|
144858
|
+
color = colors[axis0[plane]];
|
|
144859
|
+
} else {
|
|
144860
|
+
color = vec3(0.9);
|
|
144861
|
+
}
|
|
144862
|
+
gl_FragColor = vec4(color, levelAlpha);
|
|
144863
|
+
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144864
|
+
return;
|
|
144865
|
+
}
|
|
144866
|
+
|
|
144867
|
+
// 1m grid
|
|
144868
|
+
levelPos = pos;
|
|
144869
|
+
levelSize = 1.0 / 100.0;
|
|
144870
|
+
levelAlpha = pristineGrid(levelPos, ddx, ddy, vec2(levelSize)) * fade;
|
|
144871
|
+
if (levelAlpha > epsilon) {
|
|
144872
|
+
gl_FragColor = vec4(vec3(0.7), levelAlpha);
|
|
144873
|
+
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144874
|
+
return;
|
|
144875
|
+
}
|
|
144876
|
+
|
|
144877
|
+
// 0.1m grid
|
|
144878
|
+
levelPos = pos * 10.0;
|
|
144879
|
+
levelSize = 1.0 / 100.0;
|
|
144880
|
+
levelAlpha = pristineGrid(levelPos, ddx * 10.0, ddy * 10.0, vec2(levelSize)) * fade;
|
|
144881
|
+
if (levelAlpha > epsilon) {
|
|
144882
|
+
gl_FragColor = vec4(vec3(0.7), levelAlpha);
|
|
144883
|
+
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144884
|
+
return;
|
|
144885
|
+
}
|
|
144886
|
+
|
|
144887
|
+
discard;
|
|
144888
|
+
}
|
|
144836
144889
|
`;
|
|
144837
144890
|
|
|
144838
144891
|
const resolve = (scope, values) => {
|
|
@@ -144903,36 +144956,36 @@ class InfiniteGrid extends Element$1 {
|
|
|
144903
144956
|
}
|
|
144904
144957
|
}
|
|
144905
144958
|
|
|
144906
|
-
const vertexShader$2 = /* glsl*/ `
|
|
144907
|
-
attribute vec2 vertex_position;
|
|
144908
|
-
void main(void) {
|
|
144909
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
144910
|
-
}
|
|
144911
|
-
`;
|
|
144912
|
-
const fragmentShader$2 = /* glsl*/ `
|
|
144913
|
-
uniform sampler2D outlineTexture;
|
|
144914
|
-
uniform float alphaCutoff;
|
|
144915
|
-
uniform vec4 clr;
|
|
144916
|
-
|
|
144917
|
-
void main(void) {
|
|
144918
|
-
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
144919
|
-
|
|
144920
|
-
// skip solid pixels
|
|
144921
|
-
if (texelFetch(outlineTexture, texel, 0).a > alphaCutoff) {
|
|
144922
|
-
discard;
|
|
144923
|
-
}
|
|
144924
|
-
|
|
144925
|
-
for (int x = -2; x <= 2; x++) {
|
|
144926
|
-
for (int y = -2; y <= 2; y++) {
|
|
144927
|
-
if ((x != 0) && (y != 0) && (texelFetch(outlineTexture, texel + ivec2(x, y), 0).a > alphaCutoff)) {
|
|
144928
|
-
gl_FragColor = clr;
|
|
144929
|
-
return;
|
|
144930
|
-
}
|
|
144931
|
-
}
|
|
144932
|
-
}
|
|
144933
|
-
|
|
144934
|
-
discard;
|
|
144935
|
-
}
|
|
144959
|
+
const vertexShader$2 = /* glsl*/ `
|
|
144960
|
+
attribute vec2 vertex_position;
|
|
144961
|
+
void main(void) {
|
|
144962
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
144963
|
+
}
|
|
144964
|
+
`;
|
|
144965
|
+
const fragmentShader$2 = /* glsl*/ `
|
|
144966
|
+
uniform sampler2D outlineTexture;
|
|
144967
|
+
uniform float alphaCutoff;
|
|
144968
|
+
uniform vec4 clr;
|
|
144969
|
+
|
|
144970
|
+
void main(void) {
|
|
144971
|
+
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
144972
|
+
|
|
144973
|
+
// skip solid pixels
|
|
144974
|
+
if (texelFetch(outlineTexture, texel, 0).a > alphaCutoff) {
|
|
144975
|
+
discard;
|
|
144976
|
+
}
|
|
144977
|
+
|
|
144978
|
+
for (int x = -2; x <= 2; x++) {
|
|
144979
|
+
for (int y = -2; y <= 2; y++) {
|
|
144980
|
+
if ((x != 0) && (y != 0) && (texelFetch(outlineTexture, texel + ivec2(x, y), 0).a > alphaCutoff)) {
|
|
144981
|
+
gl_FragColor = clr;
|
|
144982
|
+
return;
|
|
144983
|
+
}
|
|
144984
|
+
}
|
|
144985
|
+
}
|
|
144986
|
+
|
|
144987
|
+
discard;
|
|
144988
|
+
}
|
|
144936
144989
|
`;
|
|
144937
144990
|
|
|
144938
144991
|
class Outline extends Element$1 {
|
|
@@ -145250,72 +145303,72 @@ class SceneState {
|
|
|
145250
145303
|
}
|
|
145251
145304
|
}
|
|
145252
145305
|
|
|
145253
|
-
const vertexShader$1 = /* glsl */ `
|
|
145254
|
-
attribute uint vertex_id;
|
|
145255
|
-
|
|
145256
|
-
uniform mat4 matrix_model;
|
|
145257
|
-
uniform mat4 matrix_viewProjection;
|
|
145258
|
-
|
|
145259
|
-
uniform sampler2D splatState;
|
|
145260
|
-
uniform highp usampler2D splatPosition;
|
|
145261
|
-
uniform highp usampler2D splatTransform; // per-splat index into transform palette
|
|
145262
|
-
uniform sampler2D transformPalette; // palette of transform matrices
|
|
145263
|
-
|
|
145264
|
-
uniform uvec2 texParams;
|
|
145265
|
-
|
|
145266
|
-
uniform float splatSize;
|
|
145267
|
-
uniform vec4 selectedClr;
|
|
145268
|
-
uniform vec4 unselectedClr;
|
|
145269
|
-
|
|
145270
|
-
varying vec4 varying_color;
|
|
145271
|
-
|
|
145272
|
-
// calculate the current splat index and uv
|
|
145273
|
-
ivec2 calcSplatUV(uint index, uint width) {
|
|
145274
|
-
return ivec2(int(index % width), int(index / width));
|
|
145275
|
-
}
|
|
145276
|
-
|
|
145277
|
-
void main(void) {
|
|
145278
|
-
ivec2 splatUV = calcSplatUV(vertex_id, texParams.x);
|
|
145279
|
-
uint splatState = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
|
|
145280
|
-
|
|
145281
|
-
if ((splatState & 6u) != 0u) {
|
|
145282
|
-
// deleted or locked (4 or 2)
|
|
145283
|
-
gl_Position = vec4(0.0, 0.0, 2.0, 1.0);
|
|
145284
|
-
gl_PointSize = 0.0;
|
|
145285
|
-
} else {
|
|
145286
|
-
mat4 model = matrix_model;
|
|
145287
|
-
|
|
145288
|
-
// handle per-splat transform
|
|
145289
|
-
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
145290
|
-
if (transformIndex > 0u) {
|
|
145291
|
-
// read transform matrix
|
|
145292
|
-
int u = int(transformIndex % 512u) * 3;
|
|
145293
|
-
int v = int(transformIndex / 512u);
|
|
145294
|
-
|
|
145295
|
-
mat4 t;
|
|
145296
|
-
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
145297
|
-
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
145298
|
-
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
145299
|
-
t[3] = vec4(0.0, 0.0, 0.0, 1.0);
|
|
145300
|
-
|
|
145301
|
-
model = matrix_model * transpose(t);
|
|
145302
|
-
}
|
|
145303
|
-
|
|
145304
|
-
varying_color = (splatState == 1u) ? selectedClr : unselectedClr;
|
|
145305
|
-
|
|
145306
|
-
vec3 center = uintBitsToFloat(texelFetch(splatPosition, splatUV, 0).xyz);
|
|
145307
|
-
|
|
145308
|
-
gl_Position = matrix_viewProjection * model * vec4(center, 1.0);
|
|
145309
|
-
gl_PointSize = splatSize;
|
|
145310
|
-
}
|
|
145311
|
-
}
|
|
145312
|
-
`;
|
|
145313
|
-
const fragmentShader$1 = /* glsl */ `
|
|
145314
|
-
varying vec4 varying_color;
|
|
145315
|
-
|
|
145316
|
-
void main(void) {
|
|
145317
|
-
gl_FragColor = varying_color;
|
|
145318
|
-
}
|
|
145306
|
+
const vertexShader$1 = /* glsl */ `
|
|
145307
|
+
attribute uint vertex_id;
|
|
145308
|
+
|
|
145309
|
+
uniform mat4 matrix_model;
|
|
145310
|
+
uniform mat4 matrix_viewProjection;
|
|
145311
|
+
|
|
145312
|
+
uniform sampler2D splatState;
|
|
145313
|
+
uniform highp usampler2D splatPosition;
|
|
145314
|
+
uniform highp usampler2D splatTransform; // per-splat index into transform palette
|
|
145315
|
+
uniform sampler2D transformPalette; // palette of transform matrices
|
|
145316
|
+
|
|
145317
|
+
uniform uvec2 texParams;
|
|
145318
|
+
|
|
145319
|
+
uniform float splatSize;
|
|
145320
|
+
uniform vec4 selectedClr;
|
|
145321
|
+
uniform vec4 unselectedClr;
|
|
145322
|
+
|
|
145323
|
+
varying vec4 varying_color;
|
|
145324
|
+
|
|
145325
|
+
// calculate the current splat index and uv
|
|
145326
|
+
ivec2 calcSplatUV(uint index, uint width) {
|
|
145327
|
+
return ivec2(int(index % width), int(index / width));
|
|
145328
|
+
}
|
|
145329
|
+
|
|
145330
|
+
void main(void) {
|
|
145331
|
+
ivec2 splatUV = calcSplatUV(vertex_id, texParams.x);
|
|
145332
|
+
uint splatState = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
|
|
145333
|
+
|
|
145334
|
+
if ((splatState & 6u) != 0u) {
|
|
145335
|
+
// deleted or locked (4 or 2)
|
|
145336
|
+
gl_Position = vec4(0.0, 0.0, 2.0, 1.0);
|
|
145337
|
+
gl_PointSize = 0.0;
|
|
145338
|
+
} else {
|
|
145339
|
+
mat4 model = matrix_model;
|
|
145340
|
+
|
|
145341
|
+
// handle per-splat transform
|
|
145342
|
+
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
145343
|
+
if (transformIndex > 0u) {
|
|
145344
|
+
// read transform matrix
|
|
145345
|
+
int u = int(transformIndex % 512u) * 3;
|
|
145346
|
+
int v = int(transformIndex / 512u);
|
|
145347
|
+
|
|
145348
|
+
mat4 t;
|
|
145349
|
+
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
145350
|
+
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
145351
|
+
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
145352
|
+
t[3] = vec4(0.0, 0.0, 0.0, 1.0);
|
|
145353
|
+
|
|
145354
|
+
model = matrix_model * transpose(t);
|
|
145355
|
+
}
|
|
145356
|
+
|
|
145357
|
+
varying_color = (splatState == 1u) ? selectedClr : unselectedClr;
|
|
145358
|
+
|
|
145359
|
+
vec3 center = uintBitsToFloat(texelFetch(splatPosition, splatUV, 0).xyz);
|
|
145360
|
+
|
|
145361
|
+
gl_Position = matrix_viewProjection * model * vec4(center, 1.0);
|
|
145362
|
+
gl_PointSize = splatSize;
|
|
145363
|
+
}
|
|
145364
|
+
}
|
|
145365
|
+
`;
|
|
145366
|
+
const fragmentShader$1 = /* glsl */ `
|
|
145367
|
+
varying vec4 varying_color;
|
|
145368
|
+
|
|
145369
|
+
void main(void) {
|
|
145370
|
+
gl_FragColor = varying_color;
|
|
145371
|
+
}
|
|
145319
145372
|
`;
|
|
145320
145373
|
|
|
145321
145374
|
class SplatOverlay extends Element$1 {
|
|
@@ -145404,19 +145457,19 @@ class SplatOverlay extends Element$1 {
|
|
|
145404
145457
|
}
|
|
145405
145458
|
}
|
|
145406
145459
|
|
|
145407
|
-
const vertexShader = /* glsl*/ `
|
|
145408
|
-
attribute vec2 vertex_position;
|
|
145409
|
-
void main(void) {
|
|
145410
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
145411
|
-
}
|
|
145460
|
+
const vertexShader = /* glsl*/ `
|
|
145461
|
+
attribute vec2 vertex_position;
|
|
145462
|
+
void main(void) {
|
|
145463
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
145464
|
+
}
|
|
145412
145465
|
`;
|
|
145413
|
-
const fragmentShader = /* glsl*/ `
|
|
145414
|
-
uniform sampler2D blitTexture;
|
|
145415
|
-
void main(void) {
|
|
145416
|
-
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
145417
|
-
|
|
145418
|
-
gl_FragColor = texelFetch(blitTexture, texel, 0);
|
|
145419
|
-
}
|
|
145466
|
+
const fragmentShader = /* glsl*/ `
|
|
145467
|
+
uniform sampler2D blitTexture;
|
|
145468
|
+
void main(void) {
|
|
145469
|
+
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
145470
|
+
|
|
145471
|
+
gl_FragColor = texelFetch(blitTexture, texel, 0);
|
|
145472
|
+
}
|
|
145420
145473
|
`;
|
|
145421
145474
|
|
|
145422
145475
|
class Underlay extends Element$1 {
|
|
@@ -147329,6 +147382,26 @@ class SupersplatAdapter {
|
|
|
147329
147382
|
console.warn('SupersplatAdapter: Failed to toggle camera controls', e);
|
|
147330
147383
|
}
|
|
147331
147384
|
}
|
|
147385
|
+
/**
|
|
147386
|
+
* Configure granular control over specific camera input types.
|
|
147387
|
+
* Allows enabling/disabling orbit, pan, and zoom independently.
|
|
147388
|
+
*/
|
|
147389
|
+
setCameraInputControls(options) {
|
|
147390
|
+
const controller = this.scene?.camera?.controller;
|
|
147391
|
+
if (!controller)
|
|
147392
|
+
return;
|
|
147393
|
+
try {
|
|
147394
|
+
if (typeof controller.setInputControls === 'function') {
|
|
147395
|
+
controller.setInputControls(options);
|
|
147396
|
+
}
|
|
147397
|
+
else {
|
|
147398
|
+
console.warn('SupersplatAdapter: Camera controller does not support setInputControls');
|
|
147399
|
+
}
|
|
147400
|
+
}
|
|
147401
|
+
catch (e) {
|
|
147402
|
+
console.warn('SupersplatAdapter: Failed to set camera input controls', e);
|
|
147403
|
+
}
|
|
147404
|
+
}
|
|
147332
147405
|
/**
|
|
147333
147406
|
* Enable/disable supersplat-core camera auto-update (orbit tweens).
|
|
147334
147407
|
* When enabled, the camera entity transform may be driven by an external controller (fly mode).
|
|
@@ -147693,6 +147766,7 @@ class SplatViewerCore {
|
|
|
147693
147766
|
};
|
|
147694
147767
|
this.enableStats = false;
|
|
147695
147768
|
this.autoFocus = true;
|
|
147769
|
+
this.previewMode = false;
|
|
147696
147770
|
this.isLoading = false;
|
|
147697
147771
|
this.hasModel = false;
|
|
147698
147772
|
this.error = null;
|
|
@@ -147745,6 +147819,11 @@ class SplatViewerCore {
|
|
|
147745
147819
|
this.canvas = options.canvas || null;
|
|
147746
147820
|
this.enableStats = options.enableStats || false;
|
|
147747
147821
|
this.autoFocus = options.autoFocus !== false;
|
|
147822
|
+
this.previewMode = options.previewMode || false;
|
|
147823
|
+
// In preview mode, always enable auto-focus
|
|
147824
|
+
if (this.previewMode) {
|
|
147825
|
+
this.autoFocus = true;
|
|
147826
|
+
}
|
|
147748
147827
|
this._navigationCubeConfig = options.navigationCube || null;
|
|
147749
147828
|
if (options.onStatsUpdate !== undefined) {
|
|
147750
147829
|
this._onStatsUpdate = options.onStatsUpdate;
|
|
@@ -147775,11 +147854,20 @@ class SplatViewerCore {
|
|
|
147775
147854
|
const emitEvent = (type, detail) => {
|
|
147776
147855
|
this.emit({ type, detail });
|
|
147777
147856
|
};
|
|
147778
|
-
this._supersplat = new SupersplatAdapter(this.canvas,
|
|
147857
|
+
this._supersplat = new SupersplatAdapter(this.canvas,
|
|
147858
|
+
// Disable navigation cube in preview mode
|
|
147859
|
+
this.previewMode ? null : this._navigationCubeConfig, emitEvent);
|
|
147779
147860
|
this._supersplatReady = this._supersplat.init();
|
|
147780
147861
|
this._supersplatReady
|
|
147781
147862
|
?.then(() => {
|
|
147782
|
-
|
|
147863
|
+
// In preview mode, enable zoom only (disable orbit and pan)
|
|
147864
|
+
if (this.previewMode && this._supersplat) {
|
|
147865
|
+
this._supersplat.setCameraInputControls?.({ orbit: false, pan: false, zoom: true });
|
|
147866
|
+
}
|
|
147867
|
+
// Only set up fly camera if not in preview mode
|
|
147868
|
+
if (!this.previewMode) {
|
|
147869
|
+
this._setupFlyCameraForSupersplat();
|
|
147870
|
+
}
|
|
147783
147871
|
})
|
|
147784
147872
|
.catch(error => {
|
|
147785
147873
|
console.error('SplatViewerCore.init: Failed to set up fly camera for supersplat path', error);
|
|
@@ -147818,7 +147906,9 @@ class SplatViewerCore {
|
|
|
147818
147906
|
// SuperSplat's PCApp omits ScriptComponentSystem, so `addComponent('script')`
|
|
147819
147907
|
// will not produce `camera.script.create()`. We keep the attempt (in case
|
|
147820
147908
|
// the underlying app changes), but also support a controller-based fallback.
|
|
147821
|
-
if (cameraAny &&
|
|
147909
|
+
if (cameraAny &&
|
|
147910
|
+
!cameraAny.script &&
|
|
147911
|
+
typeof cameraAny.addComponent === 'function') {
|
|
147822
147912
|
try {
|
|
147823
147913
|
cameraAny.addComponent('script');
|
|
147824
147914
|
}
|
|
@@ -147844,7 +147934,9 @@ class SplatViewerCore {
|
|
|
147844
147934
|
// Prefer script-based fly when available; fallback to controller otherwise.
|
|
147845
147935
|
const canCreateScript = typeof cameraAny?.script?.create === 'function';
|
|
147846
147936
|
if (canCreateScript) {
|
|
147847
|
-
const created = cameraAny.script.create('flyCamera', {
|
|
147937
|
+
const created = cameraAny.script.create('flyCamera', {
|
|
147938
|
+
attributes: flyAttributes,
|
|
147939
|
+
});
|
|
147848
147940
|
this._fly = created;
|
|
147849
147941
|
if (this._fly) {
|
|
147850
147942
|
;
|
|
@@ -149708,6 +149800,11 @@ class SplatViewerCore {
|
|
|
149708
149800
|
// Camera Mode / Fly Camera API
|
|
149709
149801
|
// ==========================================
|
|
149710
149802
|
setCameraMode(mode) {
|
|
149803
|
+
// Prevent camera mode changes in preview mode
|
|
149804
|
+
if (this.previewMode) {
|
|
149805
|
+
console.warn('SplatViewerCore.setCameraMode: Camera controls are disabled in preview mode');
|
|
149806
|
+
return;
|
|
149807
|
+
}
|
|
149711
149808
|
// supersplat-core path: manage mode switching explicitly (camera entity is updated by supersplat-core each frame)
|
|
149712
149809
|
if (this._supersplat) {
|
|
149713
149810
|
const prev = this._cameraMode;
|
|
@@ -149737,7 +149834,9 @@ class SplatViewerCore {
|
|
|
149737
149834
|
try {
|
|
149738
149835
|
const pos = this.entities.camera?.getPosition?.();
|
|
149739
149836
|
if (pos) {
|
|
149740
|
-
const posVec = pos.clone
|
|
149837
|
+
const posVec = pos.clone
|
|
149838
|
+
? pos.clone()
|
|
149839
|
+
: new Vec3(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
149741
149840
|
this.entities.camera?.setPosition?.(posVec);
|
|
149742
149841
|
}
|
|
149743
149842
|
const euler = this.entities.camera?.getEulerAngles?.();
|
|
@@ -149960,8 +150059,8 @@ class SplatViewerCore {
|
|
|
149960
150059
|
panSensitivity: 1.0,
|
|
149961
150060
|
zoomSensitivity: 0.1,
|
|
149962
150061
|
};
|
|
149963
|
-
// Add navigation cube configuration if available
|
|
149964
|
-
if (this._navigationCubeConfig) {
|
|
150062
|
+
// Add navigation cube configuration if available (but not in preview mode)
|
|
150063
|
+
if (this._navigationCubeConfig && !this.previewMode) {
|
|
149965
150064
|
orbitAttributes.enableNavigationCube =
|
|
149966
150065
|
this._navigationCubeConfig.enabled || false;
|
|
149967
150066
|
this.entities.camera._navigationCubeConfig =
|
|
@@ -149976,48 +150075,58 @@ class SplatViewerCore {
|
|
|
149976
150075
|
detail: { type: interactionType },
|
|
149977
150076
|
});
|
|
149978
150077
|
};
|
|
150078
|
+
// In preview mode, enable zoom only (disable orbit and pan)
|
|
150079
|
+
if (this.previewMode && this._orbit) {
|
|
150080
|
+
const orbitAny = this._orbit;
|
|
150081
|
+
if (typeof orbitAny.setInputControls === 'function') {
|
|
150082
|
+
// Enable zoom, disable orbit and pan
|
|
150083
|
+
orbitAny.setInputControls({ orbit: false, pan: false, zoom: true });
|
|
150084
|
+
}
|
|
150085
|
+
}
|
|
149979
150086
|
this.entities.camera.setPosition(0, 0, 10);
|
|
149980
150087
|
this.entities.camera.lookAt(Vec3.ZERO);
|
|
149981
150088
|
// ==============================
|
|
149982
|
-
// Setup fly camera (disabled by default)
|
|
150089
|
+
// Setup fly camera (disabled by default, skipped in preview mode)
|
|
149983
150090
|
// ==============================
|
|
149984
|
-
|
|
149985
|
-
|
|
149986
|
-
|
|
149987
|
-
|
|
149988
|
-
|
|
149989
|
-
|
|
149990
|
-
|
|
149991
|
-
|
|
149992
|
-
|
|
149993
|
-
|
|
149994
|
-
|
|
149995
|
-
|
|
149996
|
-
|
|
149997
|
-
|
|
149998
|
-
|
|
149999
|
-
|
|
150000
|
-
this._fly = this.entities.camera.script.create('flyCamera', {
|
|
150001
|
-
attributes: flyAttributes,
|
|
150002
|
-
});
|
|
150003
|
-
// Wire event emission to core
|
|
150004
|
-
if (this._fly) {
|
|
150005
|
-
;
|
|
150006
|
-
this._fly.emitFlyEvent = (type, detail) => {
|
|
150007
|
-
this.emit({ type: type, detail });
|
|
150091
|
+
if (!this.previewMode) {
|
|
150092
|
+
try {
|
|
150093
|
+
registerFlyCameraScript();
|
|
150094
|
+
// Ensure script component exists (created above)
|
|
150095
|
+
const flyAttributes = {
|
|
150096
|
+
moveSpeed: DEFAULT_FLY_CAMERA_CONFIG.moveSpeed,
|
|
150097
|
+
fastSpeedMultiplier: DEFAULT_FLY_CAMERA_CONFIG.fastSpeedMultiplier,
|
|
150098
|
+
slowSpeedMultiplier: DEFAULT_FLY_CAMERA_CONFIG.slowSpeedMultiplier,
|
|
150099
|
+
lookSensitivity: DEFAULT_FLY_CAMERA_CONFIG.lookSensitivity,
|
|
150100
|
+
invertY: DEFAULT_FLY_CAMERA_CONFIG.invertY,
|
|
150101
|
+
keyBindings: DEFAULT_FLY_CAMERA_CONFIG.keyBindings,
|
|
150102
|
+
smoothing: DEFAULT_FLY_CAMERA_CONFIG.smoothing,
|
|
150103
|
+
friction: DEFAULT_FLY_CAMERA_CONFIG.friction,
|
|
150104
|
+
enableCollision: DEFAULT_FLY_CAMERA_CONFIG.enableCollision,
|
|
150105
|
+
minHeight: DEFAULT_FLY_CAMERA_CONFIG.minHeight,
|
|
150106
|
+
maxHeight: DEFAULT_FLY_CAMERA_CONFIG.maxHeight,
|
|
150008
150107
|
};
|
|
150108
|
+
this._fly = this.entities.camera.script.create('flyCamera', {
|
|
150109
|
+
attributes: flyAttributes,
|
|
150110
|
+
});
|
|
150111
|
+
// Wire event emission to core
|
|
150112
|
+
if (this._fly) {
|
|
150113
|
+
;
|
|
150114
|
+
this._fly.emitFlyEvent = (type, detail) => {
|
|
150115
|
+
this.emit({ type: type, detail });
|
|
150116
|
+
};
|
|
150117
|
+
}
|
|
150118
|
+
// Deactivate fly by default; orbit is the initial mode
|
|
150119
|
+
if (this._fly?.deactivate) {
|
|
150120
|
+
this._fly.deactivate();
|
|
150121
|
+
}
|
|
150122
|
+
// Initialize camera mode manager
|
|
150123
|
+
this._cameraModeManager = new CameraModeManager(this.app, this.entities.camera, this._orbit, this._fly, (eventType, detail) => {
|
|
150124
|
+
this.emit({ type: eventType, detail });
|
|
150125
|
+
}, 'orbit');
|
|
150009
150126
|
}
|
|
150010
|
-
|
|
150011
|
-
|
|
150012
|
-
this._fly.deactivate();
|
|
150127
|
+
catch (e) {
|
|
150128
|
+
console.warn('Failed to set up fly camera', e);
|
|
150013
150129
|
}
|
|
150014
|
-
// Initialize camera mode manager
|
|
150015
|
-
this._cameraModeManager = new CameraModeManager(this.app, this.entities.camera, this._orbit, this._fly, (eventType, detail) => {
|
|
150016
|
-
this.emit({ type: eventType, detail });
|
|
150017
|
-
}, 'orbit');
|
|
150018
|
-
}
|
|
150019
|
-
catch (e) {
|
|
150020
|
-
console.warn('Failed to set up fly camera', e);
|
|
150021
150130
|
}
|
|
150022
150131
|
}
|
|
150023
150132
|
_setupStats() {
|
|
@@ -150262,6 +150371,7 @@ class SplatViewerElement extends HTMLElement {
|
|
|
150262
150371
|
'enable-stats',
|
|
150263
150372
|
'auto-focus',
|
|
150264
150373
|
'max-splats',
|
|
150374
|
+
'preview-mode',
|
|
150265
150375
|
'camera-position',
|
|
150266
150376
|
'camera-target',
|
|
150267
150377
|
'orbit-sensitivity',
|
|
@@ -150292,6 +150402,9 @@ class SplatViewerElement extends HTMLElement {
|
|
|
150292
150402
|
get autoFocus() {
|
|
150293
150403
|
return this.hasAttribute('auto-focus');
|
|
150294
150404
|
}
|
|
150405
|
+
get previewMode() {
|
|
150406
|
+
return this.hasAttribute('preview-mode');
|
|
150407
|
+
}
|
|
150295
150408
|
get maxSplats() {
|
|
150296
150409
|
return this.getAttribute('max-splats');
|
|
150297
150410
|
}
|
|
@@ -150369,6 +150482,14 @@ class SplatViewerElement extends HTMLElement {
|
|
|
150369
150482
|
this.removeAttribute('auto-focus');
|
|
150370
150483
|
}
|
|
150371
150484
|
}
|
|
150485
|
+
set previewMode(value) {
|
|
150486
|
+
if (value) {
|
|
150487
|
+
this.setAttribute('preview-mode', '');
|
|
150488
|
+
}
|
|
150489
|
+
else {
|
|
150490
|
+
this.removeAttribute('preview-mode');
|
|
150491
|
+
}
|
|
150492
|
+
}
|
|
150372
150493
|
set maxSplats(value) {
|
|
150373
150494
|
if (value === null) {
|
|
150374
150495
|
this.removeAttribute('max-splats');
|
|
@@ -150550,6 +150671,7 @@ class SplatViewerElement extends HTMLElement {
|
|
|
150550
150671
|
return value.length > 0;
|
|
150551
150672
|
case 'enable-stats':
|
|
150552
150673
|
case 'auto-focus':
|
|
150674
|
+
case 'preview-mode':
|
|
150553
150675
|
case 'enable-navigation-cube':
|
|
150554
150676
|
// Boolean attributes - any value is valid
|
|
150555
150677
|
return true;
|
|
@@ -151496,7 +151618,7 @@ class SplatViewerElement extends HTMLElement {
|
|
|
151496
151618
|
if (!this._core) {
|
|
151497
151619
|
throw new Error('SplatViewerElement: Core not initialized. Call connectedCallback first.');
|
|
151498
151620
|
}
|
|
151499
|
-
return this._core.selectSplatsInSphere(center, radius, modelId, addToSelection);
|
|
151621
|
+
return this._core.selectSplatsInSphere(new Vec3(center.x, center.y, center.z), radius, modelId, addToSelection);
|
|
151500
151622
|
}
|
|
151501
151623
|
clearSplatSelection() {
|
|
151502
151624
|
if (!this._core) {
|