@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
|
@@ -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 },
|
|
@@ -139563,11 +139564,15 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
139563
139564
|
}
|
|
139564
139565
|
/**
|
|
139565
139566
|
* Convert a string to a boolean value
|
|
139567
|
+
* For HTML boolean attributes, an empty string means the attribute is present (true)
|
|
139566
139568
|
*/
|
|
139567
139569
|
function parseBoolean(value) {
|
|
139568
139570
|
if (typeof value === 'boolean')
|
|
139569
139571
|
return value;
|
|
139570
139572
|
if (typeof value === 'string') {
|
|
139573
|
+
// Empty string means attribute is present without value (should be true for boolean attributes)
|
|
139574
|
+
if (value === '')
|
|
139575
|
+
return true;
|
|
139571
139576
|
return value.toLowerCase() === 'true' || value === '1';
|
|
139572
139577
|
}
|
|
139573
139578
|
return false;
|
|
@@ -139615,6 +139620,10 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
139615
139620
|
if (enableStats !== null) {
|
|
139616
139621
|
config.enableStats = parseBoolean(enableStats);
|
|
139617
139622
|
}
|
|
139623
|
+
const previewMode = element.getAttribute('preview-mode');
|
|
139624
|
+
if (previewMode !== null) {
|
|
139625
|
+
config.previewMode = parseBoolean(previewMode);
|
|
139626
|
+
}
|
|
139618
139627
|
// Parse number attributes
|
|
139619
139628
|
const maxSplats = element.getAttribute('max-splats');
|
|
139620
139629
|
if (maxSplats !== null) {
|
|
@@ -140454,6 +140463,10 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140454
140463
|
this.isPanning = false;
|
|
140455
140464
|
// Allow host to temporarily disable camera input (e.g., while dragging gizmos)
|
|
140456
140465
|
this._inputEnabled = true;
|
|
140466
|
+
// Granular control over specific input types
|
|
140467
|
+
this._orbitEnabled = true;
|
|
140468
|
+
this._panEnabled = true;
|
|
140469
|
+
this._zoomEnabled = true;
|
|
140457
140470
|
// Setup context menu prevention
|
|
140458
140471
|
this.setupContextMenuPrevention();
|
|
140459
140472
|
// Use PlayCanvas mouse events for reliable input handling
|
|
@@ -140491,6 +140504,19 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140491
140504
|
this.isPanning = false;
|
|
140492
140505
|
}
|
|
140493
140506
|
};
|
|
140507
|
+
OrbitCamera.prototype.setInputControls = function (options) {
|
|
140508
|
+
if (options.orbit !== undefined)
|
|
140509
|
+
this._orbitEnabled = !!options.orbit;
|
|
140510
|
+
if (options.pan !== undefined)
|
|
140511
|
+
this._panEnabled = !!options.pan;
|
|
140512
|
+
if (options.zoom !== undefined)
|
|
140513
|
+
this._zoomEnabled = !!options.zoom;
|
|
140514
|
+
// Clear any in-progress interactions if being disabled
|
|
140515
|
+
if (this._orbitEnabled === false)
|
|
140516
|
+
this.isOrbiting = false;
|
|
140517
|
+
if (this._panEnabled === false)
|
|
140518
|
+
this.isPanning = false;
|
|
140519
|
+
};
|
|
140494
140520
|
OrbitCamera.prototype.update = function (dt) {
|
|
140495
140521
|
// Update navigation cube if enabled
|
|
140496
140522
|
if (this.navigationCube &&
|
|
@@ -140507,12 +140533,13 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140507
140533
|
typeof this.navigationCube.cancelTransition === 'function') {
|
|
140508
140534
|
this.navigationCube.cancelTransition('manual-interaction');
|
|
140509
140535
|
}
|
|
140510
|
-
if (event.button === MOUSEBUTTON_LEFT) {
|
|
140536
|
+
if (event.button === MOUSEBUTTON_LEFT && this._orbitEnabled !== false) {
|
|
140511
140537
|
this.isOrbiting = true;
|
|
140512
140538
|
this.emitInteractionEvent?.('interaction-start', 'rotate');
|
|
140513
140539
|
}
|
|
140514
|
-
else if (event.button === MOUSEBUTTON_RIGHT ||
|
|
140515
|
-
event.button === MOUSEBUTTON_MIDDLE)
|
|
140540
|
+
else if ((event.button === MOUSEBUTTON_RIGHT ||
|
|
140541
|
+
event.button === MOUSEBUTTON_MIDDLE) &&
|
|
140542
|
+
this._panEnabled !== false) {
|
|
140516
140543
|
this.isPanning = true;
|
|
140517
140544
|
this.emitInteractionEvent?.('interaction-start', 'pan');
|
|
140518
140545
|
}
|
|
@@ -140560,7 +140587,7 @@ fn fragmentMain(input: FragmentInput) -> FragmentOutput {
|
|
|
140560
140587
|
}
|
|
140561
140588
|
};
|
|
140562
140589
|
OrbitCamera.prototype.onMouseWheel = function (event) {
|
|
140563
|
-
if (this._inputEnabled === false)
|
|
140590
|
+
if (this._inputEnabled === false || this._zoomEnabled === false)
|
|
140564
140591
|
return;
|
|
140565
140592
|
// Cancel any ongoing navigation cube transition when manual zoom interaction starts
|
|
140566
140593
|
if (this.navigationCube &&
|
|
@@ -142696,6 +142723,10 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
142696
142723
|
this.entity.setEulerAngles(orientation);
|
|
142697
142724
|
this.entity.addComponent('gsplat', { asset });
|
|
142698
142725
|
const instance = this.entity.gsplat.instance;
|
|
142726
|
+
// Check if the gsplat component initialized properly
|
|
142727
|
+
if (!instance || !instance.meshInstance) {
|
|
142728
|
+
throw new Error('Failed to initialize gsplat component. The file may not contain valid Gaussian Splatting data.');
|
|
142729
|
+
}
|
|
142699
142730
|
// use custom render order distance calculation for splats
|
|
142700
142731
|
instance.meshInstance.calculateSortDistance = (meshInstance, pos, dir) => {
|
|
142701
142732
|
const bound = this.localBound;
|
|
@@ -143168,222 +143199,222 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
143168
143199
|
}
|
|
143169
143200
|
}
|
|
143170
143201
|
|
|
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
|
-
}
|
|
143202
|
+
const vertexShader$6 = /* glsl */ `
|
|
143203
|
+
attribute vec2 vertex_position;
|
|
143204
|
+
void main(void) {
|
|
143205
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143206
|
+
}
|
|
143207
|
+
`;
|
|
143208
|
+
const fragmentShader$6 = /* glsl */ `
|
|
143209
|
+
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143210
|
+
uniform highp usampler2D splatTransform; // transform palette index
|
|
143211
|
+
uniform sampler2D transformPalette; // palette of transforms
|
|
143212
|
+
uniform sampler2D splatState; // per-splat state
|
|
143213
|
+
uniform highp ivec3 splat_params; // texture width, texture height, num splats
|
|
143214
|
+
uniform highp uint mode; // 0: selected, 1: visible
|
|
143215
|
+
|
|
143216
|
+
// calculate min and max for a single column of splats
|
|
143217
|
+
void main(void) {
|
|
143218
|
+
|
|
143219
|
+
vec3 boundMin = vec3(1e6);
|
|
143220
|
+
vec3 boundMax = vec3(-1e6);
|
|
143221
|
+
|
|
143222
|
+
for (int id = 0; id < splat_params.y; id++) {
|
|
143223
|
+
// calculate splatUV
|
|
143224
|
+
ivec2 splatUV = ivec2(gl_FragCoord.x, id);
|
|
143225
|
+
|
|
143226
|
+
// skip out-of-range splats
|
|
143227
|
+
if ((splatUV.x + splatUV.y * splat_params.x) >= splat_params.z) {
|
|
143228
|
+
continue;
|
|
143229
|
+
}
|
|
143230
|
+
|
|
143231
|
+
// read splat state
|
|
143232
|
+
uint state = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
|
|
143233
|
+
|
|
143234
|
+
// skip deleted or locked splats
|
|
143235
|
+
if (((mode == 0u) && (state != 1u)) || ((mode == 1u) && ((state & 4u) != 0u))) {
|
|
143236
|
+
continue;
|
|
143237
|
+
}
|
|
143238
|
+
|
|
143239
|
+
// read splat center
|
|
143240
|
+
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143241
|
+
|
|
143242
|
+
// apply optional per-splat transform
|
|
143243
|
+
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143244
|
+
if (transformIndex > 0u) {
|
|
143245
|
+
// read transform matrix
|
|
143246
|
+
int u = int(transformIndex % 512u) * 3;
|
|
143247
|
+
int v = int(transformIndex / 512u);
|
|
143248
|
+
|
|
143249
|
+
mat3x4 t;
|
|
143250
|
+
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143251
|
+
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143252
|
+
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143253
|
+
|
|
143254
|
+
center = vec4(center, 1.0) * t;
|
|
143255
|
+
}
|
|
143256
|
+
|
|
143257
|
+
boundMin = min(boundMin, mix(center, boundMin, isinf(center)));
|
|
143258
|
+
boundMax = max(boundMax, mix(center, boundMax, isinf(center)));
|
|
143259
|
+
}
|
|
143260
|
+
|
|
143261
|
+
pcFragColor0 = vec4(boundMin, 0.0);
|
|
143262
|
+
pcFragColor1 = vec4(boundMax, 0.0);
|
|
143263
|
+
}
|
|
143264
|
+
`;
|
|
143265
|
+
|
|
143266
|
+
const vertexShader$5 = /* glsl */ `
|
|
143267
|
+
attribute vec2 vertex_position;
|
|
143268
|
+
void main(void) {
|
|
143269
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143270
|
+
}
|
|
143271
|
+
`;
|
|
143272
|
+
const fragmentShader$5 = /* glsl */ `
|
|
143273
|
+
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143274
|
+
uniform highp usampler2D splatTransform; // transform palette index
|
|
143275
|
+
uniform sampler2D transformPalette; // palette of transforms
|
|
143276
|
+
uniform uvec2 splat_params; // splat texture width, num splats
|
|
143277
|
+
|
|
143278
|
+
uniform mat4 matrix_model;
|
|
143279
|
+
uniform mat4 matrix_viewProjection;
|
|
143280
|
+
|
|
143281
|
+
uniform uvec2 output_params; // output width, height
|
|
143282
|
+
|
|
143283
|
+
// 0: mask, 1: rect, 2: sphere
|
|
143284
|
+
uniform int mode;
|
|
143285
|
+
|
|
143286
|
+
// mask params
|
|
143287
|
+
uniform sampler2D mask; // mask in alpha channel
|
|
143288
|
+
uniform vec2 mask_params; // mask width, height
|
|
143289
|
+
|
|
143290
|
+
// rect params
|
|
143291
|
+
uniform vec4 rect_params; // rect x, y, width, height
|
|
143292
|
+
|
|
143293
|
+
// sphere params
|
|
143294
|
+
uniform vec4 sphere_params; // sphere x, y, z, radius
|
|
143295
|
+
|
|
143296
|
+
// box params
|
|
143297
|
+
uniform vec4 box_params; // box x, y, z
|
|
143298
|
+
uniform vec4 aabb_params; // len x, y, z
|
|
143299
|
+
|
|
143300
|
+
void main(void) {
|
|
143301
|
+
// calculate output id
|
|
143302
|
+
uvec2 outputUV = uvec2(gl_FragCoord);
|
|
143303
|
+
uint outputId = (outputUV.x + outputUV.y * output_params.x) * 4u;
|
|
143304
|
+
|
|
143305
|
+
vec4 clr = vec4(0.0);
|
|
143306
|
+
|
|
143307
|
+
for (uint i = 0u; i < 4u; i++) {
|
|
143308
|
+
uint id = outputId + i;
|
|
143309
|
+
|
|
143310
|
+
if (id >= splat_params.y) {
|
|
143311
|
+
continue;
|
|
143312
|
+
}
|
|
143313
|
+
|
|
143314
|
+
// calculate splatUV
|
|
143315
|
+
ivec2 splatUV = ivec2(
|
|
143316
|
+
int(id % splat_params.x),
|
|
143317
|
+
int(id / splat_params.x)
|
|
143318
|
+
);
|
|
143319
|
+
|
|
143320
|
+
// read splat center
|
|
143321
|
+
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143322
|
+
|
|
143323
|
+
// apply optional per-splat transform
|
|
143324
|
+
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143325
|
+
if (transformIndex > 0u) {
|
|
143326
|
+
// read transform matrix
|
|
143327
|
+
int u = int(transformIndex % 512u) * 3;
|
|
143328
|
+
int v = int(transformIndex / 512u);
|
|
143329
|
+
|
|
143330
|
+
mat3x4 t;
|
|
143331
|
+
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143332
|
+
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143333
|
+
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143334
|
+
|
|
143335
|
+
center = vec4(center, 1.0) * t;
|
|
143336
|
+
}
|
|
143337
|
+
|
|
143338
|
+
// transform to clip space and discard if outside
|
|
143339
|
+
vec3 world = (matrix_model * vec4(center, 1.0)).xyz;
|
|
143340
|
+
vec4 clip = matrix_viewProjection * vec4(world, 1.0);
|
|
143341
|
+
vec3 ndc = clip.xyz / clip.w;
|
|
143342
|
+
|
|
143343
|
+
// skip offscreen fragments
|
|
143344
|
+
if (!any(greaterThan(abs(ndc), vec3(1.0)))) {
|
|
143345
|
+
if (mode == 0) {
|
|
143346
|
+
// select by mask
|
|
143347
|
+
ivec2 maskUV = ivec2((ndc.xy * vec2(0.5, -0.5) + 0.5) * mask_params);
|
|
143348
|
+
clr[i] = texelFetch(mask, maskUV, 0).a < 1.0 ? 0.0 : 1.0;
|
|
143349
|
+
} else if (mode == 1) {
|
|
143350
|
+
// select by rect
|
|
143351
|
+
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;
|
|
143352
|
+
} else if (mode == 2) {
|
|
143353
|
+
// select by sphere
|
|
143354
|
+
clr[i] = length(world - sphere_params.xyz) < sphere_params.w ? 1.0 : 0.0;
|
|
143355
|
+
} else if (mode == 3) {
|
|
143356
|
+
// select by box
|
|
143357
|
+
vec3 relativePosition = world - box_params.xyz;
|
|
143358
|
+
bool isInsideCube = true;
|
|
143359
|
+
if (relativePosition.x < -aabb_params.x || relativePosition.x > aabb_params.x) {
|
|
143360
|
+
isInsideCube = false;
|
|
143361
|
+
}
|
|
143362
|
+
if (relativePosition.y < -aabb_params.y || relativePosition.y > aabb_params.y) {
|
|
143363
|
+
isInsideCube = false;
|
|
143364
|
+
}
|
|
143365
|
+
if (relativePosition.z < -aabb_params.z || relativePosition.z > aabb_params.z) {
|
|
143366
|
+
isInsideCube = false;
|
|
143367
|
+
}
|
|
143368
|
+
clr[i] = isInsideCube ? 1.0 : 0.0;
|
|
143369
|
+
}
|
|
143370
|
+
}
|
|
143371
|
+
}
|
|
143372
|
+
|
|
143373
|
+
gl_FragColor = clr;
|
|
143374
|
+
}
|
|
143375
|
+
`;
|
|
143376
|
+
|
|
143377
|
+
const vertexShader$4 = /* glsl */ `
|
|
143378
|
+
attribute vec2 vertex_position;
|
|
143379
|
+
void main(void) {
|
|
143380
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143381
|
+
}
|
|
143382
|
+
`;
|
|
143383
|
+
const fragmentShader$4 = /* glsl */ `
|
|
143384
|
+
uniform highp usampler2D transformA; // splat center x, y, z
|
|
143385
|
+
uniform highp usampler2D splatTransform; // transform palette index
|
|
143386
|
+
uniform sampler2D transformPalette; // palette of transforms
|
|
143387
|
+
uniform ivec2 splat_params; // splat texture width, num splats
|
|
143388
|
+
|
|
143389
|
+
void main(void) {
|
|
143390
|
+
// calculate output id
|
|
143391
|
+
ivec2 splatUV = ivec2(gl_FragCoord);
|
|
143392
|
+
|
|
143393
|
+
// skip if splat index is out of bounds
|
|
143394
|
+
if (splatUV.x + splatUV.y * splat_params.x >= splat_params.y) {
|
|
143395
|
+
discard;
|
|
143396
|
+
}
|
|
143397
|
+
|
|
143398
|
+
// read splat center
|
|
143399
|
+
vec3 center = uintBitsToFloat(texelFetch(transformA, splatUV, 0).xyz);
|
|
143400
|
+
|
|
143401
|
+
// apply optional per-splat transform
|
|
143402
|
+
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
143403
|
+
if (transformIndex > 0u) {
|
|
143404
|
+
// read transform matrix
|
|
143405
|
+
int u = int(transformIndex % 512u) * 3;
|
|
143406
|
+
int v = int(transformIndex / 512u);
|
|
143407
|
+
|
|
143408
|
+
mat3x4 t;
|
|
143409
|
+
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
143410
|
+
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
143411
|
+
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
143412
|
+
|
|
143413
|
+
center = vec4(center, 1.0) * t;
|
|
143414
|
+
}
|
|
143415
|
+
|
|
143416
|
+
gl_FragColor = vec4(center, 0.0);
|
|
143417
|
+
}
|
|
143387
143418
|
`;
|
|
143388
143419
|
|
|
143389
143420
|
const v1 = new Vec3();
|
|
@@ -143420,18 +143451,18 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
143420
143451
|
attributes: {
|
|
143421
143452
|
vertex_position: SEMANTIC_POSITION
|
|
143422
143453
|
},
|
|
143423
|
-
vertexGLSL: `
|
|
143424
|
-
attribute vec2 vertex_position;
|
|
143425
|
-
void main(void) {
|
|
143426
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143427
|
-
}
|
|
143454
|
+
vertexGLSL: `
|
|
143455
|
+
attribute vec2 vertex_position;
|
|
143456
|
+
void main(void) {
|
|
143457
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
143458
|
+
}
|
|
143428
143459
|
`,
|
|
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
|
-
}
|
|
143460
|
+
fragmentGLSL: `
|
|
143461
|
+
uniform sampler2D colorTex;
|
|
143462
|
+
void main(void) {
|
|
143463
|
+
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
143464
|
+
gl_FragColor = texelFetch(colorTex, texel, 0);
|
|
143465
|
+
}
|
|
143435
143466
|
`
|
|
143436
143467
|
});
|
|
143437
143468
|
// intersection test
|
|
@@ -143804,6 +143835,10 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
143804
143835
|
};
|
|
143805
143836
|
// Allow temporarily disabling camera controls (e.g. while dragging gizmos).
|
|
143806
143837
|
let enabled = true;
|
|
143838
|
+
// Granular control over specific input types
|
|
143839
|
+
let orbitEnabled = true;
|
|
143840
|
+
let panEnabled = true;
|
|
143841
|
+
let zoomEnabled = true;
|
|
143807
143842
|
const resetState = () => {
|
|
143808
143843
|
pressedButton = -1;
|
|
143809
143844
|
touches = [];
|
|
@@ -143910,13 +143945,13 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
143910
143945
|
(event.shiftKey || event.ctrlKey ? 'orbit' :
|
|
143911
143946
|
(event.altKey || event.metaKey ? 'zoom' : null)) :
|
|
143912
143947
|
null;
|
|
143913
|
-
if (mod === 'orbit' || (mod === null && pressedButton === 0)) {
|
|
143948
|
+
if ((mod === 'orbit' || (mod === null && pressedButton === 0)) && orbitEnabled) {
|
|
143914
143949
|
orbit(dx, dy);
|
|
143915
143950
|
}
|
|
143916
|
-
else if (mod === 'zoom' || (mod === null && pressedButton === 1)) {
|
|
143951
|
+
else if ((mod === 'zoom' || (mod === null && pressedButton === 1)) && zoomEnabled) {
|
|
143917
143952
|
zoom(dy * -0.02);
|
|
143918
143953
|
}
|
|
143919
|
-
else if (mod === 'pan' || (mod === null && pressedButton === 2)) {
|
|
143954
|
+
else if ((mod === 'pan' || (mod === null && pressedButton === 2)) && panEnabled) {
|
|
143920
143955
|
pan(x, y, dx, dy);
|
|
143921
143956
|
}
|
|
143922
143957
|
}
|
|
@@ -143927,7 +143962,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
143927
143962
|
const dy = event.offsetY - touch.y;
|
|
143928
143963
|
touch.x = event.offsetX;
|
|
143929
143964
|
touch.y = event.offsetY;
|
|
143930
|
-
|
|
143965
|
+
if (orbitEnabled) {
|
|
143966
|
+
orbit(dx, dy);
|
|
143967
|
+
}
|
|
143931
143968
|
}
|
|
143932
143969
|
else if (touches.length === 2) {
|
|
143933
143970
|
const touch = touches[touches.map(t => t.id).indexOf(event.pointerId)];
|
|
@@ -143936,8 +143973,12 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
143936
143973
|
const mx = (touches[0].x + touches[1].x) * 0.5;
|
|
143937
143974
|
const my = (touches[0].y + touches[1].y) * 0.5;
|
|
143938
143975
|
const ml = dist(touches[0].x, touches[0].y, touches[1].x, touches[1].y);
|
|
143939
|
-
|
|
143940
|
-
|
|
143976
|
+
if (panEnabled) {
|
|
143977
|
+
pan(mx, my, (mx - midx), (my - midy));
|
|
143978
|
+
}
|
|
143979
|
+
if (zoomEnabled) {
|
|
143980
|
+
zoom((ml - midlen) * 0.01);
|
|
143981
|
+
}
|
|
143941
143982
|
midx = mx;
|
|
143942
143983
|
midy = my;
|
|
143943
143984
|
midlen = ml;
|
|
@@ -143955,16 +143996,20 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
143955
143996
|
return;
|
|
143956
143997
|
const { deltaX, deltaY } = event;
|
|
143957
143998
|
if (isMouseEvent(deltaX, deltaY)) {
|
|
143958
|
-
|
|
143999
|
+
if (zoomEnabled)
|
|
144000
|
+
zoom(deltaY * -2e-3);
|
|
143959
144001
|
}
|
|
143960
144002
|
else if (event.ctrlKey || event.metaKey) {
|
|
143961
|
-
|
|
144003
|
+
if (zoomEnabled)
|
|
144004
|
+
zoom(deltaY * -0.02);
|
|
143962
144005
|
}
|
|
143963
144006
|
else if (event.shiftKey) {
|
|
143964
|
-
|
|
144007
|
+
if (panEnabled)
|
|
144008
|
+
pan(event.offsetX, event.offsetY, deltaX, deltaY);
|
|
143965
144009
|
}
|
|
143966
144010
|
else {
|
|
143967
|
-
|
|
144011
|
+
if (orbitEnabled)
|
|
144012
|
+
orbit(deltaX, deltaY);
|
|
143968
144013
|
}
|
|
143969
144014
|
event.preventDefault();
|
|
143970
144015
|
};
|
|
@@ -144032,6 +144077,14 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
144032
144077
|
resetState();
|
|
144033
144078
|
}
|
|
144034
144079
|
};
|
|
144080
|
+
this.setInputControls = (options) => {
|
|
144081
|
+
if (options.orbit !== undefined)
|
|
144082
|
+
orbitEnabled = !!options.orbit;
|
|
144083
|
+
if (options.pan !== undefined)
|
|
144084
|
+
panEnabled = !!options.pan;
|
|
144085
|
+
if (options.zoom !== undefined)
|
|
144086
|
+
zoomEnabled = !!options.zoom;
|
|
144087
|
+
};
|
|
144035
144088
|
}
|
|
144036
144089
|
}
|
|
144037
144090
|
|
|
@@ -144670,176 +144723,176 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
144670
144723
|
}
|
|
144671
144724
|
}
|
|
144672
144725
|
|
|
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
|
-
}
|
|
144726
|
+
const vertexShader$3 = /* glsl*/ `
|
|
144727
|
+
uniform vec3 near_origin;
|
|
144728
|
+
uniform vec3 near_x;
|
|
144729
|
+
uniform vec3 near_y;
|
|
144730
|
+
|
|
144731
|
+
uniform vec3 far_origin;
|
|
144732
|
+
uniform vec3 far_x;
|
|
144733
|
+
uniform vec3 far_y;
|
|
144734
|
+
|
|
144735
|
+
attribute vec2 vertex_position;
|
|
144736
|
+
|
|
144737
|
+
varying vec3 worldFar;
|
|
144738
|
+
varying vec3 worldNear;
|
|
144739
|
+
|
|
144740
|
+
void main(void) {
|
|
144741
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
144742
|
+
|
|
144743
|
+
vec2 p = vertex_position * 0.5 + 0.5;
|
|
144744
|
+
worldNear = near_origin + near_x * p.x + near_y * p.y;
|
|
144745
|
+
worldFar = far_origin + far_x * p.x + far_y * p.y;
|
|
144746
|
+
}
|
|
144747
|
+
`;
|
|
144748
|
+
const fragmentShader$3 = /* glsl*/ `
|
|
144749
|
+
uniform vec3 view_position;
|
|
144750
|
+
uniform mat4 matrix_viewProjection;
|
|
144751
|
+
uniform sampler2D blueNoiseTex32;
|
|
144752
|
+
|
|
144753
|
+
uniform int plane; // 0: x (yz), 1: y (xz), 2: z (xy)
|
|
144754
|
+
|
|
144755
|
+
vec4 planes[3] = vec4[3](
|
|
144756
|
+
vec4(1.0, 0.0, 0.0, 0.0),
|
|
144757
|
+
vec4(0.0, 1.0, 0.0, 0.0),
|
|
144758
|
+
vec4(0.0, 0.0, 1.0, 0.0)
|
|
144759
|
+
);
|
|
144760
|
+
|
|
144761
|
+
vec3 colors[3] = vec3[3](
|
|
144762
|
+
vec3(1.0, 0.2, 0.2),
|
|
144763
|
+
vec3(0.2, 1.0, 0.2),
|
|
144764
|
+
vec3(0.2, 0.2, 1.0)
|
|
144765
|
+
);
|
|
144766
|
+
|
|
144767
|
+
int axis0[3] = int[3](1, 0, 0);
|
|
144768
|
+
int axis1[3] = int[3](2, 2, 1);
|
|
144769
|
+
|
|
144770
|
+
varying vec3 worldNear;
|
|
144771
|
+
varying vec3 worldFar;
|
|
144772
|
+
|
|
144773
|
+
bool intersectPlane(inout float t, vec3 pos, vec3 dir, vec4 plane) {
|
|
144774
|
+
float d = dot(dir, plane.xyz);
|
|
144775
|
+
if (abs(d) < 1e-06) {
|
|
144776
|
+
return false;
|
|
144777
|
+
}
|
|
144778
|
+
|
|
144779
|
+
float n = -(dot(pos, plane.xyz) + plane.w) / d;
|
|
144780
|
+
if (n < 0.0) {
|
|
144781
|
+
return false;
|
|
144782
|
+
}
|
|
144783
|
+
|
|
144784
|
+
t = n;
|
|
144785
|
+
|
|
144786
|
+
return true;
|
|
144787
|
+
}
|
|
144788
|
+
|
|
144789
|
+
// https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8#1e7c
|
|
144790
|
+
float pristineGrid(in vec2 uv, in vec2 ddx, in vec2 ddy, vec2 lineWidth) {
|
|
144791
|
+
vec2 uvDeriv = vec2(length(vec2(ddx.x, ddy.x)), length(vec2(ddx.y, ddy.y)));
|
|
144792
|
+
bvec2 invertLine = bvec2(lineWidth.x > 0.5, lineWidth.y > 0.5);
|
|
144793
|
+
vec2 targetWidth = vec2(
|
|
144794
|
+
invertLine.x ? 1.0 - lineWidth.x : lineWidth.x,
|
|
144795
|
+
invertLine.y ? 1.0 - lineWidth.y : lineWidth.y
|
|
144796
|
+
);
|
|
144797
|
+
vec2 drawWidth = clamp(targetWidth, uvDeriv, vec2(0.5));
|
|
144798
|
+
vec2 lineAA = uvDeriv * 1.5;
|
|
144799
|
+
vec2 gridUV = abs(fract(uv) * 2.0 - 1.0);
|
|
144800
|
+
gridUV.x = invertLine.x ? gridUV.x : 1.0 - gridUV.x;
|
|
144801
|
+
gridUV.y = invertLine.y ? gridUV.y : 1.0 - gridUV.y;
|
|
144802
|
+
vec2 grid2 = smoothstep(drawWidth + lineAA, drawWidth - lineAA, gridUV);
|
|
144803
|
+
|
|
144804
|
+
grid2 *= clamp(targetWidth / drawWidth, 0.0, 1.0);
|
|
144805
|
+
grid2 = mix(grid2, targetWidth, clamp(uvDeriv * 2.0 - 1.0, 0.0, 1.0));
|
|
144806
|
+
grid2.x = invertLine.x ? 1.0 - grid2.x : grid2.x;
|
|
144807
|
+
grid2.y = invertLine.y ? 1.0 - grid2.y : grid2.y;
|
|
144808
|
+
|
|
144809
|
+
return mix(grid2.x, 1.0, grid2.y);
|
|
144810
|
+
}
|
|
144811
|
+
|
|
144812
|
+
float calcDepth(vec3 p) {
|
|
144813
|
+
vec4 v = matrix_viewProjection * vec4(p, 1.0);
|
|
144814
|
+
return (v.z / v.w) * 0.5 + 0.5;
|
|
144815
|
+
}
|
|
144816
|
+
|
|
144817
|
+
bool writeDepth(float alpha) {
|
|
144818
|
+
vec2 uv = fract(gl_FragCoord.xy / 32.0);
|
|
144819
|
+
float noise = texture2DLod(blueNoiseTex32, uv, 0.0).y;
|
|
144820
|
+
return alpha > noise;
|
|
144821
|
+
}
|
|
144822
|
+
|
|
144823
|
+
void main(void) {
|
|
144824
|
+
vec3 p = worldNear;
|
|
144825
|
+
vec3 v = normalize(worldFar - worldNear);
|
|
144826
|
+
|
|
144827
|
+
// intersect ray with the world xz plane
|
|
144828
|
+
float t;
|
|
144829
|
+
if (!intersectPlane(t, p, v, planes[plane])) {
|
|
144830
|
+
discard;
|
|
144831
|
+
}
|
|
144832
|
+
|
|
144833
|
+
// calculate grid intersection
|
|
144834
|
+
vec3 worldPos = p + v * t;
|
|
144835
|
+
vec2 pos = plane == 0 ? worldPos.yz : (plane == 1 ? worldPos.xz : worldPos.xy);
|
|
144836
|
+
vec2 ddx = dFdx(pos);
|
|
144837
|
+
vec2 ddy = dFdy(pos);
|
|
144838
|
+
|
|
144839
|
+
float epsilon = 1.0 / 255.0;
|
|
144840
|
+
|
|
144841
|
+
// calculate fade
|
|
144842
|
+
float fade = 1.0 - smoothstep(400.0, 1000.0, length(worldPos - view_position));
|
|
144843
|
+
if (fade < epsilon) {
|
|
144844
|
+
discard;
|
|
144845
|
+
}
|
|
144846
|
+
|
|
144847
|
+
vec2 levelPos;
|
|
144848
|
+
float levelSize;
|
|
144849
|
+
float levelAlpha;
|
|
144850
|
+
|
|
144851
|
+
// 10m grid with colored main axes
|
|
144852
|
+
levelPos = pos * 0.1;
|
|
144853
|
+
levelSize = 2.0 / 1000.0;
|
|
144854
|
+
levelAlpha = pristineGrid(levelPos, ddx * 0.1, ddy * 0.1, vec2(levelSize)) * fade;
|
|
144855
|
+
if (levelAlpha > epsilon) {
|
|
144856
|
+
vec3 color;
|
|
144857
|
+
vec2 loc = abs(levelPos);
|
|
144858
|
+
if (loc.x < levelSize) {
|
|
144859
|
+
if (loc.y < levelSize) {
|
|
144860
|
+
color = vec3(1.0);
|
|
144861
|
+
} else {
|
|
144862
|
+
color = colors[axis1[plane]];
|
|
144863
|
+
}
|
|
144864
|
+
} else if (loc.y < levelSize) {
|
|
144865
|
+
color = colors[axis0[plane]];
|
|
144866
|
+
} else {
|
|
144867
|
+
color = vec3(0.9);
|
|
144868
|
+
}
|
|
144869
|
+
gl_FragColor = vec4(color, levelAlpha);
|
|
144870
|
+
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144871
|
+
return;
|
|
144872
|
+
}
|
|
144873
|
+
|
|
144874
|
+
// 1m grid
|
|
144875
|
+
levelPos = pos;
|
|
144876
|
+
levelSize = 1.0 / 100.0;
|
|
144877
|
+
levelAlpha = pristineGrid(levelPos, ddx, ddy, vec2(levelSize)) * fade;
|
|
144878
|
+
if (levelAlpha > epsilon) {
|
|
144879
|
+
gl_FragColor = vec4(vec3(0.7), levelAlpha);
|
|
144880
|
+
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144881
|
+
return;
|
|
144882
|
+
}
|
|
144883
|
+
|
|
144884
|
+
// 0.1m grid
|
|
144885
|
+
levelPos = pos * 10.0;
|
|
144886
|
+
levelSize = 1.0 / 100.0;
|
|
144887
|
+
levelAlpha = pristineGrid(levelPos, ddx * 10.0, ddy * 10.0, vec2(levelSize)) * fade;
|
|
144888
|
+
if (levelAlpha > epsilon) {
|
|
144889
|
+
gl_FragColor = vec4(vec3(0.7), levelAlpha);
|
|
144890
|
+
gl_FragDepth = writeDepth(levelAlpha) ? calcDepth(worldPos) : 1.0;
|
|
144891
|
+
return;
|
|
144892
|
+
}
|
|
144893
|
+
|
|
144894
|
+
discard;
|
|
144895
|
+
}
|
|
144843
144896
|
`;
|
|
144844
144897
|
|
|
144845
144898
|
const resolve = (scope, values) => {
|
|
@@ -144910,36 +144963,36 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
144910
144963
|
}
|
|
144911
144964
|
}
|
|
144912
144965
|
|
|
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
|
-
}
|
|
144966
|
+
const vertexShader$2 = /* glsl*/ `
|
|
144967
|
+
attribute vec2 vertex_position;
|
|
144968
|
+
void main(void) {
|
|
144969
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
144970
|
+
}
|
|
144971
|
+
`;
|
|
144972
|
+
const fragmentShader$2 = /* glsl*/ `
|
|
144973
|
+
uniform sampler2D outlineTexture;
|
|
144974
|
+
uniform float alphaCutoff;
|
|
144975
|
+
uniform vec4 clr;
|
|
144976
|
+
|
|
144977
|
+
void main(void) {
|
|
144978
|
+
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
144979
|
+
|
|
144980
|
+
// skip solid pixels
|
|
144981
|
+
if (texelFetch(outlineTexture, texel, 0).a > alphaCutoff) {
|
|
144982
|
+
discard;
|
|
144983
|
+
}
|
|
144984
|
+
|
|
144985
|
+
for (int x = -2; x <= 2; x++) {
|
|
144986
|
+
for (int y = -2; y <= 2; y++) {
|
|
144987
|
+
if ((x != 0) && (y != 0) && (texelFetch(outlineTexture, texel + ivec2(x, y), 0).a > alphaCutoff)) {
|
|
144988
|
+
gl_FragColor = clr;
|
|
144989
|
+
return;
|
|
144990
|
+
}
|
|
144991
|
+
}
|
|
144992
|
+
}
|
|
144993
|
+
|
|
144994
|
+
discard;
|
|
144995
|
+
}
|
|
144943
144996
|
`;
|
|
144944
144997
|
|
|
144945
144998
|
class Outline extends Element$1 {
|
|
@@ -145257,72 +145310,72 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
145257
145310
|
}
|
|
145258
145311
|
}
|
|
145259
145312
|
|
|
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
|
-
}
|
|
145313
|
+
const vertexShader$1 = /* glsl */ `
|
|
145314
|
+
attribute uint vertex_id;
|
|
145315
|
+
|
|
145316
|
+
uniform mat4 matrix_model;
|
|
145317
|
+
uniform mat4 matrix_viewProjection;
|
|
145318
|
+
|
|
145319
|
+
uniform sampler2D splatState;
|
|
145320
|
+
uniform highp usampler2D splatPosition;
|
|
145321
|
+
uniform highp usampler2D splatTransform; // per-splat index into transform palette
|
|
145322
|
+
uniform sampler2D transformPalette; // palette of transform matrices
|
|
145323
|
+
|
|
145324
|
+
uniform uvec2 texParams;
|
|
145325
|
+
|
|
145326
|
+
uniform float splatSize;
|
|
145327
|
+
uniform vec4 selectedClr;
|
|
145328
|
+
uniform vec4 unselectedClr;
|
|
145329
|
+
|
|
145330
|
+
varying vec4 varying_color;
|
|
145331
|
+
|
|
145332
|
+
// calculate the current splat index and uv
|
|
145333
|
+
ivec2 calcSplatUV(uint index, uint width) {
|
|
145334
|
+
return ivec2(int(index % width), int(index / width));
|
|
145335
|
+
}
|
|
145336
|
+
|
|
145337
|
+
void main(void) {
|
|
145338
|
+
ivec2 splatUV = calcSplatUV(vertex_id, texParams.x);
|
|
145339
|
+
uint splatState = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
|
|
145340
|
+
|
|
145341
|
+
if ((splatState & 6u) != 0u) {
|
|
145342
|
+
// deleted or locked (4 or 2)
|
|
145343
|
+
gl_Position = vec4(0.0, 0.0, 2.0, 1.0);
|
|
145344
|
+
gl_PointSize = 0.0;
|
|
145345
|
+
} else {
|
|
145346
|
+
mat4 model = matrix_model;
|
|
145347
|
+
|
|
145348
|
+
// handle per-splat transform
|
|
145349
|
+
uint transformIndex = texelFetch(splatTransform, splatUV, 0).r;
|
|
145350
|
+
if (transformIndex > 0u) {
|
|
145351
|
+
// read transform matrix
|
|
145352
|
+
int u = int(transformIndex % 512u) * 3;
|
|
145353
|
+
int v = int(transformIndex / 512u);
|
|
145354
|
+
|
|
145355
|
+
mat4 t;
|
|
145356
|
+
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
|
|
145357
|
+
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
|
|
145358
|
+
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
|
|
145359
|
+
t[3] = vec4(0.0, 0.0, 0.0, 1.0);
|
|
145360
|
+
|
|
145361
|
+
model = matrix_model * transpose(t);
|
|
145362
|
+
}
|
|
145363
|
+
|
|
145364
|
+
varying_color = (splatState == 1u) ? selectedClr : unselectedClr;
|
|
145365
|
+
|
|
145366
|
+
vec3 center = uintBitsToFloat(texelFetch(splatPosition, splatUV, 0).xyz);
|
|
145367
|
+
|
|
145368
|
+
gl_Position = matrix_viewProjection * model * vec4(center, 1.0);
|
|
145369
|
+
gl_PointSize = splatSize;
|
|
145370
|
+
}
|
|
145371
|
+
}
|
|
145372
|
+
`;
|
|
145373
|
+
const fragmentShader$1 = /* glsl */ `
|
|
145374
|
+
varying vec4 varying_color;
|
|
145375
|
+
|
|
145376
|
+
void main(void) {
|
|
145377
|
+
gl_FragColor = varying_color;
|
|
145378
|
+
}
|
|
145326
145379
|
`;
|
|
145327
145380
|
|
|
145328
145381
|
class SplatOverlay extends Element$1 {
|
|
@@ -145411,19 +145464,19 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
145411
145464
|
}
|
|
145412
145465
|
}
|
|
145413
145466
|
|
|
145414
|
-
const vertexShader = /* glsl*/ `
|
|
145415
|
-
attribute vec2 vertex_position;
|
|
145416
|
-
void main(void) {
|
|
145417
|
-
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
145418
|
-
}
|
|
145467
|
+
const vertexShader = /* glsl*/ `
|
|
145468
|
+
attribute vec2 vertex_position;
|
|
145469
|
+
void main(void) {
|
|
145470
|
+
gl_Position = vec4(vertex_position, 0.0, 1.0);
|
|
145471
|
+
}
|
|
145419
145472
|
`;
|
|
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
|
-
}
|
|
145473
|
+
const fragmentShader = /* glsl*/ `
|
|
145474
|
+
uniform sampler2D blitTexture;
|
|
145475
|
+
void main(void) {
|
|
145476
|
+
ivec2 texel = ivec2(gl_FragCoord.xy);
|
|
145477
|
+
|
|
145478
|
+
gl_FragColor = texelFetch(blitTexture, texel, 0);
|
|
145479
|
+
}
|
|
145427
145480
|
`;
|
|
145428
145481
|
|
|
145429
145482
|
class Underlay extends Element$1 {
|
|
@@ -147336,6 +147389,26 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
147336
147389
|
console.warn('SupersplatAdapter: Failed to toggle camera controls', e);
|
|
147337
147390
|
}
|
|
147338
147391
|
}
|
|
147392
|
+
/**
|
|
147393
|
+
* Configure granular control over specific camera input types.
|
|
147394
|
+
* Allows enabling/disabling orbit, pan, and zoom independently.
|
|
147395
|
+
*/
|
|
147396
|
+
setCameraInputControls(options) {
|
|
147397
|
+
const controller = this.scene?.camera?.controller;
|
|
147398
|
+
if (!controller)
|
|
147399
|
+
return;
|
|
147400
|
+
try {
|
|
147401
|
+
if (typeof controller.setInputControls === 'function') {
|
|
147402
|
+
controller.setInputControls(options);
|
|
147403
|
+
}
|
|
147404
|
+
else {
|
|
147405
|
+
console.warn('SupersplatAdapter: Camera controller does not support setInputControls');
|
|
147406
|
+
}
|
|
147407
|
+
}
|
|
147408
|
+
catch (e) {
|
|
147409
|
+
console.warn('SupersplatAdapter: Failed to set camera input controls', e);
|
|
147410
|
+
}
|
|
147411
|
+
}
|
|
147339
147412
|
/**
|
|
147340
147413
|
* Enable/disable supersplat-core camera auto-update (orbit tweens).
|
|
147341
147414
|
* When enabled, the camera entity transform may be driven by an external controller (fly mode).
|
|
@@ -147700,6 +147773,7 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
147700
147773
|
};
|
|
147701
147774
|
this.enableStats = false;
|
|
147702
147775
|
this.autoFocus = true;
|
|
147776
|
+
this.previewMode = false;
|
|
147703
147777
|
this.isLoading = false;
|
|
147704
147778
|
this.hasModel = false;
|
|
147705
147779
|
this.error = null;
|
|
@@ -147752,6 +147826,11 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
147752
147826
|
this.canvas = options.canvas || null;
|
|
147753
147827
|
this.enableStats = options.enableStats || false;
|
|
147754
147828
|
this.autoFocus = options.autoFocus !== false;
|
|
147829
|
+
this.previewMode = options.previewMode || false;
|
|
147830
|
+
// In preview mode, always enable auto-focus
|
|
147831
|
+
if (this.previewMode) {
|
|
147832
|
+
this.autoFocus = true;
|
|
147833
|
+
}
|
|
147755
147834
|
this._navigationCubeConfig = options.navigationCube || null;
|
|
147756
147835
|
if (options.onStatsUpdate !== undefined) {
|
|
147757
147836
|
this._onStatsUpdate = options.onStatsUpdate;
|
|
@@ -147782,11 +147861,20 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
147782
147861
|
const emitEvent = (type, detail) => {
|
|
147783
147862
|
this.emit({ type, detail });
|
|
147784
147863
|
};
|
|
147785
|
-
this._supersplat = new SupersplatAdapter(this.canvas,
|
|
147864
|
+
this._supersplat = new SupersplatAdapter(this.canvas,
|
|
147865
|
+
// Disable navigation cube in preview mode
|
|
147866
|
+
this.previewMode ? null : this._navigationCubeConfig, emitEvent);
|
|
147786
147867
|
this._supersplatReady = this._supersplat.init();
|
|
147787
147868
|
this._supersplatReady
|
|
147788
147869
|
?.then(() => {
|
|
147789
|
-
|
|
147870
|
+
// In preview mode, enable zoom only (disable orbit and pan)
|
|
147871
|
+
if (this.previewMode && this._supersplat) {
|
|
147872
|
+
this._supersplat.setCameraInputControls?.({ orbit: false, pan: false, zoom: true });
|
|
147873
|
+
}
|
|
147874
|
+
// Only set up fly camera if not in preview mode
|
|
147875
|
+
if (!this.previewMode) {
|
|
147876
|
+
this._setupFlyCameraForSupersplat();
|
|
147877
|
+
}
|
|
147790
147878
|
})
|
|
147791
147879
|
.catch(error => {
|
|
147792
147880
|
console.error('SplatViewerCore.init: Failed to set up fly camera for supersplat path', error);
|
|
@@ -147825,7 +147913,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
147825
147913
|
// SuperSplat's PCApp omits ScriptComponentSystem, so `addComponent('script')`
|
|
147826
147914
|
// will not produce `camera.script.create()`. We keep the attempt (in case
|
|
147827
147915
|
// the underlying app changes), but also support a controller-based fallback.
|
|
147828
|
-
if (cameraAny &&
|
|
147916
|
+
if (cameraAny &&
|
|
147917
|
+
!cameraAny.script &&
|
|
147918
|
+
typeof cameraAny.addComponent === 'function') {
|
|
147829
147919
|
try {
|
|
147830
147920
|
cameraAny.addComponent('script');
|
|
147831
147921
|
}
|
|
@@ -147851,7 +147941,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
147851
147941
|
// Prefer script-based fly when available; fallback to controller otherwise.
|
|
147852
147942
|
const canCreateScript = typeof cameraAny?.script?.create === 'function';
|
|
147853
147943
|
if (canCreateScript) {
|
|
147854
|
-
const created = cameraAny.script.create('flyCamera', {
|
|
147944
|
+
const created = cameraAny.script.create('flyCamera', {
|
|
147945
|
+
attributes: flyAttributes,
|
|
147946
|
+
});
|
|
147855
147947
|
this._fly = created;
|
|
147856
147948
|
if (this._fly) {
|
|
147857
147949
|
;
|
|
@@ -149715,6 +149807,11 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
149715
149807
|
// Camera Mode / Fly Camera API
|
|
149716
149808
|
// ==========================================
|
|
149717
149809
|
setCameraMode(mode) {
|
|
149810
|
+
// Prevent camera mode changes in preview mode
|
|
149811
|
+
if (this.previewMode) {
|
|
149812
|
+
console.warn('SplatViewerCore.setCameraMode: Camera controls are disabled in preview mode');
|
|
149813
|
+
return;
|
|
149814
|
+
}
|
|
149718
149815
|
// supersplat-core path: manage mode switching explicitly (camera entity is updated by supersplat-core each frame)
|
|
149719
149816
|
if (this._supersplat) {
|
|
149720
149817
|
const prev = this._cameraMode;
|
|
@@ -149744,7 +149841,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
149744
149841
|
try {
|
|
149745
149842
|
const pos = this.entities.camera?.getPosition?.();
|
|
149746
149843
|
if (pos) {
|
|
149747
|
-
const posVec = pos.clone
|
|
149844
|
+
const posVec = pos.clone
|
|
149845
|
+
? pos.clone()
|
|
149846
|
+
: new Vec3(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
149748
149847
|
this.entities.camera?.setPosition?.(posVec);
|
|
149749
149848
|
}
|
|
149750
149849
|
const euler = this.entities.camera?.getEulerAngles?.();
|
|
@@ -149967,8 +150066,8 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
149967
150066
|
panSensitivity: 1.0,
|
|
149968
150067
|
zoomSensitivity: 0.1,
|
|
149969
150068
|
};
|
|
149970
|
-
// Add navigation cube configuration if available
|
|
149971
|
-
if (this._navigationCubeConfig) {
|
|
150069
|
+
// Add navigation cube configuration if available (but not in preview mode)
|
|
150070
|
+
if (this._navigationCubeConfig && !this.previewMode) {
|
|
149972
150071
|
orbitAttributes.enableNavigationCube =
|
|
149973
150072
|
this._navigationCubeConfig.enabled || false;
|
|
149974
150073
|
this.entities.camera._navigationCubeConfig =
|
|
@@ -149983,48 +150082,58 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
149983
150082
|
detail: { type: interactionType },
|
|
149984
150083
|
});
|
|
149985
150084
|
};
|
|
150085
|
+
// In preview mode, enable zoom only (disable orbit and pan)
|
|
150086
|
+
if (this.previewMode && this._orbit) {
|
|
150087
|
+
const orbitAny = this._orbit;
|
|
150088
|
+
if (typeof orbitAny.setInputControls === 'function') {
|
|
150089
|
+
// Enable zoom, disable orbit and pan
|
|
150090
|
+
orbitAny.setInputControls({ orbit: false, pan: false, zoom: true });
|
|
150091
|
+
}
|
|
150092
|
+
}
|
|
149986
150093
|
this.entities.camera.setPosition(0, 0, 10);
|
|
149987
150094
|
this.entities.camera.lookAt(Vec3.ZERO);
|
|
149988
150095
|
// ==============================
|
|
149989
|
-
// Setup fly camera (disabled by default)
|
|
150096
|
+
// Setup fly camera (disabled by default, skipped in preview mode)
|
|
149990
150097
|
// ==============================
|
|
149991
|
-
|
|
149992
|
-
|
|
149993
|
-
|
|
149994
|
-
|
|
149995
|
-
|
|
149996
|
-
|
|
149997
|
-
|
|
149998
|
-
|
|
149999
|
-
|
|
150000
|
-
|
|
150001
|
-
|
|
150002
|
-
|
|
150003
|
-
|
|
150004
|
-
|
|
150005
|
-
|
|
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 });
|
|
150098
|
+
if (!this.previewMode) {
|
|
150099
|
+
try {
|
|
150100
|
+
registerFlyCameraScript();
|
|
150101
|
+
// Ensure script component exists (created above)
|
|
150102
|
+
const flyAttributes = {
|
|
150103
|
+
moveSpeed: DEFAULT_FLY_CAMERA_CONFIG.moveSpeed,
|
|
150104
|
+
fastSpeedMultiplier: DEFAULT_FLY_CAMERA_CONFIG.fastSpeedMultiplier,
|
|
150105
|
+
slowSpeedMultiplier: DEFAULT_FLY_CAMERA_CONFIG.slowSpeedMultiplier,
|
|
150106
|
+
lookSensitivity: DEFAULT_FLY_CAMERA_CONFIG.lookSensitivity,
|
|
150107
|
+
invertY: DEFAULT_FLY_CAMERA_CONFIG.invertY,
|
|
150108
|
+
keyBindings: DEFAULT_FLY_CAMERA_CONFIG.keyBindings,
|
|
150109
|
+
smoothing: DEFAULT_FLY_CAMERA_CONFIG.smoothing,
|
|
150110
|
+
friction: DEFAULT_FLY_CAMERA_CONFIG.friction,
|
|
150111
|
+
enableCollision: DEFAULT_FLY_CAMERA_CONFIG.enableCollision,
|
|
150112
|
+
minHeight: DEFAULT_FLY_CAMERA_CONFIG.minHeight,
|
|
150113
|
+
maxHeight: DEFAULT_FLY_CAMERA_CONFIG.maxHeight,
|
|
150015
150114
|
};
|
|
150115
|
+
this._fly = this.entities.camera.script.create('flyCamera', {
|
|
150116
|
+
attributes: flyAttributes,
|
|
150117
|
+
});
|
|
150118
|
+
// Wire event emission to core
|
|
150119
|
+
if (this._fly) {
|
|
150120
|
+
;
|
|
150121
|
+
this._fly.emitFlyEvent = (type, detail) => {
|
|
150122
|
+
this.emit({ type: type, detail });
|
|
150123
|
+
};
|
|
150124
|
+
}
|
|
150125
|
+
// Deactivate fly by default; orbit is the initial mode
|
|
150126
|
+
if (this._fly?.deactivate) {
|
|
150127
|
+
this._fly.deactivate();
|
|
150128
|
+
}
|
|
150129
|
+
// Initialize camera mode manager
|
|
150130
|
+
this._cameraModeManager = new CameraModeManager(this.app, this.entities.camera, this._orbit, this._fly, (eventType, detail) => {
|
|
150131
|
+
this.emit({ type: eventType, detail });
|
|
150132
|
+
}, 'orbit');
|
|
150016
150133
|
}
|
|
150017
|
-
|
|
150018
|
-
|
|
150019
|
-
this._fly.deactivate();
|
|
150134
|
+
catch (e) {
|
|
150135
|
+
console.warn('Failed to set up fly camera', e);
|
|
150020
150136
|
}
|
|
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
150137
|
}
|
|
150029
150138
|
}
|
|
150030
150139
|
_setupStats() {
|
|
@@ -150269,6 +150378,7 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
150269
150378
|
'enable-stats',
|
|
150270
150379
|
'auto-focus',
|
|
150271
150380
|
'max-splats',
|
|
150381
|
+
'preview-mode',
|
|
150272
150382
|
'camera-position',
|
|
150273
150383
|
'camera-target',
|
|
150274
150384
|
'orbit-sensitivity',
|
|
@@ -150299,6 +150409,9 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
150299
150409
|
get autoFocus() {
|
|
150300
150410
|
return this.hasAttribute('auto-focus');
|
|
150301
150411
|
}
|
|
150412
|
+
get previewMode() {
|
|
150413
|
+
return this.hasAttribute('preview-mode');
|
|
150414
|
+
}
|
|
150302
150415
|
get maxSplats() {
|
|
150303
150416
|
return this.getAttribute('max-splats');
|
|
150304
150417
|
}
|
|
@@ -150376,6 +150489,14 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
150376
150489
|
this.removeAttribute('auto-focus');
|
|
150377
150490
|
}
|
|
150378
150491
|
}
|
|
150492
|
+
set previewMode(value) {
|
|
150493
|
+
if (value) {
|
|
150494
|
+
this.setAttribute('preview-mode', '');
|
|
150495
|
+
}
|
|
150496
|
+
else {
|
|
150497
|
+
this.removeAttribute('preview-mode');
|
|
150498
|
+
}
|
|
150499
|
+
}
|
|
150379
150500
|
set maxSplats(value) {
|
|
150380
150501
|
if (value === null) {
|
|
150381
150502
|
this.removeAttribute('max-splats');
|
|
@@ -150557,6 +150678,7 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
150557
150678
|
return value.length > 0;
|
|
150558
150679
|
case 'enable-stats':
|
|
150559
150680
|
case 'auto-focus':
|
|
150681
|
+
case 'preview-mode':
|
|
150560
150682
|
case 'enable-navigation-cube':
|
|
150561
150683
|
// Boolean attributes - any value is valid
|
|
150562
150684
|
return true;
|
|
@@ -151503,7 +151625,7 @@ bool initCenter(SplatSource source, vec3 modelCenter, out SplatCenter center) {
|
|
|
151503
151625
|
if (!this._core) {
|
|
151504
151626
|
throw new Error('SplatViewerElement: Core not initialized. Call connectedCallback first.');
|
|
151505
151627
|
}
|
|
151506
|
-
return this._core.selectSplatsInSphere(center, radius, modelId, addToSelection);
|
|
151628
|
+
return this._core.selectSplatsInSphere(new Vec3(center.x, center.y, center.z), radius, modelId, addToSelection);
|
|
151507
151629
|
}
|
|
151508
151630
|
clearSplatSelection() {
|
|
151509
151631
|
if (!this._core) {
|