@babylonjs/loaders 9.19.1 → 9.20.1
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/SPLAT/gaussianSplattingStream.d.ts +170 -1
- package/SPLAT/gaussianSplattingStream.js +516 -40
- package/SPLAT/gaussianSplattingStream.js.map +1 -1
- package/SPLAT/gaussianSplattingWorkBuffer.d.ts +163 -4
- package/SPLAT/gaussianSplattingWorkBuffer.js +683 -35
- package/SPLAT/gaussianSplattingWorkBuffer.js.map +1 -1
- package/SPLAT/gaussianSplattingWorkBufferShaders.d.ts +70 -2
- package/SPLAT/gaussianSplattingWorkBufferShaders.js +465 -4
- package/SPLAT/gaussianSplattingWorkBufferShaders.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +16 -1
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +232 -25
- package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +52 -2
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +108 -7
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.d.ts +37 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js +69 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.d.ts +44 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.js +51 -0
- package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js +143 -12
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +6 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +4 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_visibility.pure.js +11 -0
- package/glTF/2.0/Extensions/KHR_node_visibility.pure.js.map +1 -1
- package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.d.ts +126 -0
- package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.js +251 -0
- package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.js.map +1 -0
- package/glTF/2.0/Extensions/compositePathToObjectConverter.d.ts +51 -0
- package/glTF/2.0/Extensions/compositePathToObjectConverter.js +51 -0
- package/glTF/2.0/Extensions/compositePathToObjectConverter.js.map +1 -0
- package/glTF/2.0/Extensions/gltfPathToObjectConverter.js +69 -7
- package/glTF/2.0/Extensions/gltfPathToObjectConverter.js.map +1 -1
- package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.d.ts +41 -0
- package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.js +108 -0
- package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.js.map +1 -0
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.d.ts +28 -0
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js +71 -0
- package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js.map +1 -0
- package/glTF/2.0/Extensions/objectModelMapping.d.ts +118 -30
- package/glTF/2.0/Extensions/objectModelMapping.js +472 -70
- package/glTF/2.0/Extensions/objectModelMapping.js.map +1 -1
- package/glTF/2.0/Extensions/transmissionHelper.js +4 -0
- package/glTF/2.0/Extensions/transmissionHelper.js.map +1 -1
- package/glTF/2.0/glTFLoader.pure.js +2 -1
- package/glTF/2.0/glTFLoader.pure.js.map +1 -1
- package/package.json +3 -3
|
@@ -252,6 +252,300 @@ fn main(input : FragmentInputs) -> FragmentOutputs {
|
|
|
252
252
|
fragmentOutputs.fragData3 = vec4<f32>(colRgb, colA);
|
|
253
253
|
}
|
|
254
254
|
`;
|
|
255
|
+
/**
|
|
256
|
+
* Shader name for the rotation/scale decode pass (the three half-float textures voxel-IBL shadowing consumes).
|
|
257
|
+
*/
|
|
258
|
+
export const GaussianSplattingWorkBufferRotationDecodeShaderName = "gsSogRotDecodeToWorkBuffer";
|
|
259
|
+
/**
|
|
260
|
+
* Rotation/scale decode fragment shader (GLSL/WebGL2). Reconstructs each splat's rotation matrix R and scale and
|
|
261
|
+
* writes the three half-float textures the voxel shader samples (rotationsATexture/B/Scale). The layout lets the
|
|
262
|
+
* voxel shader reconstruct the same R and scale, so streamed splats get the same ellipsoid the draw path renders:
|
|
263
|
+
* rotA = (R col0.xyz, R col1.x)
|
|
264
|
+
* rotB = (R col1.yz, R col2.xy)
|
|
265
|
+
* rotScale = (R col2.z, 2*scale.x, 2*scale.y, 2*scale.z)
|
|
266
|
+
*/
|
|
267
|
+
export const GaussianSplattingWorkBufferRotationDecodeFragmentShaderGLSL = `precision highp float;
|
|
268
|
+
precision highp int;
|
|
269
|
+
|
|
270
|
+
uniform sampler2D sogScalesTex;
|
|
271
|
+
uniform sampler2D sogQuatsTex;
|
|
272
|
+
uniform sampler2D sogCodebookTex;
|
|
273
|
+
|
|
274
|
+
uniform vec3 sogScalesMin;
|
|
275
|
+
uniform vec3 sogScalesMax;
|
|
276
|
+
uniform int uVersion;
|
|
277
|
+
uniform int uOffset;
|
|
278
|
+
uniform int uCount;
|
|
279
|
+
uniform int uDestWidth;
|
|
280
|
+
uniform int uSrcWidth;
|
|
281
|
+
|
|
282
|
+
layout(location = 0) out vec4 glFragData[3];
|
|
283
|
+
|
|
284
|
+
void main() {
|
|
285
|
+
ivec2 p = ivec2(gl_FragCoord.xy);
|
|
286
|
+
int global = p.y * uDestWidth + p.x;
|
|
287
|
+
if (global < uOffset || global >= uOffset + uCount) {
|
|
288
|
+
discard;
|
|
289
|
+
}
|
|
290
|
+
int k = global - uOffset;
|
|
291
|
+
ivec2 src = ivec2(k - (k / uSrcWidth) * uSrcWidth, k / uSrcWidth);
|
|
292
|
+
|
|
293
|
+
vec3 sRaw = texelFetch(sogScalesTex, src, 0).xyz;
|
|
294
|
+
vec4 qRaw = texelFetch(sogQuatsTex, src, 0);
|
|
295
|
+
|
|
296
|
+
vec3 splatScale;
|
|
297
|
+
if (uVersion == 2) {
|
|
298
|
+
vec3 sIdx = floor(sRaw * 255.0 + 0.5);
|
|
299
|
+
splatScale.x = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.x), 0), 0).r);
|
|
300
|
+
splatScale.y = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.y), 0), 0).r);
|
|
301
|
+
splatScale.z = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.z), 0), 0).r);
|
|
302
|
+
} else {
|
|
303
|
+
splatScale = exp(mix(sogScalesMin, sogScalesMax, sRaw));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const float invSqrt2 = 0.70710678118;
|
|
307
|
+
vec3 qabc = (qRaw.xyz - vec3(0.5)) * 2.0 * invSqrt2;
|
|
308
|
+
int qMode = int(qRaw.w * 255.0 + 0.5) - 252;
|
|
309
|
+
float qd = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));
|
|
310
|
+
vec4 quat;
|
|
311
|
+
if (qMode == 0) {
|
|
312
|
+
quat = vec4(qd, qabc.x, qabc.y, qabc.z);
|
|
313
|
+
} else if (qMode == 1) {
|
|
314
|
+
quat = vec4(qabc.x, qd, qabc.y, qabc.z);
|
|
315
|
+
} else if (qMode == 2) {
|
|
316
|
+
quat = vec4(qabc.x, qabc.y, qd, qabc.z);
|
|
317
|
+
} else {
|
|
318
|
+
quat = vec4(qabc.x, qabc.y, qabc.z, qd);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
float qw = quat.x, qx = quat.y, qy = quat.z, qz = quat.w;
|
|
322
|
+
mat3 R = mat3(
|
|
323
|
+
1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),
|
|
324
|
+
2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),
|
|
325
|
+
2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
glFragData[0] = vec4(R[0], R[1].x);
|
|
329
|
+
glFragData[1] = vec4(R[1].y, R[1].z, R[2].x, R[2].y);
|
|
330
|
+
glFragData[2] = vec4(R[2].z, 2.0 * splatScale.x, 2.0 * splatScale.y, 2.0 * splatScale.z);
|
|
331
|
+
}
|
|
332
|
+
`;
|
|
333
|
+
/**
|
|
334
|
+
* Rotation/scale decode fragment shader (WGSL/WebGPU) — same decode as the GLSL variant, writing 3 half-float MRT
|
|
335
|
+
* attachments.
|
|
336
|
+
*/
|
|
337
|
+
export const GaussianSplattingWorkBufferRotationDecodeFragmentShaderWGSL = `
|
|
338
|
+
var sogScalesTexSampler : sampler;
|
|
339
|
+
var sogScalesTex : texture_2d<f32>;
|
|
340
|
+
var sogQuatsTexSampler : sampler;
|
|
341
|
+
var sogQuatsTex : texture_2d<f32>;
|
|
342
|
+
var sogCodebookTexSampler : sampler;
|
|
343
|
+
var sogCodebookTex : texture_2d<f32>;
|
|
344
|
+
|
|
345
|
+
uniform sogScalesMin : vec3<f32>;
|
|
346
|
+
uniform sogScalesMax : vec3<f32>;
|
|
347
|
+
uniform uVersion : i32;
|
|
348
|
+
uniform uOffset : i32;
|
|
349
|
+
uniform uCount : i32;
|
|
350
|
+
uniform uDestWidth : i32;
|
|
351
|
+
uniform uSrcWidth : i32;
|
|
352
|
+
|
|
353
|
+
@fragment
|
|
354
|
+
fn main(input : FragmentInputs) -> FragmentOutputs {
|
|
355
|
+
let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));
|
|
356
|
+
let global : i32 = p.y * uniforms.uDestWidth + p.x;
|
|
357
|
+
if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {
|
|
358
|
+
discard;
|
|
359
|
+
}
|
|
360
|
+
let k : i32 = global - uniforms.uOffset;
|
|
361
|
+
let src : vec2<i32> = vec2<i32>(k - (k / uniforms.uSrcWidth) * uniforms.uSrcWidth, k / uniforms.uSrcWidth);
|
|
362
|
+
|
|
363
|
+
let sRaw : vec3<f32> = textureLoad(sogScalesTex, src, 0).xyz;
|
|
364
|
+
let qRaw : vec4<f32> = textureLoad(sogQuatsTex, src, 0);
|
|
365
|
+
|
|
366
|
+
var splatScale : vec3<f32>;
|
|
367
|
+
if (uniforms.uVersion == 2) {
|
|
368
|
+
let sIdx : vec3<f32> = floor(sRaw * 255.0 + 0.5);
|
|
369
|
+
splatScale.x = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.x), 0), 0).r);
|
|
370
|
+
splatScale.y = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.y), 0), 0).r);
|
|
371
|
+
splatScale.z = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.z), 0), 0).r);
|
|
372
|
+
} else {
|
|
373
|
+
splatScale = exp(mix(uniforms.sogScalesMin, uniforms.sogScalesMax, sRaw));
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
let invSqrt2 : f32 = 0.70710678118;
|
|
377
|
+
let qabc : vec3<f32> = (qRaw.xyz - vec3<f32>(0.5)) * 2.0 * invSqrt2;
|
|
378
|
+
let qMode : i32 = i32(qRaw.w * 255.0 + 0.5) - 252;
|
|
379
|
+
let qd : f32 = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));
|
|
380
|
+
var quat : vec4<f32>;
|
|
381
|
+
if (qMode == 0) {
|
|
382
|
+
quat = vec4<f32>(qd, qabc.x, qabc.y, qabc.z);
|
|
383
|
+
} else if (qMode == 1) {
|
|
384
|
+
quat = vec4<f32>(qabc.x, qd, qabc.y, qabc.z);
|
|
385
|
+
} else if (qMode == 2) {
|
|
386
|
+
quat = vec4<f32>(qabc.x, qabc.y, qd, qabc.z);
|
|
387
|
+
} else {
|
|
388
|
+
quat = vec4<f32>(qabc.x, qabc.y, qabc.z, qd);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
let qw : f32 = quat.x;
|
|
392
|
+
let qx : f32 = quat.y;
|
|
393
|
+
let qy : f32 = quat.z;
|
|
394
|
+
let qz : f32 = quat.w;
|
|
395
|
+
let R : mat3x3<f32> = mat3x3<f32>(
|
|
396
|
+
1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),
|
|
397
|
+
2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),
|
|
398
|
+
2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
fragmentOutputs.fragData0 = vec4<f32>(R[0], R[1].x);
|
|
402
|
+
fragmentOutputs.fragData1 = vec4<f32>(R[1].y, R[1].z, R[2].x, R[2].y);
|
|
403
|
+
fragmentOutputs.fragData2 = vec4<f32>(R[2].z, 2.0 * splatScale.x, 2.0 * splatScale.y, 2.0 * splatScale.z);
|
|
404
|
+
}
|
|
405
|
+
`;
|
|
406
|
+
/**
|
|
407
|
+
* Shader name for the SOG higher-order SH decode pass (bakes one packed-u32 SH texture per pass).
|
|
408
|
+
*/
|
|
409
|
+
export const GaussianSplattingWorkBufferShDecodeShaderName = "gsSogShDecodeToWorkBuffer";
|
|
410
|
+
/**
|
|
411
|
+
* SH decode fragment shader (GLSL/WebGL2). Decodes one SOG file's higher-order spherical-harmonics into one
|
|
412
|
+
* packed-u32 SH texture at the region offset, in the layout the draw path's `computeSHWeighted`/`decompose`
|
|
413
|
+
* expects (16 SH scalar-bytes per RGBA-u32 texel, little-endian; one texel per splat). Run once per SH texture
|
|
414
|
+
* (`uShTextureIndex` selects the 16 scalars written this pass). Coefficients this file lacks are written neutral
|
|
415
|
+
* (128 == 0 after `decompose`), so a lower-band file mixes correctly with higher-band ones.
|
|
416
|
+
*/
|
|
417
|
+
export const GaussianSplattingWorkBufferShDecodeFragmentShaderGLSL = `precision highp float;
|
|
418
|
+
precision highp int;
|
|
419
|
+
|
|
420
|
+
uniform sampler2D sogShLabelsTex;
|
|
421
|
+
uniform sampler2D sogShCentroidsTex;
|
|
422
|
+
uniform sampler2D sogCodebookTex;
|
|
423
|
+
uniform float sogShnMin;
|
|
424
|
+
uniform float sogShnMax;
|
|
425
|
+
uniform int uVersion;
|
|
426
|
+
uniform int uOffset;
|
|
427
|
+
uniform int uCount;
|
|
428
|
+
uniform int uDestWidth;
|
|
429
|
+
uniform int uSrcWidth;
|
|
430
|
+
uniform int uCoeffs;
|
|
431
|
+
uniform int uShTextureIndex;
|
|
432
|
+
|
|
433
|
+
layout(location = 0) out uvec4 outSh;
|
|
434
|
+
|
|
435
|
+
void main() {
|
|
436
|
+
ivec2 p = ivec2(gl_FragCoord.xy);
|
|
437
|
+
int global = p.y * uDestWidth + p.x;
|
|
438
|
+
if (global < uOffset || global >= uOffset + uCount) {
|
|
439
|
+
discard;
|
|
440
|
+
}
|
|
441
|
+
int kLocal = global - uOffset;
|
|
442
|
+
|
|
443
|
+
// 16-bit label for this source splat (LSB in r, MSB in g), indexed over the labels texture's own width.
|
|
444
|
+
ivec2 lsz = textureSize(sogShLabelsTex, 0);
|
|
445
|
+
ivec2 lsrc = ivec2(kLocal - (kLocal / lsz.x) * lsz.x, kLocal / lsz.x);
|
|
446
|
+
vec4 labelRaw = texelFetch(sogShLabelsTex, lsrc, 0);
|
|
447
|
+
int n = int(labelRaw.r * 255.0 + 0.5) + int(labelRaw.g * 255.0 + 0.5) * 256;
|
|
448
|
+
int u = (n - (n / 64) * 64) * uCoeffs;
|
|
449
|
+
int v = n / 64;
|
|
450
|
+
|
|
451
|
+
uint packed0 = 0u;
|
|
452
|
+
uint packed1 = 0u;
|
|
453
|
+
uint packed2 = 0u;
|
|
454
|
+
uint packed3 = 0u;
|
|
455
|
+
|
|
456
|
+
for (int b = 0; b < 16; b++) {
|
|
457
|
+
int s = uShTextureIndex * 16 + b; // flat SH scalar index
|
|
458
|
+
int kc = s / 3; // higher-order coefficient (0-based)
|
|
459
|
+
int j = s - kc * 3; // channel (0=r,1=g,2=b)
|
|
460
|
+
float byteVal = 128.0; // neutral (decompose(128) ~= 0)
|
|
461
|
+
if (kc < uCoeffs) {
|
|
462
|
+
vec4 centroidRaw = texelFetch(sogShCentroidsTex, ivec2(u + kc, v), 0);
|
|
463
|
+
float ch = (j == 0) ? centroidRaw.r : ((j == 1) ? centroidRaw.g : centroidRaw.b);
|
|
464
|
+
float coeff;
|
|
465
|
+
if (uVersion == 2) {
|
|
466
|
+
int cidx = int(ch * 255.0 + 0.5);
|
|
467
|
+
coeff = texelFetch(sogCodebookTex, ivec2(512 + cidx, 0), 0).r;
|
|
468
|
+
} else {
|
|
469
|
+
coeff = mix(sogShnMin, sogShnMax, ch);
|
|
470
|
+
}
|
|
471
|
+
byteVal = clamp(coeff * 127.5 + 127.5, 0.0, 255.0);
|
|
472
|
+
}
|
|
473
|
+
uint bv = uint(byteVal + 0.5);
|
|
474
|
+
int comp = b / 4;
|
|
475
|
+
uint contrib = bv << uint((b - comp * 4) * 8);
|
|
476
|
+
if (comp == 0) { packed0 |= contrib; }
|
|
477
|
+
else if (comp == 1) { packed1 |= contrib; }
|
|
478
|
+
else if (comp == 2) { packed2 |= contrib; }
|
|
479
|
+
else { packed3 |= contrib; }
|
|
480
|
+
}
|
|
481
|
+
outSh = uvec4(packed0, packed1, packed2, packed3);
|
|
482
|
+
}
|
|
483
|
+
`;
|
|
484
|
+
/**
|
|
485
|
+
* SH decode fragment shader (WGSL/WebGPU) — same as the GLSL variant. The integer output (`vec4<u32>` fragData)
|
|
486
|
+
* requires the WGSL processor's integer-fragData support.
|
|
487
|
+
*/
|
|
488
|
+
export const GaussianSplattingWorkBufferShDecodeFragmentShaderWGSL = `
|
|
489
|
+
var sogShLabelsTexSampler : sampler;
|
|
490
|
+
var sogShLabelsTex : texture_2d<f32>;
|
|
491
|
+
var sogShCentroidsTexSampler : sampler;
|
|
492
|
+
var sogShCentroidsTex : texture_2d<f32>;
|
|
493
|
+
var sogCodebookTexSampler : sampler;
|
|
494
|
+
var sogCodebookTex : texture_2d<f32>;
|
|
495
|
+
|
|
496
|
+
uniform sogShnMin : f32;
|
|
497
|
+
uniform sogShnMax : f32;
|
|
498
|
+
uniform uVersion : i32;
|
|
499
|
+
uniform uOffset : i32;
|
|
500
|
+
uniform uCount : i32;
|
|
501
|
+
uniform uDestWidth : i32;
|
|
502
|
+
uniform uSrcWidth : i32;
|
|
503
|
+
uniform uCoeffs : i32;
|
|
504
|
+
uniform uShTextureIndex : i32;
|
|
505
|
+
|
|
506
|
+
@fragment
|
|
507
|
+
fn main(input : FragmentInputs) -> FragmentOutputs {
|
|
508
|
+
let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));
|
|
509
|
+
let global : i32 = p.y * uniforms.uDestWidth + p.x;
|
|
510
|
+
if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {
|
|
511
|
+
discard;
|
|
512
|
+
}
|
|
513
|
+
let kLocal : i32 = global - uniforms.uOffset;
|
|
514
|
+
|
|
515
|
+
let lsz : vec2<i32> = vec2<i32>(textureDimensions(sogShLabelsTex, 0));
|
|
516
|
+
let lsrc : vec2<i32> = vec2<i32>(kLocal - (kLocal / lsz.x) * lsz.x, kLocal / lsz.x);
|
|
517
|
+
let labelRaw : vec4<f32> = textureLoad(sogShLabelsTex, lsrc, 0);
|
|
518
|
+
let n : i32 = i32(labelRaw.r * 255.0 + 0.5) + i32(labelRaw.g * 255.0 + 0.5) * 256;
|
|
519
|
+
let u : i32 = (n - (n / 64) * 64) * uniforms.uCoeffs;
|
|
520
|
+
let v : i32 = n / 64;
|
|
521
|
+
|
|
522
|
+
var packed : array<u32, 4> = array<u32, 4>(0u, 0u, 0u, 0u);
|
|
523
|
+
|
|
524
|
+
for (var b : i32 = 0; b < 16; b = b + 1) {
|
|
525
|
+
let s : i32 = uniforms.uShTextureIndex * 16 + b;
|
|
526
|
+
let kc : i32 = s / 3;
|
|
527
|
+
let j : i32 = s - kc * 3;
|
|
528
|
+
var byteVal : f32 = 128.0;
|
|
529
|
+
if (kc < uniforms.uCoeffs) {
|
|
530
|
+
let centroidRaw : vec4<f32> = textureLoad(sogShCentroidsTex, vec2<i32>(u + kc, v), 0);
|
|
531
|
+
var ch : f32 = centroidRaw.b;
|
|
532
|
+
if (j == 0) { ch = centroidRaw.r; } else if (j == 1) { ch = centroidRaw.g; }
|
|
533
|
+
var coeff : f32;
|
|
534
|
+
if (uniforms.uVersion == 2) {
|
|
535
|
+
let cidx : i32 = i32(ch * 255.0 + 0.5);
|
|
536
|
+
coeff = textureLoad(sogCodebookTex, vec2<i32>(512 + cidx, 0), 0).r;
|
|
537
|
+
} else {
|
|
538
|
+
coeff = mix(uniforms.sogShnMin, uniforms.sogShnMax, ch);
|
|
539
|
+
}
|
|
540
|
+
byteVal = clamp(coeff * 127.5 + 127.5, 0.0, 255.0);
|
|
541
|
+
}
|
|
542
|
+
let bv : u32 = u32(byteVal + 0.5);
|
|
543
|
+
let comp : i32 = b / 4;
|
|
544
|
+
packed[comp] = packed[comp] | (bv << u32((b - comp * 4) * 8));
|
|
545
|
+
}
|
|
546
|
+
fragmentOutputs.fragData0 = vec4<u32>(packed[0], packed[1], packed[2], packed[3]);
|
|
547
|
+
}
|
|
548
|
+
`;
|
|
255
549
|
/**
|
|
256
550
|
* Shader name for the work-buffer relayout (defrag/compaction) copy pass.
|
|
257
551
|
*/
|
|
@@ -273,6 +567,11 @@ uniform sampler2D uSrc3;
|
|
|
273
567
|
uniform int uDstWidth;
|
|
274
568
|
uniform int uSrcWidth;
|
|
275
569
|
uniform int uUseMap;
|
|
570
|
+
// Region-scoped relayout (hosted compound atlas), both default 0 (standalone square path unchanged):
|
|
571
|
+
// uSrcBaseOffset — added to the map's (region-local) source index so pass 1 reads the correct GLOBAL atlas texel.
|
|
572
|
+
// uDstBaseRow — subtracted from the atlas destination row so pass 2's identity copy reads the region-local temp.
|
|
573
|
+
uniform int uSrcBaseOffset;
|
|
574
|
+
uniform int uDstBaseRow;
|
|
276
575
|
|
|
277
576
|
layout(location = 0) out vec4 glFragData[4];
|
|
278
577
|
|
|
@@ -284,9 +583,9 @@ void main() {
|
|
|
284
583
|
if (m < 0.0) {
|
|
285
584
|
discard;
|
|
286
585
|
}
|
|
287
|
-
srcIdx = int(m + 0.5);
|
|
586
|
+
srcIdx = uSrcBaseOffset + int(m + 0.5);
|
|
288
587
|
} else {
|
|
289
|
-
srcIdx = p.y * uDstWidth + p.x;
|
|
588
|
+
srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;
|
|
290
589
|
}
|
|
291
590
|
ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);
|
|
292
591
|
glFragData[0] = texelFetch(uSrc0, s, 0);
|
|
@@ -295,6 +594,165 @@ void main() {
|
|
|
295
594
|
glFragData[3] = texelFetch(uSrc3, s, 0);
|
|
296
595
|
}
|
|
297
596
|
`;
|
|
597
|
+
/**
|
|
598
|
+
* Shader name for the INTEGER (packed-u32 SH) relayout/backup copy pass. Same index/map/base math as the float
|
|
599
|
+
* relayout shader, but samples ONE integer SH source texture (`usampler2D`) and writes ONE integer attachment,
|
|
600
|
+
* so it moves one baked SH texture per pass (parallel to the four-out float copy).
|
|
601
|
+
*/
|
|
602
|
+
export const GaussianSplattingWorkBufferShCopyShaderName = "gsWorkBufferShCopy";
|
|
603
|
+
/**
|
|
604
|
+
* Integer SH relayout/backup copy fragment shader (GLSL/WebGL2). Copies one packed-u32 SH texture from a source
|
|
605
|
+
* layout to a destination layout, one output texel per draw. Map mode (`uUseMap == 1`) reads each destination
|
|
606
|
+
* texel's source splat index from `uMapTex` (R32F; negative = gap, discarded); identity mode copies texel-for-texel
|
|
607
|
+
* (region backup/restore). `uSrcBaseOffset`/`uDstBaseRow` scope the copy to a hosted region's atlas rows (default 0).
|
|
608
|
+
*/
|
|
609
|
+
export const GaussianSplattingWorkBufferShCopyFragmentShaderGLSL = `precision highp float;
|
|
610
|
+
precision highp int;
|
|
611
|
+
precision highp usampler2D;
|
|
612
|
+
|
|
613
|
+
uniform sampler2D uMapTex;
|
|
614
|
+
uniform usampler2D uSrcSh;
|
|
615
|
+
uniform int uDstWidth;
|
|
616
|
+
uniform int uSrcWidth;
|
|
617
|
+
uniform int uUseMap;
|
|
618
|
+
uniform int uSrcBaseOffset;
|
|
619
|
+
uniform int uDstBaseRow;
|
|
620
|
+
|
|
621
|
+
layout(location = 0) out uvec4 outSh;
|
|
622
|
+
|
|
623
|
+
void main() {
|
|
624
|
+
ivec2 p = ivec2(gl_FragCoord.xy);
|
|
625
|
+
int srcIdx;
|
|
626
|
+
if (uUseMap == 1) {
|
|
627
|
+
float m = texelFetch(uMapTex, p, 0).r;
|
|
628
|
+
if (m < 0.0) {
|
|
629
|
+
discard;
|
|
630
|
+
}
|
|
631
|
+
srcIdx = uSrcBaseOffset + int(m + 0.5);
|
|
632
|
+
} else {
|
|
633
|
+
srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;
|
|
634
|
+
}
|
|
635
|
+
ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);
|
|
636
|
+
outSh = texelFetch(uSrcSh, s, 0);
|
|
637
|
+
}
|
|
638
|
+
`;
|
|
639
|
+
/**
|
|
640
|
+
* Integer SH relayout/backup copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant. The integer output
|
|
641
|
+
* (`vec4<u32>` fragData) requires the WGSL processor's integer-fragData support.
|
|
642
|
+
*/
|
|
643
|
+
export const GaussianSplattingWorkBufferShCopyFragmentShaderWGSL = `
|
|
644
|
+
var uMapTexSampler : sampler;
|
|
645
|
+
var uMapTex : texture_2d<f32>;
|
|
646
|
+
// Integer source sampled via textureLoad only — NO paired sampler (a sampler on a Uint texture fails WebGPU
|
|
647
|
+
// validation: "None of the supported sample types (Uint)"). Mirrors the draw shader's shTexture0 declaration.
|
|
648
|
+
var uSrcSh : texture_2d<u32>;
|
|
649
|
+
|
|
650
|
+
uniform uDstWidth : i32;
|
|
651
|
+
uniform uSrcWidth : i32;
|
|
652
|
+
uniform uUseMap : i32;
|
|
653
|
+
uniform uSrcBaseOffset : i32;
|
|
654
|
+
uniform uDstBaseRow : i32;
|
|
655
|
+
|
|
656
|
+
@fragment
|
|
657
|
+
fn main(input : FragmentInputs) -> FragmentOutputs {
|
|
658
|
+
let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));
|
|
659
|
+
var srcIdx : i32;
|
|
660
|
+
if (uniforms.uUseMap == 1) {
|
|
661
|
+
let m : f32 = textureLoad(uMapTex, p, 0).r;
|
|
662
|
+
if (m < 0.0) {
|
|
663
|
+
discard;
|
|
664
|
+
}
|
|
665
|
+
srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);
|
|
666
|
+
} else {
|
|
667
|
+
srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;
|
|
668
|
+
}
|
|
669
|
+
let s : vec2<i32> = vec2<i32>(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);
|
|
670
|
+
// Wrap in an explicit vec4<u32> so the WGSL processor emits an integer fragData location (its detection keys
|
|
671
|
+
// off a literal vec4<u32>/vec4u in the assignment; a bare textureLoad(...) would default to vec4<f32>).
|
|
672
|
+
fragmentOutputs.fragData0 = vec4<u32>(textureLoad(uSrcSh, s, 0));
|
|
673
|
+
}
|
|
674
|
+
`;
|
|
675
|
+
/**
|
|
676
|
+
* Shader name for the rotation/scale relayout/backup copy pass. Same index/map/base math as the four-out float
|
|
677
|
+
* relayout shader, but moves the THREE half-float rotation/scale textures in one pass (their own separate atlas).
|
|
678
|
+
*/
|
|
679
|
+
export const GaussianSplattingWorkBufferRotCopyShaderName = "gsWorkBufferRotCopy";
|
|
680
|
+
/**
|
|
681
|
+
* Rotation/scale relayout/backup copy fragment shader (GLSL/WebGL2). Copies the three half-float rotation/scale
|
|
682
|
+
* textures from a source layout to a destination layout, one output texel per draw. Identical to the four-out
|
|
683
|
+
* float relayout shader but with three attachments (the rotation atlas has no fourth texture).
|
|
684
|
+
*/
|
|
685
|
+
export const GaussianSplattingWorkBufferRotCopyFragmentShaderGLSL = `precision highp float;
|
|
686
|
+
precision highp int;
|
|
687
|
+
|
|
688
|
+
uniform sampler2D uMapTex;
|
|
689
|
+
uniform sampler2D uSrc0;
|
|
690
|
+
uniform sampler2D uSrc1;
|
|
691
|
+
uniform sampler2D uSrc2;
|
|
692
|
+
uniform int uDstWidth;
|
|
693
|
+
uniform int uSrcWidth;
|
|
694
|
+
uniform int uUseMap;
|
|
695
|
+
uniform int uSrcBaseOffset;
|
|
696
|
+
uniform int uDstBaseRow;
|
|
697
|
+
|
|
698
|
+
layout(location = 0) out vec4 glFragData[3];
|
|
699
|
+
|
|
700
|
+
void main() {
|
|
701
|
+
ivec2 p = ivec2(gl_FragCoord.xy);
|
|
702
|
+
int srcIdx;
|
|
703
|
+
if (uUseMap == 1) {
|
|
704
|
+
float m = texelFetch(uMapTex, p, 0).r;
|
|
705
|
+
if (m < 0.0) {
|
|
706
|
+
discard;
|
|
707
|
+
}
|
|
708
|
+
srcIdx = uSrcBaseOffset + int(m + 0.5);
|
|
709
|
+
} else {
|
|
710
|
+
srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;
|
|
711
|
+
}
|
|
712
|
+
ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);
|
|
713
|
+
glFragData[0] = texelFetch(uSrc0, s, 0);
|
|
714
|
+
glFragData[1] = texelFetch(uSrc1, s, 0);
|
|
715
|
+
glFragData[2] = texelFetch(uSrc2, s, 0);
|
|
716
|
+
}
|
|
717
|
+
`;
|
|
718
|
+
/**
|
|
719
|
+
* Rotation/scale relayout/backup copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant, 3 attachments.
|
|
720
|
+
*/
|
|
721
|
+
export const GaussianSplattingWorkBufferRotCopyFragmentShaderWGSL = `
|
|
722
|
+
var uMapTexSampler : sampler;
|
|
723
|
+
var uMapTex : texture_2d<f32>;
|
|
724
|
+
var uSrc0Sampler : sampler;
|
|
725
|
+
var uSrc0 : texture_2d<f32>;
|
|
726
|
+
var uSrc1Sampler : sampler;
|
|
727
|
+
var uSrc1 : texture_2d<f32>;
|
|
728
|
+
var uSrc2Sampler : sampler;
|
|
729
|
+
var uSrc2 : texture_2d<f32>;
|
|
730
|
+
|
|
731
|
+
uniform uDstWidth : i32;
|
|
732
|
+
uniform uSrcWidth : i32;
|
|
733
|
+
uniform uUseMap : i32;
|
|
734
|
+
uniform uSrcBaseOffset : i32;
|
|
735
|
+
uniform uDstBaseRow : i32;
|
|
736
|
+
|
|
737
|
+
@fragment
|
|
738
|
+
fn main(input : FragmentInputs) -> FragmentOutputs {
|
|
739
|
+
let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));
|
|
740
|
+
var srcIdx : i32;
|
|
741
|
+
if (uniforms.uUseMap == 1) {
|
|
742
|
+
let m : f32 = textureLoad(uMapTex, p, 0).r;
|
|
743
|
+
if (m < 0.0) {
|
|
744
|
+
discard;
|
|
745
|
+
}
|
|
746
|
+
srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);
|
|
747
|
+
} else {
|
|
748
|
+
srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;
|
|
749
|
+
}
|
|
750
|
+
let s : vec2<i32> = vec2<i32>(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);
|
|
751
|
+
fragmentOutputs.fragData0 = textureLoad(uSrc0, s, 0);
|
|
752
|
+
fragmentOutputs.fragData1 = textureLoad(uSrc1, s, 0);
|
|
753
|
+
fragmentOutputs.fragData2 = textureLoad(uSrc2, s, 0);
|
|
754
|
+
}
|
|
755
|
+
`;
|
|
298
756
|
/**
|
|
299
757
|
* Relayout copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant.
|
|
300
758
|
*/
|
|
@@ -313,6 +771,9 @@ var uSrc3 : texture_2d<f32>;
|
|
|
313
771
|
uniform uDstWidth : i32;
|
|
314
772
|
uniform uSrcWidth : i32;
|
|
315
773
|
uniform uUseMap : i32;
|
|
774
|
+
// Region-scoped relayout (hosted compound atlas), both default 0 (standalone square path unchanged).
|
|
775
|
+
uniform uSrcBaseOffset : i32;
|
|
776
|
+
uniform uDstBaseRow : i32;
|
|
316
777
|
|
|
317
778
|
@fragment
|
|
318
779
|
fn main(input : FragmentInputs) -> FragmentOutputs {
|
|
@@ -323,9 +784,9 @@ fn main(input : FragmentInputs) -> FragmentOutputs {
|
|
|
323
784
|
if (m < 0.0) {
|
|
324
785
|
discard;
|
|
325
786
|
}
|
|
326
|
-
srcIdx = i32(m + 0.5);
|
|
787
|
+
srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);
|
|
327
788
|
} else {
|
|
328
|
-
srcIdx = p.y * uniforms.uDstWidth + p.x;
|
|
789
|
+
srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;
|
|
329
790
|
}
|
|
330
791
|
let s : vec2<i32> = vec2<i32>(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);
|
|
331
792
|
fragmentOutputs.fragData0 = textureLoad(uSrc0, s, 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gaussianSplattingWorkBufferShaders.js","sourceRoot":"","sources":["../../../../dev/loaders/src/SPLAT/gaussianSplattingWorkBufferShaders.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D;;GAEG;AACH,MAAM,CAAC,MAAM,qCAAqC,GAAG,yBAAyB,CAAC;AAE/E;;GAEG;AACH,MAAM,CAAC,MAAM,2CAA2C,GAAG;;;;;CAK1D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,6CAA6C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8G5D,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,2CAA2C,GAAG;;;;;;CAM1D,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,6CAA6C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4G5D,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,6CAA6C,GAAG,sBAAsB,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qDAAqD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCpE,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,qDAAqD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCpE,CAAC","sourcesContent":["/** This file must only contain pure code and pure imports */\r\n\r\n/**\r\n * Shared shader names for the SOG -> decoded work-buffer copy pass.\r\n */\r\nexport const GaussianSplattingWorkBufferShaderName = \"gsSogDecodeToWorkBuffer\";\r\n\r\n/**\r\n * Pass-through vertex shader (GLSL): the geometry is a fullscreen triangle already in NDC.\r\n */\r\nexport const GaussianSplattingWorkBufferVertexShaderGLSL = `precision highp float;\r\nattribute vec3 position;\r\nvoid main() {\r\n gl_Position = vec4(position.xy, 0.0, 1.0);\r\n}\r\n`;\r\n\r\n/**\r\n * Fragment shader (GLSL/WebGL2): decodes one SOG source file into the decoded GS work-buffer layout,\r\n * writing each splat into its allocated pixel. Mirrors the USE_SOG decode in ShadersInclude/gaussianSplatting.fx\r\n * but outputs the decoded MRT (center, covA, covB, color) consumed by the standard (non-SOG) draw path.\r\n *\r\n * MRT layout: 0 = center (x,y,z,1), 1 = covA (Sigma00,01,02,11), 2 = covB (Sigma12,22,0,0), 3 = color (rgba).\r\n */\r\nexport const GaussianSplattingWorkBufferFragmentShaderGLSL = `precision highp float;\r\nprecision highp int;\r\n\r\nuniform sampler2D sogMeansLTex;\r\nuniform sampler2D sogMeansUTex;\r\nuniform sampler2D sogScalesTex;\r\nuniform sampler2D sogQuatsTex;\r\nuniform sampler2D sogSh0Tex;\r\nuniform sampler2D sogCodebookTex;\r\n\r\nuniform vec3 sogMeansMin;\r\nuniform vec3 sogMeansMax;\r\nuniform vec3 sogScalesMin;\r\nuniform vec3 sogScalesMax;\r\nuniform vec4 sogSh0Min;\r\nuniform vec4 sogSh0Max;\r\nuniform int uVersion;\r\nuniform int uOffset;\r\nuniform int uCount;\r\nuniform int uDestWidth;\r\nuniform int uSrcWidth;\r\n\r\nlayout(location = 0) out vec4 glFragData[4];\r\n\r\nmat3 transposeM(mat3 m) {\r\n return mat3(m[0][0], m[1][0], m[2][0], m[0][1], m[1][1], m[2][1], m[0][2], m[1][2], m[2][2]);\r\n}\r\n\r\nvoid main() {\r\n ivec2 p = ivec2(gl_FragCoord.xy);\r\n int global = p.y * uDestWidth + p.x;\r\n if (global < uOffset || global >= uOffset + uCount) {\r\n discard;\r\n }\r\n int k = global - uOffset;\r\n ivec2 src = ivec2(k - (k / uSrcWidth) * uSrcWidth, k / uSrcWidth);\r\n\r\n vec3 mL = texelFetch(sogMeansLTex, src, 0).xyz;\r\n vec3 mU = texelFetch(sogMeansUTex, src, 0).xyz;\r\n vec3 sRaw = texelFetch(sogScalesTex, src, 0).xyz;\r\n vec4 qRaw = texelFetch(sogQuatsTex, src, 0);\r\n vec4 c0 = texelFetch(sogSh0Tex, src, 0);\r\n\r\n // Position: q16 = (u<<8)|l normalized; n = lerp(min,max,q16); pos = sign(n)*(exp(|n|)-1)\r\n vec3 q16 = (mU * 256.0 + mL) * (255.0 / 65535.0);\r\n vec3 nPos = mix(sogMeansMin, sogMeansMax, q16);\r\n vec3 center = sign(nPos) * (exp(abs(nPos)) - vec3(1.0));\r\n\r\n // Scale (v1: lerp+exp ; v2: codebook lookup)\r\n vec3 splatScale;\r\n if (uVersion == 2) {\r\n vec3 sIdx = floor(sRaw * 255.0 + 0.5);\r\n splatScale.x = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.x), 0), 0).r);\r\n splatScale.y = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.y), 0), 0).r);\r\n splatScale.z = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.z), 0), 0).r);\r\n } else {\r\n splatScale = exp(mix(sogScalesMin, sogScalesMax, sRaw));\r\n }\r\n\r\n // Quaternion (largest-omitted, mode in alpha as 252 + omitted-index)\r\n const float invSqrt2 = 0.70710678118;\r\n vec3 qabc = (qRaw.xyz - vec3(0.5)) * 2.0 * invSqrt2;\r\n int qMode = int(qRaw.w * 255.0 + 0.5) - 252;\r\n float qd = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\r\n vec4 quat;\r\n if (qMode == 0) {\r\n quat = vec4(qd, qabc.x, qabc.y, qabc.z);\r\n } else if (qMode == 1) {\r\n quat = vec4(qabc.x, qd, qabc.y, qabc.z);\r\n } else if (qMode == 2) {\r\n quat = vec4(qabc.x, qabc.y, qd, qabc.z);\r\n } else {\r\n quat = vec4(qabc.x, qabc.y, qabc.z, qd);\r\n }\r\n\r\n float qw = quat.x, qx = quat.y, qy = quat.z, qz = quat.w;\r\n mat3 R = mat3(\r\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\r\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\r\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\r\n );\r\n mat3 S2 = mat3(\r\n 4.0 * splatScale.x * splatScale.x, 0.0, 0.0,\r\n 0.0, 4.0 * splatScale.y * splatScale.y, 0.0,\r\n 0.0, 0.0, 4.0 * splatScale.z * splatScale.z\r\n );\r\n mat3 Sigma = R * S2 * transposeM(R);\r\n\r\n // Color (sh0)\r\n const float SH_C0 = 0.28209479177387814;\r\n vec3 colRgb;\r\n float colA;\r\n if (uVersion == 2) {\r\n vec3 c3;\r\n c3.x = texelFetch(sogCodebookTex, ivec2(256 + int(c0.x * 255.0 + 0.5), 0), 0).r;\r\n c3.y = texelFetch(sogCodebookTex, ivec2(256 + int(c0.y * 255.0 + 0.5), 0), 0).r;\r\n c3.z = texelFetch(sogCodebookTex, ivec2(256 + int(c0.z * 255.0 + 0.5), 0), 0).r;\r\n colRgb = vec3(0.5) + c3 * SH_C0;\r\n colA = c0.w;\r\n } else {\r\n vec4 cLerp = mix(sogSh0Min, sogSh0Max, c0);\r\n colRgb = vec3(0.5) + cLerp.xyz * SH_C0;\r\n colA = 1.0 / (1.0 + exp(-cLerp.w));\r\n }\r\n\r\n glFragData[0] = vec4(center, 1.0);\r\n glFragData[1] = vec4(Sigma[0][0], Sigma[0][1], Sigma[0][2], Sigma[1][1]);\r\n glFragData[2] = vec4(Sigma[1][2], Sigma[2][2], 0.0, 0.0);\r\n glFragData[3] = vec4(colRgb, colA);\r\n}\r\n`;\r\n\r\n/**\r\n * Pass-through vertex shader (WGSL).\r\n */\r\nexport const GaussianSplattingWorkBufferVertexShaderWGSL = `\r\nattribute position : vec3<f32>;\r\n@vertex\r\nfn main(input : VertexInputs) -> FragmentInputs {\r\n vertexOutputs.position = vec4<f32>(input.position.xy, 0.0, 1.0);\r\n}\r\n`;\r\n\r\n/**\r\n * Fragment shader (WGSL/WebGPU) — same decode as the GLSL variant, writing 4 MRT attachments.\r\n */\r\nexport const GaussianSplattingWorkBufferFragmentShaderWGSL = `\r\nvar sogMeansLTexSampler : sampler;\r\nvar sogMeansLTex : texture_2d<f32>;\r\nvar sogMeansUTexSampler : sampler;\r\nvar sogMeansUTex : texture_2d<f32>;\r\nvar sogScalesTexSampler : sampler;\r\nvar sogScalesTex : texture_2d<f32>;\r\nvar sogQuatsTexSampler : sampler;\r\nvar sogQuatsTex : texture_2d<f32>;\r\nvar sogSh0TexSampler : sampler;\r\nvar sogSh0Tex : texture_2d<f32>;\r\nvar sogCodebookTexSampler : sampler;\r\nvar sogCodebookTex : texture_2d<f32>;\r\n\r\nuniform sogMeansMin : vec3<f32>;\r\nuniform sogMeansMax : vec3<f32>;\r\nuniform sogScalesMin : vec3<f32>;\r\nuniform sogScalesMax : vec3<f32>;\r\nuniform sogSh0Min : vec4<f32>;\r\nuniform sogSh0Max : vec4<f32>;\r\nuniform uVersion : i32;\r\nuniform uOffset : i32;\r\nuniform uCount : i32;\r\nuniform uDestWidth : i32;\r\nuniform uSrcWidth : i32;\r\n\r\n@fragment\r\nfn main(input : FragmentInputs) -> FragmentOutputs {\r\n let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\r\n let global : i32 = p.y * uniforms.uDestWidth + p.x;\r\n if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {\r\n discard;\r\n }\r\n let k : i32 = global - uniforms.uOffset;\r\n let src : vec2<i32> = vec2<i32>(k - (k / uniforms.uSrcWidth) * uniforms.uSrcWidth, k / uniforms.uSrcWidth);\r\n\r\n let mL : vec3<f32> = textureLoad(sogMeansLTex, src, 0).xyz;\r\n let mU : vec3<f32> = textureLoad(sogMeansUTex, src, 0).xyz;\r\n let sRaw : vec3<f32> = textureLoad(sogScalesTex, src, 0).xyz;\r\n let qRaw : vec4<f32> = textureLoad(sogQuatsTex, src, 0);\r\n let c0 : vec4<f32> = textureLoad(sogSh0Tex, src, 0);\r\n\r\n let q16 : vec3<f32> = (mU * 256.0 + mL) * (255.0 / 65535.0);\r\n let nPos : vec3<f32> = mix(uniforms.sogMeansMin, uniforms.sogMeansMax, q16);\r\n let center : vec3<f32> = sign(nPos) * (exp(abs(nPos)) - vec3<f32>(1.0));\r\n\r\n var splatScale : vec3<f32>;\r\n if (uniforms.uVersion == 2) {\r\n let sIdx : vec3<f32> = floor(sRaw * 255.0 + 0.5);\r\n splatScale.x = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.x), 0), 0).r);\r\n splatScale.y = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.y), 0), 0).r);\r\n splatScale.z = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.z), 0), 0).r);\r\n } else {\r\n splatScale = exp(mix(uniforms.sogScalesMin, uniforms.sogScalesMax, sRaw));\r\n }\r\n\r\n let invSqrt2 : f32 = 0.70710678118;\r\n let qabc : vec3<f32> = (qRaw.xyz - vec3<f32>(0.5)) * 2.0 * invSqrt2;\r\n let qMode : i32 = i32(qRaw.w * 255.0 + 0.5) - 252;\r\n let qd : f32 = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\r\n var quat : vec4<f32>;\r\n if (qMode == 0) {\r\n quat = vec4<f32>(qd, qabc.x, qabc.y, qabc.z);\r\n } else if (qMode == 1) {\r\n quat = vec4<f32>(qabc.x, qd, qabc.y, qabc.z);\r\n } else if (qMode == 2) {\r\n quat = vec4<f32>(qabc.x, qabc.y, qd, qabc.z);\r\n } else {\r\n quat = vec4<f32>(qabc.x, qabc.y, qabc.z, qd);\r\n }\r\n\r\n let qw : f32 = quat.x;\r\n let qx : f32 = quat.y;\r\n let qy : f32 = quat.z;\r\n let qz : f32 = quat.w;\r\n let R : mat3x3<f32> = mat3x3<f32>(\r\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\r\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\r\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\r\n );\r\n let S2 : mat3x3<f32> = mat3x3<f32>(\r\n 4.0 * splatScale.x * splatScale.x, 0.0, 0.0,\r\n 0.0, 4.0 * splatScale.y * splatScale.y, 0.0,\r\n 0.0, 0.0, 4.0 * splatScale.z * splatScale.z\r\n );\r\n let Sigma : mat3x3<f32> = R * S2 * transpose(R);\r\n\r\n let SH_C0 : f32 = 0.28209479177387814;\r\n var colRgb : vec3<f32>;\r\n var colA : f32;\r\n if (uniforms.uVersion == 2) {\r\n var c3 : vec3<f32>;\r\n c3.x = textureLoad(sogCodebookTex, vec2<i32>(256 + i32(c0.x * 255.0 + 0.5), 0), 0).r;\r\n c3.y = textureLoad(sogCodebookTex, vec2<i32>(256 + i32(c0.y * 255.0 + 0.5), 0), 0).r;\r\n c3.z = textureLoad(sogCodebookTex, vec2<i32>(256 + i32(c0.z * 255.0 + 0.5), 0), 0).r;\r\n colRgb = vec3<f32>(0.5) + c3 * SH_C0;\r\n colA = c0.w;\r\n } else {\r\n let cLerp : vec4<f32> = mix(uniforms.sogSh0Min, uniforms.sogSh0Max, c0);\r\n colRgb = vec3<f32>(0.5) + cLerp.xyz * SH_C0;\r\n colA = 1.0 / (1.0 + exp(-cLerp.w));\r\n }\r\n\r\n fragmentOutputs.fragData0 = vec4<f32>(center, 1.0);\r\n fragmentOutputs.fragData1 = vec4<f32>(Sigma[0][0], Sigma[0][1], Sigma[0][2], Sigma[1][1]);\r\n fragmentOutputs.fragData2 = vec4<f32>(Sigma[1][2], Sigma[2][2], 0.0, 0.0);\r\n fragmentOutputs.fragData3 = vec4<f32>(colRgb, colA);\r\n}\r\n`;\r\n\r\n/**\r\n * Shader name for the work-buffer relayout (defrag/compaction) copy pass.\r\n */\r\nexport const GaussianSplattingWorkBufferRelayoutShaderName = \"gsWorkBufferRelayout\";\r\n\r\n/**\r\n * Relayout copy fragment shader (GLSL/WebGL2). Copies the four decoded work-buffer textures from a source\r\n * layout to a destination layout, one output texel per draw. In map mode (`uUseMap == 1`) each destination\r\n * texel reads its source splat index from `uMapTex` (R32F; a negative value marks a gap and is discarded so\r\n * the cleared destination stays zero). In identity mode the source texel equals the destination texel.\r\n */\r\nexport const GaussianSplattingWorkBufferRelayoutFragmentShaderGLSL = `precision highp float;\r\nprecision highp int;\r\n\r\nuniform sampler2D uMapTex;\r\nuniform sampler2D uSrc0;\r\nuniform sampler2D uSrc1;\r\nuniform sampler2D uSrc2;\r\nuniform sampler2D uSrc3;\r\nuniform int uDstWidth;\r\nuniform int uSrcWidth;\r\nuniform int uUseMap;\r\n\r\nlayout(location = 0) out vec4 glFragData[4];\r\n\r\nvoid main() {\r\n ivec2 p = ivec2(gl_FragCoord.xy);\r\n int srcIdx;\r\n if (uUseMap == 1) {\r\n float m = texelFetch(uMapTex, p, 0).r;\r\n if (m < 0.0) {\r\n discard;\r\n }\r\n srcIdx = int(m + 0.5);\r\n } else {\r\n srcIdx = p.y * uDstWidth + p.x;\r\n }\r\n ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);\r\n glFragData[0] = texelFetch(uSrc0, s, 0);\r\n glFragData[1] = texelFetch(uSrc1, s, 0);\r\n glFragData[2] = texelFetch(uSrc2, s, 0);\r\n glFragData[3] = texelFetch(uSrc3, s, 0);\r\n}\r\n`;\r\n\r\n/**\r\n * Relayout copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant.\r\n */\r\nexport const GaussianSplattingWorkBufferRelayoutFragmentShaderWGSL = `\r\nvar uMapTexSampler : sampler;\r\nvar uMapTex : texture_2d<f32>;\r\nvar uSrc0Sampler : sampler;\r\nvar uSrc0 : texture_2d<f32>;\r\nvar uSrc1Sampler : sampler;\r\nvar uSrc1 : texture_2d<f32>;\r\nvar uSrc2Sampler : sampler;\r\nvar uSrc2 : texture_2d<f32>;\r\nvar uSrc3Sampler : sampler;\r\nvar uSrc3 : texture_2d<f32>;\r\n\r\nuniform uDstWidth : i32;\r\nuniform uSrcWidth : i32;\r\nuniform uUseMap : i32;\r\n\r\n@fragment\r\nfn main(input : FragmentInputs) -> FragmentOutputs {\r\n let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\r\n var srcIdx : i32;\r\n if (uniforms.uUseMap == 1) {\r\n let m : f32 = textureLoad(uMapTex, p, 0).r;\r\n if (m < 0.0) {\r\n discard;\r\n }\r\n srcIdx = i32(m + 0.5);\r\n } else {\r\n srcIdx = p.y * uniforms.uDstWidth + p.x;\r\n }\r\n let s : vec2<i32> = vec2<i32>(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);\r\n fragmentOutputs.fragData0 = textureLoad(uSrc0, s, 0);\r\n fragmentOutputs.fragData1 = textureLoad(uSrc1, s, 0);\r\n fragmentOutputs.fragData2 = textureLoad(uSrc2, s, 0);\r\n fragmentOutputs.fragData3 = textureLoad(uSrc3, s, 0);\r\n}\r\n`;\r\n"]}
|
|
1
|
+
{"version":3,"file":"gaussianSplattingWorkBufferShaders.js","sourceRoot":"","sources":["../../../../dev/loaders/src/SPLAT/gaussianSplattingWorkBufferShaders.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D;;GAEG;AACH,MAAM,CAAC,MAAM,qCAAqC,GAAG,yBAAyB,CAAC;AAE/E;;GAEG;AACH,MAAM,CAAC,MAAM,2CAA2C,GAAG;;;;;CAK1D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,6CAA6C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8G5D,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,2CAA2C,GAAG;;;;;;CAM1D,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,6CAA6C,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4G5D,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,mDAAmD,GAAG,4BAA4B,CAAC;AAEhG;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,2DAA2D,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiE1E,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,2DAA2D,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoE1E,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,6CAA6C,GAAG,2BAA2B,CAAC;AAEzF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qDAAqD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkEpE,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,qDAAqD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DpE,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,6CAA6C,GAAG,sBAAsB,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qDAAqD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCpE,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,2CAA2C,GAAG,oBAAoB,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mDAAmD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BlE,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,mDAAmD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BlE,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,4CAA4C,GAAG,qBAAqB,CAAC;AAElF;;;;GAIG;AACH,MAAM,CAAC,MAAM,oDAAoD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCnE,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,oDAAoD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCnE,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,qDAAqD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCpE,CAAC","sourcesContent":["/** This file must only contain pure code and pure imports */\r\n\r\n/**\r\n * Shared shader names for the SOG -> decoded work-buffer copy pass.\r\n */\r\nexport const GaussianSplattingWorkBufferShaderName = \"gsSogDecodeToWorkBuffer\";\r\n\r\n/**\r\n * Pass-through vertex shader (GLSL): the geometry is a fullscreen triangle already in NDC.\r\n */\r\nexport const GaussianSplattingWorkBufferVertexShaderGLSL = `precision highp float;\r\nattribute vec3 position;\r\nvoid main() {\r\n gl_Position = vec4(position.xy, 0.0, 1.0);\r\n}\r\n`;\r\n\r\n/**\r\n * Fragment shader (GLSL/WebGL2): decodes one SOG source file into the decoded GS work-buffer layout,\r\n * writing each splat into its allocated pixel. Mirrors the USE_SOG decode in ShadersInclude/gaussianSplatting.fx\r\n * but outputs the decoded MRT (center, covA, covB, color) consumed by the standard (non-SOG) draw path.\r\n *\r\n * MRT layout: 0 = center (x,y,z,1), 1 = covA (Sigma00,01,02,11), 2 = covB (Sigma12,22,0,0), 3 = color (rgba).\r\n */\r\nexport const GaussianSplattingWorkBufferFragmentShaderGLSL = `precision highp float;\r\nprecision highp int;\r\n\r\nuniform sampler2D sogMeansLTex;\r\nuniform sampler2D sogMeansUTex;\r\nuniform sampler2D sogScalesTex;\r\nuniform sampler2D sogQuatsTex;\r\nuniform sampler2D sogSh0Tex;\r\nuniform sampler2D sogCodebookTex;\r\n\r\nuniform vec3 sogMeansMin;\r\nuniform vec3 sogMeansMax;\r\nuniform vec3 sogScalesMin;\r\nuniform vec3 sogScalesMax;\r\nuniform vec4 sogSh0Min;\r\nuniform vec4 sogSh0Max;\r\nuniform int uVersion;\r\nuniform int uOffset;\r\nuniform int uCount;\r\nuniform int uDestWidth;\r\nuniform int uSrcWidth;\r\n\r\nlayout(location = 0) out vec4 glFragData[4];\r\n\r\nmat3 transposeM(mat3 m) {\r\n return mat3(m[0][0], m[1][0], m[2][0], m[0][1], m[1][1], m[2][1], m[0][2], m[1][2], m[2][2]);\r\n}\r\n\r\nvoid main() {\r\n ivec2 p = ivec2(gl_FragCoord.xy);\r\n int global = p.y * uDestWidth + p.x;\r\n if (global < uOffset || global >= uOffset + uCount) {\r\n discard;\r\n }\r\n int k = global - uOffset;\r\n ivec2 src = ivec2(k - (k / uSrcWidth) * uSrcWidth, k / uSrcWidth);\r\n\r\n vec3 mL = texelFetch(sogMeansLTex, src, 0).xyz;\r\n vec3 mU = texelFetch(sogMeansUTex, src, 0).xyz;\r\n vec3 sRaw = texelFetch(sogScalesTex, src, 0).xyz;\r\n vec4 qRaw = texelFetch(sogQuatsTex, src, 0);\r\n vec4 c0 = texelFetch(sogSh0Tex, src, 0);\r\n\r\n // Position: q16 = (u<<8)|l normalized; n = lerp(min,max,q16); pos = sign(n)*(exp(|n|)-1)\r\n vec3 q16 = (mU * 256.0 + mL) * (255.0 / 65535.0);\r\n vec3 nPos = mix(sogMeansMin, sogMeansMax, q16);\r\n vec3 center = sign(nPos) * (exp(abs(nPos)) - vec3(1.0));\r\n\r\n // Scale (v1: lerp+exp ; v2: codebook lookup)\r\n vec3 splatScale;\r\n if (uVersion == 2) {\r\n vec3 sIdx = floor(sRaw * 255.0 + 0.5);\r\n splatScale.x = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.x), 0), 0).r);\r\n splatScale.y = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.y), 0), 0).r);\r\n splatScale.z = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.z), 0), 0).r);\r\n } else {\r\n splatScale = exp(mix(sogScalesMin, sogScalesMax, sRaw));\r\n }\r\n\r\n // Quaternion (largest-omitted, mode in alpha as 252 + omitted-index)\r\n const float invSqrt2 = 0.70710678118;\r\n vec3 qabc = (qRaw.xyz - vec3(0.5)) * 2.0 * invSqrt2;\r\n int qMode = int(qRaw.w * 255.0 + 0.5) - 252;\r\n float qd = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\r\n vec4 quat;\r\n if (qMode == 0) {\r\n quat = vec4(qd, qabc.x, qabc.y, qabc.z);\r\n } else if (qMode == 1) {\r\n quat = vec4(qabc.x, qd, qabc.y, qabc.z);\r\n } else if (qMode == 2) {\r\n quat = vec4(qabc.x, qabc.y, qd, qabc.z);\r\n } else {\r\n quat = vec4(qabc.x, qabc.y, qabc.z, qd);\r\n }\r\n\r\n float qw = quat.x, qx = quat.y, qy = quat.z, qz = quat.w;\r\n mat3 R = mat3(\r\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\r\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\r\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\r\n );\r\n mat3 S2 = mat3(\r\n 4.0 * splatScale.x * splatScale.x, 0.0, 0.0,\r\n 0.0, 4.0 * splatScale.y * splatScale.y, 0.0,\r\n 0.0, 0.0, 4.0 * splatScale.z * splatScale.z\r\n );\r\n mat3 Sigma = R * S2 * transposeM(R);\r\n\r\n // Color (sh0)\r\n const float SH_C0 = 0.28209479177387814;\r\n vec3 colRgb;\r\n float colA;\r\n if (uVersion == 2) {\r\n vec3 c3;\r\n c3.x = texelFetch(sogCodebookTex, ivec2(256 + int(c0.x * 255.0 + 0.5), 0), 0).r;\r\n c3.y = texelFetch(sogCodebookTex, ivec2(256 + int(c0.y * 255.0 + 0.5), 0), 0).r;\r\n c3.z = texelFetch(sogCodebookTex, ivec2(256 + int(c0.z * 255.0 + 0.5), 0), 0).r;\r\n colRgb = vec3(0.5) + c3 * SH_C0;\r\n colA = c0.w;\r\n } else {\r\n vec4 cLerp = mix(sogSh0Min, sogSh0Max, c0);\r\n colRgb = vec3(0.5) + cLerp.xyz * SH_C0;\r\n colA = 1.0 / (1.0 + exp(-cLerp.w));\r\n }\r\n\r\n glFragData[0] = vec4(center, 1.0);\r\n glFragData[1] = vec4(Sigma[0][0], Sigma[0][1], Sigma[0][2], Sigma[1][1]);\r\n glFragData[2] = vec4(Sigma[1][2], Sigma[2][2], 0.0, 0.0);\r\n glFragData[3] = vec4(colRgb, colA);\r\n}\r\n`;\r\n\r\n/**\r\n * Pass-through vertex shader (WGSL).\r\n */\r\nexport const GaussianSplattingWorkBufferVertexShaderWGSL = `\r\nattribute position : vec3<f32>;\r\n@vertex\r\nfn main(input : VertexInputs) -> FragmentInputs {\r\n vertexOutputs.position = vec4<f32>(input.position.xy, 0.0, 1.0);\r\n}\r\n`;\r\n\r\n/**\r\n * Fragment shader (WGSL/WebGPU) — same decode as the GLSL variant, writing 4 MRT attachments.\r\n */\r\nexport const GaussianSplattingWorkBufferFragmentShaderWGSL = `\r\nvar sogMeansLTexSampler : sampler;\r\nvar sogMeansLTex : texture_2d<f32>;\r\nvar sogMeansUTexSampler : sampler;\r\nvar sogMeansUTex : texture_2d<f32>;\r\nvar sogScalesTexSampler : sampler;\r\nvar sogScalesTex : texture_2d<f32>;\r\nvar sogQuatsTexSampler : sampler;\r\nvar sogQuatsTex : texture_2d<f32>;\r\nvar sogSh0TexSampler : sampler;\r\nvar sogSh0Tex : texture_2d<f32>;\r\nvar sogCodebookTexSampler : sampler;\r\nvar sogCodebookTex : texture_2d<f32>;\r\n\r\nuniform sogMeansMin : vec3<f32>;\r\nuniform sogMeansMax : vec3<f32>;\r\nuniform sogScalesMin : vec3<f32>;\r\nuniform sogScalesMax : vec3<f32>;\r\nuniform sogSh0Min : vec4<f32>;\r\nuniform sogSh0Max : vec4<f32>;\r\nuniform uVersion : i32;\r\nuniform uOffset : i32;\r\nuniform uCount : i32;\r\nuniform uDestWidth : i32;\r\nuniform uSrcWidth : i32;\r\n\r\n@fragment\r\nfn main(input : FragmentInputs) -> FragmentOutputs {\r\n let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\r\n let global : i32 = p.y * uniforms.uDestWidth + p.x;\r\n if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {\r\n discard;\r\n }\r\n let k : i32 = global - uniforms.uOffset;\r\n let src : vec2<i32> = vec2<i32>(k - (k / uniforms.uSrcWidth) * uniforms.uSrcWidth, k / uniforms.uSrcWidth);\r\n\r\n let mL : vec3<f32> = textureLoad(sogMeansLTex, src, 0).xyz;\r\n let mU : vec3<f32> = textureLoad(sogMeansUTex, src, 0).xyz;\r\n let sRaw : vec3<f32> = textureLoad(sogScalesTex, src, 0).xyz;\r\n let qRaw : vec4<f32> = textureLoad(sogQuatsTex, src, 0);\r\n let c0 : vec4<f32> = textureLoad(sogSh0Tex, src, 0);\r\n\r\n let q16 : vec3<f32> = (mU * 256.0 + mL) * (255.0 / 65535.0);\r\n let nPos : vec3<f32> = mix(uniforms.sogMeansMin, uniforms.sogMeansMax, q16);\r\n let center : vec3<f32> = sign(nPos) * (exp(abs(nPos)) - vec3<f32>(1.0));\r\n\r\n var splatScale : vec3<f32>;\r\n if (uniforms.uVersion == 2) {\r\n let sIdx : vec3<f32> = floor(sRaw * 255.0 + 0.5);\r\n splatScale.x = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.x), 0), 0).r);\r\n splatScale.y = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.y), 0), 0).r);\r\n splatScale.z = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.z), 0), 0).r);\r\n } else {\r\n splatScale = exp(mix(uniforms.sogScalesMin, uniforms.sogScalesMax, sRaw));\r\n }\r\n\r\n let invSqrt2 : f32 = 0.70710678118;\r\n let qabc : vec3<f32> = (qRaw.xyz - vec3<f32>(0.5)) * 2.0 * invSqrt2;\r\n let qMode : i32 = i32(qRaw.w * 255.0 + 0.5) - 252;\r\n let qd : f32 = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\r\n var quat : vec4<f32>;\r\n if (qMode == 0) {\r\n quat = vec4<f32>(qd, qabc.x, qabc.y, qabc.z);\r\n } else if (qMode == 1) {\r\n quat = vec4<f32>(qabc.x, qd, qabc.y, qabc.z);\r\n } else if (qMode == 2) {\r\n quat = vec4<f32>(qabc.x, qabc.y, qd, qabc.z);\r\n } else {\r\n quat = vec4<f32>(qabc.x, qabc.y, qabc.z, qd);\r\n }\r\n\r\n let qw : f32 = quat.x;\r\n let qx : f32 = quat.y;\r\n let qy : f32 = quat.z;\r\n let qz : f32 = quat.w;\r\n let R : mat3x3<f32> = mat3x3<f32>(\r\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\r\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\r\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\r\n );\r\n let S2 : mat3x3<f32> = mat3x3<f32>(\r\n 4.0 * splatScale.x * splatScale.x, 0.0, 0.0,\r\n 0.0, 4.0 * splatScale.y * splatScale.y, 0.0,\r\n 0.0, 0.0, 4.0 * splatScale.z * splatScale.z\r\n );\r\n let Sigma : mat3x3<f32> = R * S2 * transpose(R);\r\n\r\n let SH_C0 : f32 = 0.28209479177387814;\r\n var colRgb : vec3<f32>;\r\n var colA : f32;\r\n if (uniforms.uVersion == 2) {\r\n var c3 : vec3<f32>;\r\n c3.x = textureLoad(sogCodebookTex, vec2<i32>(256 + i32(c0.x * 255.0 + 0.5), 0), 0).r;\r\n c3.y = textureLoad(sogCodebookTex, vec2<i32>(256 + i32(c0.y * 255.0 + 0.5), 0), 0).r;\r\n c3.z = textureLoad(sogCodebookTex, vec2<i32>(256 + i32(c0.z * 255.0 + 0.5), 0), 0).r;\r\n colRgb = vec3<f32>(0.5) + c3 * SH_C0;\r\n colA = c0.w;\r\n } else {\r\n let cLerp : vec4<f32> = mix(uniforms.sogSh0Min, uniforms.sogSh0Max, c0);\r\n colRgb = vec3<f32>(0.5) + cLerp.xyz * SH_C0;\r\n colA = 1.0 / (1.0 + exp(-cLerp.w));\r\n }\r\n\r\n fragmentOutputs.fragData0 = vec4<f32>(center, 1.0);\r\n fragmentOutputs.fragData1 = vec4<f32>(Sigma[0][0], Sigma[0][1], Sigma[0][2], Sigma[1][1]);\r\n fragmentOutputs.fragData2 = vec4<f32>(Sigma[1][2], Sigma[2][2], 0.0, 0.0);\r\n fragmentOutputs.fragData3 = vec4<f32>(colRgb, colA);\r\n}\r\n`;\r\n\r\n/**\r\n * Shader name for the rotation/scale decode pass (the three half-float textures voxel-IBL shadowing consumes).\r\n */\r\nexport const GaussianSplattingWorkBufferRotationDecodeShaderName = \"gsSogRotDecodeToWorkBuffer\";\r\n\r\n/**\r\n * Rotation/scale decode fragment shader (GLSL/WebGL2). Reconstructs each splat's rotation matrix R and scale and\r\n * writes the three half-float textures the voxel shader samples (rotationsATexture/B/Scale). The layout lets the\r\n * voxel shader reconstruct the same R and scale, so streamed splats get the same ellipsoid the draw path renders:\r\n * rotA = (R col0.xyz, R col1.x)\r\n * rotB = (R col1.yz, R col2.xy)\r\n * rotScale = (R col2.z, 2*scale.x, 2*scale.y, 2*scale.z)\r\n */\r\nexport const GaussianSplattingWorkBufferRotationDecodeFragmentShaderGLSL = `precision highp float;\r\nprecision highp int;\r\n\r\nuniform sampler2D sogScalesTex;\r\nuniform sampler2D sogQuatsTex;\r\nuniform sampler2D sogCodebookTex;\r\n\r\nuniform vec3 sogScalesMin;\r\nuniform vec3 sogScalesMax;\r\nuniform int uVersion;\r\nuniform int uOffset;\r\nuniform int uCount;\r\nuniform int uDestWidth;\r\nuniform int uSrcWidth;\r\n\r\nlayout(location = 0) out vec4 glFragData[3];\r\n\r\nvoid main() {\r\n ivec2 p = ivec2(gl_FragCoord.xy);\r\n int global = p.y * uDestWidth + p.x;\r\n if (global < uOffset || global >= uOffset + uCount) {\r\n discard;\r\n }\r\n int k = global - uOffset;\r\n ivec2 src = ivec2(k - (k / uSrcWidth) * uSrcWidth, k / uSrcWidth);\r\n\r\n vec3 sRaw = texelFetch(sogScalesTex, src, 0).xyz;\r\n vec4 qRaw = texelFetch(sogQuatsTex, src, 0);\r\n\r\n vec3 splatScale;\r\n if (uVersion == 2) {\r\n vec3 sIdx = floor(sRaw * 255.0 + 0.5);\r\n splatScale.x = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.x), 0), 0).r);\r\n splatScale.y = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.y), 0), 0).r);\r\n splatScale.z = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.z), 0), 0).r);\r\n } else {\r\n splatScale = exp(mix(sogScalesMin, sogScalesMax, sRaw));\r\n }\r\n\r\n const float invSqrt2 = 0.70710678118;\r\n vec3 qabc = (qRaw.xyz - vec3(0.5)) * 2.0 * invSqrt2;\r\n int qMode = int(qRaw.w * 255.0 + 0.5) - 252;\r\n float qd = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\r\n vec4 quat;\r\n if (qMode == 0) {\r\n quat = vec4(qd, qabc.x, qabc.y, qabc.z);\r\n } else if (qMode == 1) {\r\n quat = vec4(qabc.x, qd, qabc.y, qabc.z);\r\n } else if (qMode == 2) {\r\n quat = vec4(qabc.x, qabc.y, qd, qabc.z);\r\n } else {\r\n quat = vec4(qabc.x, qabc.y, qabc.z, qd);\r\n }\r\n\r\n float qw = quat.x, qx = quat.y, qy = quat.z, qz = quat.w;\r\n mat3 R = mat3(\r\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\r\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\r\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\r\n );\r\n\r\n glFragData[0] = vec4(R[0], R[1].x);\r\n glFragData[1] = vec4(R[1].y, R[1].z, R[2].x, R[2].y);\r\n glFragData[2] = vec4(R[2].z, 2.0 * splatScale.x, 2.0 * splatScale.y, 2.0 * splatScale.z);\r\n}\r\n`;\r\n\r\n/**\r\n * Rotation/scale decode fragment shader (WGSL/WebGPU) — same decode as the GLSL variant, writing 3 half-float MRT\r\n * attachments.\r\n */\r\nexport const GaussianSplattingWorkBufferRotationDecodeFragmentShaderWGSL = `\r\nvar sogScalesTexSampler : sampler;\r\nvar sogScalesTex : texture_2d<f32>;\r\nvar sogQuatsTexSampler : sampler;\r\nvar sogQuatsTex : texture_2d<f32>;\r\nvar sogCodebookTexSampler : sampler;\r\nvar sogCodebookTex : texture_2d<f32>;\r\n\r\nuniform sogScalesMin : vec3<f32>;\r\nuniform sogScalesMax : vec3<f32>;\r\nuniform uVersion : i32;\r\nuniform uOffset : i32;\r\nuniform uCount : i32;\r\nuniform uDestWidth : i32;\r\nuniform uSrcWidth : i32;\r\n\r\n@fragment\r\nfn main(input : FragmentInputs) -> FragmentOutputs {\r\n let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\r\n let global : i32 = p.y * uniforms.uDestWidth + p.x;\r\n if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {\r\n discard;\r\n }\r\n let k : i32 = global - uniforms.uOffset;\r\n let src : vec2<i32> = vec2<i32>(k - (k / uniforms.uSrcWidth) * uniforms.uSrcWidth, k / uniforms.uSrcWidth);\r\n\r\n let sRaw : vec3<f32> = textureLoad(sogScalesTex, src, 0).xyz;\r\n let qRaw : vec4<f32> = textureLoad(sogQuatsTex, src, 0);\r\n\r\n var splatScale : vec3<f32>;\r\n if (uniforms.uVersion == 2) {\r\n let sIdx : vec3<f32> = floor(sRaw * 255.0 + 0.5);\r\n splatScale.x = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.x), 0), 0).r);\r\n splatScale.y = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.y), 0), 0).r);\r\n splatScale.z = exp(textureLoad(sogCodebookTex, vec2<i32>(i32(sIdx.z), 0), 0).r);\r\n } else {\r\n splatScale = exp(mix(uniforms.sogScalesMin, uniforms.sogScalesMax, sRaw));\r\n }\r\n\r\n let invSqrt2 : f32 = 0.70710678118;\r\n let qabc : vec3<f32> = (qRaw.xyz - vec3<f32>(0.5)) * 2.0 * invSqrt2;\r\n let qMode : i32 = i32(qRaw.w * 255.0 + 0.5) - 252;\r\n let qd : f32 = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\r\n var quat : vec4<f32>;\r\n if (qMode == 0) {\r\n quat = vec4<f32>(qd, qabc.x, qabc.y, qabc.z);\r\n } else if (qMode == 1) {\r\n quat = vec4<f32>(qabc.x, qd, qabc.y, qabc.z);\r\n } else if (qMode == 2) {\r\n quat = vec4<f32>(qabc.x, qabc.y, qd, qabc.z);\r\n } else {\r\n quat = vec4<f32>(qabc.x, qabc.y, qabc.z, qd);\r\n }\r\n\r\n let qw : f32 = quat.x;\r\n let qx : f32 = quat.y;\r\n let qy : f32 = quat.z;\r\n let qz : f32 = quat.w;\r\n let R : mat3x3<f32> = mat3x3<f32>(\r\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\r\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\r\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\r\n );\r\n\r\n fragmentOutputs.fragData0 = vec4<f32>(R[0], R[1].x);\r\n fragmentOutputs.fragData1 = vec4<f32>(R[1].y, R[1].z, R[2].x, R[2].y);\r\n fragmentOutputs.fragData2 = vec4<f32>(R[2].z, 2.0 * splatScale.x, 2.0 * splatScale.y, 2.0 * splatScale.z);\r\n}\r\n`;\r\n\r\n/**\r\n * Shader name for the SOG higher-order SH decode pass (bakes one packed-u32 SH texture per pass).\r\n */\r\nexport const GaussianSplattingWorkBufferShDecodeShaderName = \"gsSogShDecodeToWorkBuffer\";\r\n\r\n/**\r\n * SH decode fragment shader (GLSL/WebGL2). Decodes one SOG file's higher-order spherical-harmonics into one\r\n * packed-u32 SH texture at the region offset, in the layout the draw path's `computeSHWeighted`/`decompose`\r\n * expects (16 SH scalar-bytes per RGBA-u32 texel, little-endian; one texel per splat). Run once per SH texture\r\n * (`uShTextureIndex` selects the 16 scalars written this pass). Coefficients this file lacks are written neutral\r\n * (128 == 0 after `decompose`), so a lower-band file mixes correctly with higher-band ones.\r\n */\r\nexport const GaussianSplattingWorkBufferShDecodeFragmentShaderGLSL = `precision highp float;\r\nprecision highp int;\r\n\r\nuniform sampler2D sogShLabelsTex;\r\nuniform sampler2D sogShCentroidsTex;\r\nuniform sampler2D sogCodebookTex;\r\nuniform float sogShnMin;\r\nuniform float sogShnMax;\r\nuniform int uVersion;\r\nuniform int uOffset;\r\nuniform int uCount;\r\nuniform int uDestWidth;\r\nuniform int uSrcWidth;\r\nuniform int uCoeffs;\r\nuniform int uShTextureIndex;\r\n\r\nlayout(location = 0) out uvec4 outSh;\r\n\r\nvoid main() {\r\n ivec2 p = ivec2(gl_FragCoord.xy);\r\n int global = p.y * uDestWidth + p.x;\r\n if (global < uOffset || global >= uOffset + uCount) {\r\n discard;\r\n }\r\n int kLocal = global - uOffset;\r\n\r\n // 16-bit label for this source splat (LSB in r, MSB in g), indexed over the labels texture's own width.\r\n ivec2 lsz = textureSize(sogShLabelsTex, 0);\r\n ivec2 lsrc = ivec2(kLocal - (kLocal / lsz.x) * lsz.x, kLocal / lsz.x);\r\n vec4 labelRaw = texelFetch(sogShLabelsTex, lsrc, 0);\r\n int n = int(labelRaw.r * 255.0 + 0.5) + int(labelRaw.g * 255.0 + 0.5) * 256;\r\n int u = (n - (n / 64) * 64) * uCoeffs;\r\n int v = n / 64;\r\n\r\n uint packed0 = 0u;\r\n uint packed1 = 0u;\r\n uint packed2 = 0u;\r\n uint packed3 = 0u;\r\n\r\n for (int b = 0; b < 16; b++) {\r\n int s = uShTextureIndex * 16 + b; // flat SH scalar index\r\n int kc = s / 3; // higher-order coefficient (0-based)\r\n int j = s - kc * 3; // channel (0=r,1=g,2=b)\r\n float byteVal = 128.0; // neutral (decompose(128) ~= 0)\r\n if (kc < uCoeffs) {\r\n vec4 centroidRaw = texelFetch(sogShCentroidsTex, ivec2(u + kc, v), 0);\r\n float ch = (j == 0) ? centroidRaw.r : ((j == 1) ? centroidRaw.g : centroidRaw.b);\r\n float coeff;\r\n if (uVersion == 2) {\r\n int cidx = int(ch * 255.0 + 0.5);\r\n coeff = texelFetch(sogCodebookTex, ivec2(512 + cidx, 0), 0).r;\r\n } else {\r\n coeff = mix(sogShnMin, sogShnMax, ch);\r\n }\r\n byteVal = clamp(coeff * 127.5 + 127.5, 0.0, 255.0);\r\n }\r\n uint bv = uint(byteVal + 0.5);\r\n int comp = b / 4;\r\n uint contrib = bv << uint((b - comp * 4) * 8);\r\n if (comp == 0) { packed0 |= contrib; }\r\n else if (comp == 1) { packed1 |= contrib; }\r\n else if (comp == 2) { packed2 |= contrib; }\r\n else { packed3 |= contrib; }\r\n }\r\n outSh = uvec4(packed0, packed1, packed2, packed3);\r\n}\r\n`;\r\n\r\n/**\r\n * SH decode fragment shader (WGSL/WebGPU) — same as the GLSL variant. The integer output (`vec4<u32>` fragData)\r\n * requires the WGSL processor's integer-fragData support.\r\n */\r\nexport const GaussianSplattingWorkBufferShDecodeFragmentShaderWGSL = `\r\nvar sogShLabelsTexSampler : sampler;\r\nvar sogShLabelsTex : texture_2d<f32>;\r\nvar sogShCentroidsTexSampler : sampler;\r\nvar sogShCentroidsTex : texture_2d<f32>;\r\nvar sogCodebookTexSampler : sampler;\r\nvar sogCodebookTex : texture_2d<f32>;\r\n\r\nuniform sogShnMin : f32;\r\nuniform sogShnMax : f32;\r\nuniform uVersion : i32;\r\nuniform uOffset : i32;\r\nuniform uCount : i32;\r\nuniform uDestWidth : i32;\r\nuniform uSrcWidth : i32;\r\nuniform uCoeffs : i32;\r\nuniform uShTextureIndex : i32;\r\n\r\n@fragment\r\nfn main(input : FragmentInputs) -> FragmentOutputs {\r\n let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\r\n let global : i32 = p.y * uniforms.uDestWidth + p.x;\r\n if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {\r\n discard;\r\n }\r\n let kLocal : i32 = global - uniforms.uOffset;\r\n\r\n let lsz : vec2<i32> = vec2<i32>(textureDimensions(sogShLabelsTex, 0));\r\n let lsrc : vec2<i32> = vec2<i32>(kLocal - (kLocal / lsz.x) * lsz.x, kLocal / lsz.x);\r\n let labelRaw : vec4<f32> = textureLoad(sogShLabelsTex, lsrc, 0);\r\n let n : i32 = i32(labelRaw.r * 255.0 + 0.5) + i32(labelRaw.g * 255.0 + 0.5) * 256;\r\n let u : i32 = (n - (n / 64) * 64) * uniforms.uCoeffs;\r\n let v : i32 = n / 64;\r\n\r\n var packed : array<u32, 4> = array<u32, 4>(0u, 0u, 0u, 0u);\r\n\r\n for (var b : i32 = 0; b < 16; b = b + 1) {\r\n let s : i32 = uniforms.uShTextureIndex * 16 + b;\r\n let kc : i32 = s / 3;\r\n let j : i32 = s - kc * 3;\r\n var byteVal : f32 = 128.0;\r\n if (kc < uniforms.uCoeffs) {\r\n let centroidRaw : vec4<f32> = textureLoad(sogShCentroidsTex, vec2<i32>(u + kc, v), 0);\r\n var ch : f32 = centroidRaw.b;\r\n if (j == 0) { ch = centroidRaw.r; } else if (j == 1) { ch = centroidRaw.g; }\r\n var coeff : f32;\r\n if (uniforms.uVersion == 2) {\r\n let cidx : i32 = i32(ch * 255.0 + 0.5);\r\n coeff = textureLoad(sogCodebookTex, vec2<i32>(512 + cidx, 0), 0).r;\r\n } else {\r\n coeff = mix(uniforms.sogShnMin, uniforms.sogShnMax, ch);\r\n }\r\n byteVal = clamp(coeff * 127.5 + 127.5, 0.0, 255.0);\r\n }\r\n let bv : u32 = u32(byteVal + 0.5);\r\n let comp : i32 = b / 4;\r\n packed[comp] = packed[comp] | (bv << u32((b - comp * 4) * 8));\r\n }\r\n fragmentOutputs.fragData0 = vec4<u32>(packed[0], packed[1], packed[2], packed[3]);\r\n}\r\n`;\r\n\r\n/**\r\n * Shader name for the work-buffer relayout (defrag/compaction) copy pass.\r\n */\r\nexport const GaussianSplattingWorkBufferRelayoutShaderName = \"gsWorkBufferRelayout\";\r\n\r\n/**\r\n * Relayout copy fragment shader (GLSL/WebGL2). Copies the four decoded work-buffer textures from a source\r\n * layout to a destination layout, one output texel per draw. In map mode (`uUseMap == 1`) each destination\r\n * texel reads its source splat index from `uMapTex` (R32F; a negative value marks a gap and is discarded so\r\n * the cleared destination stays zero). In identity mode the source texel equals the destination texel.\r\n */\r\nexport const GaussianSplattingWorkBufferRelayoutFragmentShaderGLSL = `precision highp float;\r\nprecision highp int;\r\n\r\nuniform sampler2D uMapTex;\r\nuniform sampler2D uSrc0;\r\nuniform sampler2D uSrc1;\r\nuniform sampler2D uSrc2;\r\nuniform sampler2D uSrc3;\r\nuniform int uDstWidth;\r\nuniform int uSrcWidth;\r\nuniform int uUseMap;\r\n// Region-scoped relayout (hosted compound atlas), both default 0 (standalone square path unchanged):\r\n// uSrcBaseOffset — added to the map's (region-local) source index so pass 1 reads the correct GLOBAL atlas texel.\r\n// uDstBaseRow — subtracted from the atlas destination row so pass 2's identity copy reads the region-local temp.\r\nuniform int uSrcBaseOffset;\r\nuniform int uDstBaseRow;\r\n\r\nlayout(location = 0) out vec4 glFragData[4];\r\n\r\nvoid main() {\r\n ivec2 p = ivec2(gl_FragCoord.xy);\r\n int srcIdx;\r\n if (uUseMap == 1) {\r\n float m = texelFetch(uMapTex, p, 0).r;\r\n if (m < 0.0) {\r\n discard;\r\n }\r\n srcIdx = uSrcBaseOffset + int(m + 0.5);\r\n } else {\r\n srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;\r\n }\r\n ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);\r\n glFragData[0] = texelFetch(uSrc0, s, 0);\r\n glFragData[1] = texelFetch(uSrc1, s, 0);\r\n glFragData[2] = texelFetch(uSrc2, s, 0);\r\n glFragData[3] = texelFetch(uSrc3, s, 0);\r\n}\r\n`;\r\n\r\n/**\r\n * Shader name for the INTEGER (packed-u32 SH) relayout/backup copy pass. Same index/map/base math as the float\r\n * relayout shader, but samples ONE integer SH source texture (`usampler2D`) and writes ONE integer attachment,\r\n * so it moves one baked SH texture per pass (parallel to the four-out float copy).\r\n */\r\nexport const GaussianSplattingWorkBufferShCopyShaderName = \"gsWorkBufferShCopy\";\r\n\r\n/**\r\n * Integer SH relayout/backup copy fragment shader (GLSL/WebGL2). Copies one packed-u32 SH texture from a source\r\n * layout to a destination layout, one output texel per draw. Map mode (`uUseMap == 1`) reads each destination\r\n * texel's source splat index from `uMapTex` (R32F; negative = gap, discarded); identity mode copies texel-for-texel\r\n * (region backup/restore). `uSrcBaseOffset`/`uDstBaseRow` scope the copy to a hosted region's atlas rows (default 0).\r\n */\r\nexport const GaussianSplattingWorkBufferShCopyFragmentShaderGLSL = `precision highp float;\r\nprecision highp int;\r\nprecision highp usampler2D;\r\n\r\nuniform sampler2D uMapTex;\r\nuniform usampler2D uSrcSh;\r\nuniform int uDstWidth;\r\nuniform int uSrcWidth;\r\nuniform int uUseMap;\r\nuniform int uSrcBaseOffset;\r\nuniform int uDstBaseRow;\r\n\r\nlayout(location = 0) out uvec4 outSh;\r\n\r\nvoid main() {\r\n ivec2 p = ivec2(gl_FragCoord.xy);\r\n int srcIdx;\r\n if (uUseMap == 1) {\r\n float m = texelFetch(uMapTex, p, 0).r;\r\n if (m < 0.0) {\r\n discard;\r\n }\r\n srcIdx = uSrcBaseOffset + int(m + 0.5);\r\n } else {\r\n srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;\r\n }\r\n ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);\r\n outSh = texelFetch(uSrcSh, s, 0);\r\n}\r\n`;\r\n\r\n/**\r\n * Integer SH relayout/backup copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant. The integer output\r\n * (`vec4<u32>` fragData) requires the WGSL processor's integer-fragData support.\r\n */\r\nexport const GaussianSplattingWorkBufferShCopyFragmentShaderWGSL = `\r\nvar uMapTexSampler : sampler;\r\nvar uMapTex : texture_2d<f32>;\r\n// Integer source sampled via textureLoad only — NO paired sampler (a sampler on a Uint texture fails WebGPU\r\n// validation: \"None of the supported sample types (Uint)\"). Mirrors the draw shader's shTexture0 declaration.\r\nvar uSrcSh : texture_2d<u32>;\r\n\r\nuniform uDstWidth : i32;\r\nuniform uSrcWidth : i32;\r\nuniform uUseMap : i32;\r\nuniform uSrcBaseOffset : i32;\r\nuniform uDstBaseRow : i32;\r\n\r\n@fragment\r\nfn main(input : FragmentInputs) -> FragmentOutputs {\r\n let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\r\n var srcIdx : i32;\r\n if (uniforms.uUseMap == 1) {\r\n let m : f32 = textureLoad(uMapTex, p, 0).r;\r\n if (m < 0.0) {\r\n discard;\r\n }\r\n srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);\r\n } else {\r\n srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;\r\n }\r\n let s : vec2<i32> = vec2<i32>(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);\r\n // Wrap in an explicit vec4<u32> so the WGSL processor emits an integer fragData location (its detection keys\r\n // off a literal vec4<u32>/vec4u in the assignment; a bare textureLoad(...) would default to vec4<f32>).\r\n fragmentOutputs.fragData0 = vec4<u32>(textureLoad(uSrcSh, s, 0));\r\n}\r\n`;\r\n\r\n/**\r\n * Shader name for the rotation/scale relayout/backup copy pass. Same index/map/base math as the four-out float\r\n * relayout shader, but moves the THREE half-float rotation/scale textures in one pass (their own separate atlas).\r\n */\r\nexport const GaussianSplattingWorkBufferRotCopyShaderName = \"gsWorkBufferRotCopy\";\r\n\r\n/**\r\n * Rotation/scale relayout/backup copy fragment shader (GLSL/WebGL2). Copies the three half-float rotation/scale\r\n * textures from a source layout to a destination layout, one output texel per draw. Identical to the four-out\r\n * float relayout shader but with three attachments (the rotation atlas has no fourth texture).\r\n */\r\nexport const GaussianSplattingWorkBufferRotCopyFragmentShaderGLSL = `precision highp float;\r\nprecision highp int;\r\n\r\nuniform sampler2D uMapTex;\r\nuniform sampler2D uSrc0;\r\nuniform sampler2D uSrc1;\r\nuniform sampler2D uSrc2;\r\nuniform int uDstWidth;\r\nuniform int uSrcWidth;\r\nuniform int uUseMap;\r\nuniform int uSrcBaseOffset;\r\nuniform int uDstBaseRow;\r\n\r\nlayout(location = 0) out vec4 glFragData[3];\r\n\r\nvoid main() {\r\n ivec2 p = ivec2(gl_FragCoord.xy);\r\n int srcIdx;\r\n if (uUseMap == 1) {\r\n float m = texelFetch(uMapTex, p, 0).r;\r\n if (m < 0.0) {\r\n discard;\r\n }\r\n srcIdx = uSrcBaseOffset + int(m + 0.5);\r\n } else {\r\n srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;\r\n }\r\n ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);\r\n glFragData[0] = texelFetch(uSrc0, s, 0);\r\n glFragData[1] = texelFetch(uSrc1, s, 0);\r\n glFragData[2] = texelFetch(uSrc2, s, 0);\r\n}\r\n`;\r\n\r\n/**\r\n * Rotation/scale relayout/backup copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant, 3 attachments.\r\n */\r\nexport const GaussianSplattingWorkBufferRotCopyFragmentShaderWGSL = `\r\nvar uMapTexSampler : sampler;\r\nvar uMapTex : texture_2d<f32>;\r\nvar uSrc0Sampler : sampler;\r\nvar uSrc0 : texture_2d<f32>;\r\nvar uSrc1Sampler : sampler;\r\nvar uSrc1 : texture_2d<f32>;\r\nvar uSrc2Sampler : sampler;\r\nvar uSrc2 : texture_2d<f32>;\r\n\r\nuniform uDstWidth : i32;\r\nuniform uSrcWidth : i32;\r\nuniform uUseMap : i32;\r\nuniform uSrcBaseOffset : i32;\r\nuniform uDstBaseRow : i32;\r\n\r\n@fragment\r\nfn main(input : FragmentInputs) -> FragmentOutputs {\r\n let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\r\n var srcIdx : i32;\r\n if (uniforms.uUseMap == 1) {\r\n let m : f32 = textureLoad(uMapTex, p, 0).r;\r\n if (m < 0.0) {\r\n discard;\r\n }\r\n srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);\r\n } else {\r\n srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;\r\n }\r\n let s : vec2<i32> = vec2<i32>(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);\r\n fragmentOutputs.fragData0 = textureLoad(uSrc0, s, 0);\r\n fragmentOutputs.fragData1 = textureLoad(uSrc1, s, 0);\r\n fragmentOutputs.fragData2 = textureLoad(uSrc2, s, 0);\r\n}\r\n`;\r\n\r\n/**\r\n * Relayout copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant.\r\n */\r\nexport const GaussianSplattingWorkBufferRelayoutFragmentShaderWGSL = `\r\nvar uMapTexSampler : sampler;\r\nvar uMapTex : texture_2d<f32>;\r\nvar uSrc0Sampler : sampler;\r\nvar uSrc0 : texture_2d<f32>;\r\nvar uSrc1Sampler : sampler;\r\nvar uSrc1 : texture_2d<f32>;\r\nvar uSrc2Sampler : sampler;\r\nvar uSrc2 : texture_2d<f32>;\r\nvar uSrc3Sampler : sampler;\r\nvar uSrc3 : texture_2d<f32>;\r\n\r\nuniform uDstWidth : i32;\r\nuniform uSrcWidth : i32;\r\nuniform uUseMap : i32;\r\n// Region-scoped relayout (hosted compound atlas), both default 0 (standalone square path unchanged).\r\nuniform uSrcBaseOffset : i32;\r\nuniform uDstBaseRow : i32;\r\n\r\n@fragment\r\nfn main(input : FragmentInputs) -> FragmentOutputs {\r\n let p : vec2<i32> = vec2<i32>(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\r\n var srcIdx : i32;\r\n if (uniforms.uUseMap == 1) {\r\n let m : f32 = textureLoad(uMapTex, p, 0).r;\r\n if (m < 0.0) {\r\n discard;\r\n }\r\n srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);\r\n } else {\r\n srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;\r\n }\r\n let s : vec2<i32> = vec2<i32>(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);\r\n fragmentOutputs.fragData0 = textureLoad(uSrc0, s, 0);\r\n fragmentOutputs.fragData1 = textureLoad(uSrc1, s, 0);\r\n fragmentOutputs.fragData2 = textureLoad(uSrc2, s, 0);\r\n fragmentOutputs.fragData3 = textureLoad(uSrc3, s, 0);\r\n}\r\n`;\r\n"]}
|
|
@@ -45,7 +45,22 @@ interface IGLTFToFlowGraphMappingObject {
|
|
|
45
45
|
* Used in configuration values. If defined, this will be the default value, if no value is provided.
|
|
46
46
|
*/
|
|
47
47
|
defaultValue?: any;
|
|
48
|
+
/**
|
|
49
|
+
* When the input value comes from a connection (an upstream node output) rather than a literal,
|
|
50
|
+
* the parse-time {@link dataTransformer} cannot run. If this is `true`, the importer inserts a
|
|
51
|
+
* runtime multiply block that scales the connected value by the animation target fps, converting
|
|
52
|
+
* a KHR animation time (seconds) into Babylon animation frames. Literal values keep using the
|
|
53
|
+
* {@link dataTransformer}. Used by `animation/start` / `animation/stopAt` time inputs, which may
|
|
54
|
+
* be fed by a `pointer/get` (e.g. the read-only `maxTime` animation pointer).
|
|
55
|
+
*/
|
|
56
|
+
convertConnectedTimeToFrames?: boolean;
|
|
48
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Description of how a KHR_interactivity declaration (op such as
|
|
60
|
+
* `pointer/get`, `event/onSelect`, `math/add`) maps to one or more
|
|
61
|
+
* FlowGraph blocks. Used by {@link InteractivityGraphToFlowGraphParser}
|
|
62
|
+
* to translate the source glTF graph into the serialized FlowGraph form.
|
|
63
|
+
*/
|
|
49
64
|
export interface IGLTFToFlowGraphMapping {
|
|
50
65
|
/**
|
|
51
66
|
* The type of the FlowGraph block(s).
|
|
@@ -337,7 +352,7 @@ export {};
|
|
|
337
352
|
- Effective JSON Pointer Generation (`pointer/set`) [FlowGraphBlockNames.SetProperty, FlowGraphBlockNames.JsonPointerParser]
|
|
338
353
|
- Pointer Get (`pointer/get`) [FlowGraphBlockNames.GetProperty, FlowGraphBlockNames.JsonPointerParser]
|
|
339
354
|
- Pointer Set (`pointer/set`) [FlowGraphBlockNames.SetProperty, FlowGraphBlockNames.JsonPointerParser]
|
|
340
|
-
- Pointer Interpolate (`pointer/interpolate`) [FlowGraphBlockNames.ValueInterpolation, FlowGraphBlockNames.JsonPointerParser, FlowGraphBlockNames.PlayAnimation, FlowGraphBlockNames.
|
|
355
|
+
- Pointer Interpolate (`pointer/interpolate`) [FlowGraphBlockNames.ValueInterpolation, FlowGraphBlockNames.JsonPointerParser, FlowGraphBlockNames.PlayAnimation, FlowGraphBlockNames.BezierCurveEasing]
|
|
341
356
|
|
|
342
357
|
### Animation Control Nodes
|
|
343
358
|
1. **Animation Play** (`animation/start`) FlowGraphBlockNames.PlayAnimation
|