/** This file must only contain pure code and pure imports */ /** * Shared shader names for the SOG -> decoded work-buffer copy pass. */ export declare const GaussianSplattingWorkBufferShaderName = "gsSogDecodeToWorkBuffer"; /** * Pass-through vertex shader (GLSL): the geometry is a fullscreen triangle already in NDC. */ export declare const GaussianSplattingWorkBufferVertexShaderGLSL = "precision highp float;\nattribute vec3 position;\nvoid main() {\n gl_Position = vec4(position.xy, 0.0, 1.0);\n}\n"; /** * Fragment shader (GLSL/WebGL2): decodes one SOG source file into the decoded GS work-buffer layout, * writing each splat into its allocated pixel. Mirrors the USE_SOG decode in ShadersInclude/gaussianSplatting.fx * but outputs the decoded MRT (center, covA, covB, color) consumed by the standard (non-SOG) draw path. * * MRT layout: 0 = center (x,y,z,1), 1 = covA (Sigma00,01,02,11), 2 = covB (Sigma12,22,0,0), 3 = color (rgba). */ export declare const GaussianSplattingWorkBufferFragmentShaderGLSL = "precision highp float;\nprecision highp int;\n\nuniform sampler2D sogMeansLTex;\nuniform sampler2D sogMeansUTex;\nuniform sampler2D sogScalesTex;\nuniform sampler2D sogQuatsTex;\nuniform sampler2D sogSh0Tex;\nuniform sampler2D sogCodebookTex;\n\nuniform vec3 sogMeansMin;\nuniform vec3 sogMeansMax;\nuniform vec3 sogScalesMin;\nuniform vec3 sogScalesMax;\nuniform vec4 sogSh0Min;\nuniform vec4 sogSh0Max;\nuniform int uVersion;\nuniform int uOffset;\nuniform int uCount;\nuniform int uDestWidth;\nuniform int uSrcWidth;\n\nlayout(location = 0) out vec4 glFragData[4];\n\nmat3 transposeM(mat3 m) {\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]);\n}\n\nvoid main() {\n ivec2 p = ivec2(gl_FragCoord.xy);\n int global = p.y * uDestWidth + p.x;\n if (global < uOffset || global >= uOffset + uCount) {\n discard;\n }\n int k = global - uOffset;\n ivec2 src = ivec2(k - (k / uSrcWidth) * uSrcWidth, k / uSrcWidth);\n\n vec3 mL = texelFetch(sogMeansLTex, src, 0).xyz;\n vec3 mU = texelFetch(sogMeansUTex, src, 0).xyz;\n vec3 sRaw = texelFetch(sogScalesTex, src, 0).xyz;\n vec4 qRaw = texelFetch(sogQuatsTex, src, 0);\n vec4 c0 = texelFetch(sogSh0Tex, src, 0);\n\n // Position: q16 = (u<<8)|l normalized; n = lerp(min,max,q16); pos = sign(n)*(exp(|n|)-1)\n vec3 q16 = (mU * 256.0 + mL) * (255.0 / 65535.0);\n vec3 nPos = mix(sogMeansMin, sogMeansMax, q16);\n vec3 center = sign(nPos) * (exp(abs(nPos)) - vec3(1.0));\n\n // Scale (v1: lerp+exp ; v2: codebook lookup)\n vec3 splatScale;\n if (uVersion == 2) {\n vec3 sIdx = floor(sRaw * 255.0 + 0.5);\n splatScale.x = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.x), 0), 0).r);\n splatScale.y = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.y), 0), 0).r);\n splatScale.z = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.z), 0), 0).r);\n } else {\n splatScale = exp(mix(sogScalesMin, sogScalesMax, sRaw));\n }\n\n // Quaternion (largest-omitted, mode in alpha as 252 + omitted-index)\n const float invSqrt2 = 0.70710678118;\n vec3 qabc = (qRaw.xyz - vec3(0.5)) * 2.0 * invSqrt2;\n int qMode = int(qRaw.w * 255.0 + 0.5) - 252;\n float qd = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\n vec4 quat;\n if (qMode == 0) {\n quat = vec4(qd, qabc.x, qabc.y, qabc.z);\n } else if (qMode == 1) {\n quat = vec4(qabc.x, qd, qabc.y, qabc.z);\n } else if (qMode == 2) {\n quat = vec4(qabc.x, qabc.y, qd, qabc.z);\n } else {\n quat = vec4(qabc.x, qabc.y, qabc.z, qd);\n }\n\n float qw = quat.x, qx = quat.y, qy = quat.z, qz = quat.w;\n mat3 R = mat3(\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\n );\n mat3 S2 = mat3(\n 4.0 * splatScale.x * splatScale.x, 0.0, 0.0,\n 0.0, 4.0 * splatScale.y * splatScale.y, 0.0,\n 0.0, 0.0, 4.0 * splatScale.z * splatScale.z\n );\n mat3 Sigma = R * S2 * transposeM(R);\n\n // Color (sh0)\n const float SH_C0 = 0.28209479177387814;\n vec3 colRgb;\n float colA;\n if (uVersion == 2) {\n vec3 c3;\n c3.x = texelFetch(sogCodebookTex, ivec2(256 + int(c0.x * 255.0 + 0.5), 0), 0).r;\n c3.y = texelFetch(sogCodebookTex, ivec2(256 + int(c0.y * 255.0 + 0.5), 0), 0).r;\n c3.z = texelFetch(sogCodebookTex, ivec2(256 + int(c0.z * 255.0 + 0.5), 0), 0).r;\n colRgb = vec3(0.5) + c3 * SH_C0;\n colA = c0.w;\n } else {\n vec4 cLerp = mix(sogSh0Min, sogSh0Max, c0);\n colRgb = vec3(0.5) + cLerp.xyz * SH_C0;\n colA = 1.0 / (1.0 + exp(-cLerp.w));\n }\n\n glFragData[0] = vec4(center, 1.0);\n glFragData[1] = vec4(Sigma[0][0], Sigma[0][1], Sigma[0][2], Sigma[1][1]);\n glFragData[2] = vec4(Sigma[1][2], Sigma[2][2], 0.0, 0.0);\n glFragData[3] = vec4(colRgb, colA);\n}\n"; /** * Pass-through vertex shader (WGSL). */ export declare const GaussianSplattingWorkBufferVertexShaderWGSL = "\nattribute position : vec3;\n@vertex\nfn main(input : VertexInputs) -> FragmentInputs {\n vertexOutputs.position = vec4(input.position.xy, 0.0, 1.0);\n}\n"; /** * Fragment shader (WGSL/WebGPU) — same decode as the GLSL variant, writing 4 MRT attachments. */ export declare const GaussianSplattingWorkBufferFragmentShaderWGSL = "\nvar sogMeansLTexSampler : sampler;\nvar sogMeansLTex : texture_2d;\nvar sogMeansUTexSampler : sampler;\nvar sogMeansUTex : texture_2d;\nvar sogScalesTexSampler : sampler;\nvar sogScalesTex : texture_2d;\nvar sogQuatsTexSampler : sampler;\nvar sogQuatsTex : texture_2d;\nvar sogSh0TexSampler : sampler;\nvar sogSh0Tex : texture_2d;\nvar sogCodebookTexSampler : sampler;\nvar sogCodebookTex : texture_2d;\n\nuniform sogMeansMin : vec3;\nuniform sogMeansMax : vec3;\nuniform sogScalesMin : vec3;\nuniform sogScalesMax : vec3;\nuniform sogSh0Min : vec4;\nuniform sogSh0Max : vec4;\nuniform uVersion : i32;\nuniform uOffset : i32;\nuniform uCount : i32;\nuniform uDestWidth : i32;\nuniform uSrcWidth : i32;\n\n@fragment\nfn main(input : FragmentInputs) -> FragmentOutputs {\n let p : vec2 = vec2(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\n let global : i32 = p.y * uniforms.uDestWidth + p.x;\n if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {\n discard;\n }\n let k : i32 = global - uniforms.uOffset;\n let src : vec2 = vec2(k - (k / uniforms.uSrcWidth) * uniforms.uSrcWidth, k / uniforms.uSrcWidth);\n\n let mL : vec3 = textureLoad(sogMeansLTex, src, 0).xyz;\n let mU : vec3 = textureLoad(sogMeansUTex, src, 0).xyz;\n let sRaw : vec3 = textureLoad(sogScalesTex, src, 0).xyz;\n let qRaw : vec4 = textureLoad(sogQuatsTex, src, 0);\n let c0 : vec4 = textureLoad(sogSh0Tex, src, 0);\n\n let q16 : vec3 = (mU * 256.0 + mL) * (255.0 / 65535.0);\n let nPos : vec3 = mix(uniforms.sogMeansMin, uniforms.sogMeansMax, q16);\n let center : vec3 = sign(nPos) * (exp(abs(nPos)) - vec3(1.0));\n\n var splatScale : vec3;\n if (uniforms.uVersion == 2) {\n let sIdx : vec3 = floor(sRaw * 255.0 + 0.5);\n splatScale.x = exp(textureLoad(sogCodebookTex, vec2(i32(sIdx.x), 0), 0).r);\n splatScale.y = exp(textureLoad(sogCodebookTex, vec2(i32(sIdx.y), 0), 0).r);\n splatScale.z = exp(textureLoad(sogCodebookTex, vec2(i32(sIdx.z), 0), 0).r);\n } else {\n splatScale = exp(mix(uniforms.sogScalesMin, uniforms.sogScalesMax, sRaw));\n }\n\n let invSqrt2 : f32 = 0.70710678118;\n let qabc : vec3 = (qRaw.xyz - vec3(0.5)) * 2.0 * invSqrt2;\n let qMode : i32 = i32(qRaw.w * 255.0 + 0.5) - 252;\n let qd : f32 = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\n var quat : vec4;\n if (qMode == 0) {\n quat = vec4(qd, qabc.x, qabc.y, qabc.z);\n } else if (qMode == 1) {\n quat = vec4(qabc.x, qd, qabc.y, qabc.z);\n } else if (qMode == 2) {\n quat = vec4(qabc.x, qabc.y, qd, qabc.z);\n } else {\n quat = vec4(qabc.x, qabc.y, qabc.z, qd);\n }\n\n let qw : f32 = quat.x;\n let qx : f32 = quat.y;\n let qy : f32 = quat.z;\n let qz : f32 = quat.w;\n let R : mat3x3 = mat3x3(\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\n );\n let S2 : mat3x3 = mat3x3(\n 4.0 * splatScale.x * splatScale.x, 0.0, 0.0,\n 0.0, 4.0 * splatScale.y * splatScale.y, 0.0,\n 0.0, 0.0, 4.0 * splatScale.z * splatScale.z\n );\n let Sigma : mat3x3 = R * S2 * transpose(R);\n\n let SH_C0 : f32 = 0.28209479177387814;\n var colRgb : vec3;\n var colA : f32;\n if (uniforms.uVersion == 2) {\n var c3 : vec3;\n c3.x = textureLoad(sogCodebookTex, vec2(256 + i32(c0.x * 255.0 + 0.5), 0), 0).r;\n c3.y = textureLoad(sogCodebookTex, vec2(256 + i32(c0.y * 255.0 + 0.5), 0), 0).r;\n c3.z = textureLoad(sogCodebookTex, vec2(256 + i32(c0.z * 255.0 + 0.5), 0), 0).r;\n colRgb = vec3(0.5) + c3 * SH_C0;\n colA = c0.w;\n } else {\n let cLerp : vec4 = mix(uniforms.sogSh0Min, uniforms.sogSh0Max, c0);\n colRgb = vec3(0.5) + cLerp.xyz * SH_C0;\n colA = 1.0 / (1.0 + exp(-cLerp.w));\n }\n\n fragmentOutputs.fragData0 = vec4(center, 1.0);\n fragmentOutputs.fragData1 = vec4(Sigma[0][0], Sigma[0][1], Sigma[0][2], Sigma[1][1]);\n fragmentOutputs.fragData2 = vec4(Sigma[1][2], Sigma[2][2], 0.0, 0.0);\n fragmentOutputs.fragData3 = vec4(colRgb, colA);\n}\n"; /** * Shader name for the rotation/scale decode pass (the three half-float textures voxel-IBL shadowing consumes). */ export declare const GaussianSplattingWorkBufferRotationDecodeShaderName = "gsSogRotDecodeToWorkBuffer"; /** * Rotation/scale decode fragment shader (GLSL/WebGL2). Reconstructs each splat's rotation matrix R and scale and * writes the three half-float textures the voxel shader samples (rotationsATexture/B/Scale). The layout lets the * voxel shader reconstruct the same R and scale, so streamed splats get the same ellipsoid the draw path renders: * rotA = (R col0.xyz, R col1.x) * rotB = (R col1.yz, R col2.xy) * rotScale = (R col2.z, 2*scale.x, 2*scale.y, 2*scale.z) */ export declare const GaussianSplattingWorkBufferRotationDecodeFragmentShaderGLSL = "precision highp float;\nprecision highp int;\n\nuniform sampler2D sogScalesTex;\nuniform sampler2D sogQuatsTex;\nuniform sampler2D sogCodebookTex;\n\nuniform vec3 sogScalesMin;\nuniform vec3 sogScalesMax;\nuniform int uVersion;\nuniform int uOffset;\nuniform int uCount;\nuniform int uDestWidth;\nuniform int uSrcWidth;\n\nlayout(location = 0) out vec4 glFragData[3];\n\nvoid main() {\n ivec2 p = ivec2(gl_FragCoord.xy);\n int global = p.y * uDestWidth + p.x;\n if (global < uOffset || global >= uOffset + uCount) {\n discard;\n }\n int k = global - uOffset;\n ivec2 src = ivec2(k - (k / uSrcWidth) * uSrcWidth, k / uSrcWidth);\n\n vec3 sRaw = texelFetch(sogScalesTex, src, 0).xyz;\n vec4 qRaw = texelFetch(sogQuatsTex, src, 0);\n\n vec3 splatScale;\n if (uVersion == 2) {\n vec3 sIdx = floor(sRaw * 255.0 + 0.5);\n splatScale.x = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.x), 0), 0).r);\n splatScale.y = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.y), 0), 0).r);\n splatScale.z = exp(texelFetch(sogCodebookTex, ivec2(int(sIdx.z), 0), 0).r);\n } else {\n splatScale = exp(mix(sogScalesMin, sogScalesMax, sRaw));\n }\n\n const float invSqrt2 = 0.70710678118;\n vec3 qabc = (qRaw.xyz - vec3(0.5)) * 2.0 * invSqrt2;\n int qMode = int(qRaw.w * 255.0 + 0.5) - 252;\n float qd = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\n vec4 quat;\n if (qMode == 0) {\n quat = vec4(qd, qabc.x, qabc.y, qabc.z);\n } else if (qMode == 1) {\n quat = vec4(qabc.x, qd, qabc.y, qabc.z);\n } else if (qMode == 2) {\n quat = vec4(qabc.x, qabc.y, qd, qabc.z);\n } else {\n quat = vec4(qabc.x, qabc.y, qabc.z, qd);\n }\n\n float qw = quat.x, qx = quat.y, qy = quat.z, qz = quat.w;\n mat3 R = mat3(\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\n );\n\n glFragData[0] = vec4(R[0], R[1].x);\n glFragData[1] = vec4(R[1].y, R[1].z, R[2].x, R[2].y);\n glFragData[2] = vec4(R[2].z, 2.0 * splatScale.x, 2.0 * splatScale.y, 2.0 * splatScale.z);\n}\n"; /** * Rotation/scale decode fragment shader (WGSL/WebGPU) — same decode as the GLSL variant, writing 3 half-float MRT * attachments. */ export declare const GaussianSplattingWorkBufferRotationDecodeFragmentShaderWGSL = "\nvar sogScalesTexSampler : sampler;\nvar sogScalesTex : texture_2d;\nvar sogQuatsTexSampler : sampler;\nvar sogQuatsTex : texture_2d;\nvar sogCodebookTexSampler : sampler;\nvar sogCodebookTex : texture_2d;\n\nuniform sogScalesMin : vec3;\nuniform sogScalesMax : vec3;\nuniform uVersion : i32;\nuniform uOffset : i32;\nuniform uCount : i32;\nuniform uDestWidth : i32;\nuniform uSrcWidth : i32;\n\n@fragment\nfn main(input : FragmentInputs) -> FragmentOutputs {\n let p : vec2 = vec2(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\n let global : i32 = p.y * uniforms.uDestWidth + p.x;\n if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {\n discard;\n }\n let k : i32 = global - uniforms.uOffset;\n let src : vec2 = vec2(k - (k / uniforms.uSrcWidth) * uniforms.uSrcWidth, k / uniforms.uSrcWidth);\n\n let sRaw : vec3 = textureLoad(sogScalesTex, src, 0).xyz;\n let qRaw : vec4 = textureLoad(sogQuatsTex, src, 0);\n\n var splatScale : vec3;\n if (uniforms.uVersion == 2) {\n let sIdx : vec3 = floor(sRaw * 255.0 + 0.5);\n splatScale.x = exp(textureLoad(sogCodebookTex, vec2(i32(sIdx.x), 0), 0).r);\n splatScale.y = exp(textureLoad(sogCodebookTex, vec2(i32(sIdx.y), 0), 0).r);\n splatScale.z = exp(textureLoad(sogCodebookTex, vec2(i32(sIdx.z), 0), 0).r);\n } else {\n splatScale = exp(mix(uniforms.sogScalesMin, uniforms.sogScalesMax, sRaw));\n }\n\n let invSqrt2 : f32 = 0.70710678118;\n let qabc : vec3 = (qRaw.xyz - vec3(0.5)) * 2.0 * invSqrt2;\n let qMode : i32 = i32(qRaw.w * 255.0 + 0.5) - 252;\n let qd : f32 = sqrt(max(0.0, 1.0 - dot(qabc, qabc)));\n var quat : vec4;\n if (qMode == 0) {\n quat = vec4(qd, qabc.x, qabc.y, qabc.z);\n } else if (qMode == 1) {\n quat = vec4(qabc.x, qd, qabc.y, qabc.z);\n } else if (qMode == 2) {\n quat = vec4(qabc.x, qabc.y, qd, qabc.z);\n } else {\n quat = vec4(qabc.x, qabc.y, qabc.z, qd);\n }\n\n let qw : f32 = quat.x;\n let qx : f32 = quat.y;\n let qy : f32 = quat.z;\n let qz : f32 = quat.w;\n let R : mat3x3 = mat3x3(\n 1.0 - 2.0 * (qy * qy + qz * qz), 2.0 * (qx * qy + qw * qz), 2.0 * (qx * qz - qw * qy),\n 2.0 * (qx * qy - qw * qz), 1.0 - 2.0 * (qx * qx + qz * qz), 2.0 * (qy * qz + qw * qx),\n 2.0 * (qx * qz + qw * qy), 2.0 * (qy * qz - qw * qx), 1.0 - 2.0 * (qx * qx + qy * qy)\n );\n\n fragmentOutputs.fragData0 = vec4(R[0], R[1].x);\n fragmentOutputs.fragData1 = vec4(R[1].y, R[1].z, R[2].x, R[2].y);\n fragmentOutputs.fragData2 = vec4(R[2].z, 2.0 * splatScale.x, 2.0 * splatScale.y, 2.0 * splatScale.z);\n}\n"; /** * Shader name for the SOG higher-order SH decode pass (bakes one packed-u32 SH texture per pass). */ export declare const GaussianSplattingWorkBufferShDecodeShaderName = "gsSogShDecodeToWorkBuffer"; /** * SH decode fragment shader (GLSL/WebGL2). Decodes one SOG file's higher-order spherical-harmonics into one * packed-u32 SH texture at the region offset, in the layout the draw path's `computeSHWeighted`/`decompose` * expects (16 SH scalar-bytes per RGBA-u32 texel, little-endian; one texel per splat). Run once per SH texture * (`uShTextureIndex` selects the 16 scalars written this pass). Coefficients this file lacks are written neutral * (128 == 0 after `decompose`), so a lower-band file mixes correctly with higher-band ones. */ export declare const GaussianSplattingWorkBufferShDecodeFragmentShaderGLSL = "precision highp float;\nprecision highp int;\n\nuniform sampler2D sogShLabelsTex;\nuniform sampler2D sogShCentroidsTex;\nuniform sampler2D sogCodebookTex;\nuniform float sogShnMin;\nuniform float sogShnMax;\nuniform int uVersion;\nuniform int uOffset;\nuniform int uCount;\nuniform int uDestWidth;\nuniform int uSrcWidth;\nuniform int uCoeffs;\nuniform int uShTextureIndex;\n\nlayout(location = 0) out uvec4 outSh;\n\nvoid main() {\n ivec2 p = ivec2(gl_FragCoord.xy);\n int global = p.y * uDestWidth + p.x;\n if (global < uOffset || global >= uOffset + uCount) {\n discard;\n }\n int kLocal = global - uOffset;\n\n // 16-bit label for this source splat (LSB in r, MSB in g), indexed over the labels texture's own width.\n ivec2 lsz = textureSize(sogShLabelsTex, 0);\n ivec2 lsrc = ivec2(kLocal - (kLocal / lsz.x) * lsz.x, kLocal / lsz.x);\n vec4 labelRaw = texelFetch(sogShLabelsTex, lsrc, 0);\n int n = int(labelRaw.r * 255.0 + 0.5) + int(labelRaw.g * 255.0 + 0.5) * 256;\n int u = (n - (n / 64) * 64) * uCoeffs;\n int v = n / 64;\n\n uint packed0 = 0u;\n uint packed1 = 0u;\n uint packed2 = 0u;\n uint packed3 = 0u;\n\n for (int b = 0; b < 16; b++) {\n int s = uShTextureIndex * 16 + b; // flat SH scalar index\n int kc = s / 3; // higher-order coefficient (0-based)\n int j = s - kc * 3; // channel (0=r,1=g,2=b)\n float byteVal = 128.0; // neutral (decompose(128) ~= 0)\n if (kc < uCoeffs) {\n vec4 centroidRaw = texelFetch(sogShCentroidsTex, ivec2(u + kc, v), 0);\n float ch = (j == 0) ? centroidRaw.r : ((j == 1) ? centroidRaw.g : centroidRaw.b);\n float coeff;\n if (uVersion == 2) {\n int cidx = int(ch * 255.0 + 0.5);\n coeff = texelFetch(sogCodebookTex, ivec2(512 + cidx, 0), 0).r;\n } else {\n coeff = mix(sogShnMin, sogShnMax, ch);\n }\n byteVal = clamp(coeff * 127.5 + 127.5, 0.0, 255.0);\n }\n uint bv = uint(byteVal + 0.5);\n int comp = b / 4;\n uint contrib = bv << uint((b - comp * 4) * 8);\n if (comp == 0) { packed0 |= contrib; }\n else if (comp == 1) { packed1 |= contrib; }\n else if (comp == 2) { packed2 |= contrib; }\n else { packed3 |= contrib; }\n }\n outSh = uvec4(packed0, packed1, packed2, packed3);\n}\n"; /** * SH decode fragment shader (WGSL/WebGPU) — same as the GLSL variant. The integer output (`vec4` fragData) * requires the WGSL processor's integer-fragData support. */ export declare const GaussianSplattingWorkBufferShDecodeFragmentShaderWGSL = "\nvar sogShLabelsTexSampler : sampler;\nvar sogShLabelsTex : texture_2d;\nvar sogShCentroidsTexSampler : sampler;\nvar sogShCentroidsTex : texture_2d;\nvar sogCodebookTexSampler : sampler;\nvar sogCodebookTex : texture_2d;\n\nuniform sogShnMin : f32;\nuniform sogShnMax : f32;\nuniform uVersion : i32;\nuniform uOffset : i32;\nuniform uCount : i32;\nuniform uDestWidth : i32;\nuniform uSrcWidth : i32;\nuniform uCoeffs : i32;\nuniform uShTextureIndex : i32;\n\n@fragment\nfn main(input : FragmentInputs) -> FragmentOutputs {\n let p : vec2 = vec2(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\n let global : i32 = p.y * uniforms.uDestWidth + p.x;\n if (global < uniforms.uOffset || global >= uniforms.uOffset + uniforms.uCount) {\n discard;\n }\n let kLocal : i32 = global - uniforms.uOffset;\n\n let lsz : vec2 = vec2(textureDimensions(sogShLabelsTex, 0));\n let lsrc : vec2 = vec2(kLocal - (kLocal / lsz.x) * lsz.x, kLocal / lsz.x);\n let labelRaw : vec4 = textureLoad(sogShLabelsTex, lsrc, 0);\n let n : i32 = i32(labelRaw.r * 255.0 + 0.5) + i32(labelRaw.g * 255.0 + 0.5) * 256;\n let u : i32 = (n - (n / 64) * 64) * uniforms.uCoeffs;\n let v : i32 = n / 64;\n\n var packed : array = array(0u, 0u, 0u, 0u);\n\n for (var b : i32 = 0; b < 16; b = b + 1) {\n let s : i32 = uniforms.uShTextureIndex * 16 + b;\n let kc : i32 = s / 3;\n let j : i32 = s - kc * 3;\n var byteVal : f32 = 128.0;\n if (kc < uniforms.uCoeffs) {\n let centroidRaw : vec4 = textureLoad(sogShCentroidsTex, vec2(u + kc, v), 0);\n var ch : f32 = centroidRaw.b;\n if (j == 0) { ch = centroidRaw.r; } else if (j == 1) { ch = centroidRaw.g; }\n var coeff : f32;\n if (uniforms.uVersion == 2) {\n let cidx : i32 = i32(ch * 255.0 + 0.5);\n coeff = textureLoad(sogCodebookTex, vec2(512 + cidx, 0), 0).r;\n } else {\n coeff = mix(uniforms.sogShnMin, uniforms.sogShnMax, ch);\n }\n byteVal = clamp(coeff * 127.5 + 127.5, 0.0, 255.0);\n }\n let bv : u32 = u32(byteVal + 0.5);\n let comp : i32 = b / 4;\n packed[comp] = packed[comp] | (bv << u32((b - comp * 4) * 8));\n }\n fragmentOutputs.fragData0 = vec4(packed[0], packed[1], packed[2], packed[3]);\n}\n"; /** * Shader name for the work-buffer relayout (defrag/compaction) copy pass. */ export declare const GaussianSplattingWorkBufferRelayoutShaderName = "gsWorkBufferRelayout"; /** * Relayout copy fragment shader (GLSL/WebGL2). Copies the four decoded work-buffer textures from a source * layout to a destination layout, one output texel per draw. In map mode (`uUseMap == 1`) each destination * texel reads its source splat index from `uMapTex` (R32F; a negative value marks a gap and is discarded so * the cleared destination stays zero). In identity mode the source texel equals the destination texel. */ export declare const GaussianSplattingWorkBufferRelayoutFragmentShaderGLSL = "precision highp float;\nprecision highp int;\n\nuniform sampler2D uMapTex;\nuniform sampler2D uSrc0;\nuniform sampler2D uSrc1;\nuniform sampler2D uSrc2;\nuniform sampler2D uSrc3;\nuniform int uDstWidth;\nuniform int uSrcWidth;\nuniform int uUseMap;\n// Region-scoped relayout (hosted compound atlas), both default 0 (standalone square path unchanged):\n// uSrcBaseOffset \u2014 added to the map's (region-local) source index so pass 1 reads the correct GLOBAL atlas texel.\n// uDstBaseRow \u2014 subtracted from the atlas destination row so pass 2's identity copy reads the region-local temp.\nuniform int uSrcBaseOffset;\nuniform int uDstBaseRow;\n\nlayout(location = 0) out vec4 glFragData[4];\n\nvoid main() {\n ivec2 p = ivec2(gl_FragCoord.xy);\n int srcIdx;\n if (uUseMap == 1) {\n float m = texelFetch(uMapTex, p, 0).r;\n if (m < 0.0) {\n discard;\n }\n srcIdx = uSrcBaseOffset + int(m + 0.5);\n } else {\n srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;\n }\n ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);\n glFragData[0] = texelFetch(uSrc0, s, 0);\n glFragData[1] = texelFetch(uSrc1, s, 0);\n glFragData[2] = texelFetch(uSrc2, s, 0);\n glFragData[3] = texelFetch(uSrc3, s, 0);\n}\n"; /** * Shader name for the INTEGER (packed-u32 SH) relayout/backup copy pass. Same index/map/base math as the float * relayout shader, but samples ONE integer SH source texture (`usampler2D`) and writes ONE integer attachment, * so it moves one baked SH texture per pass (parallel to the four-out float copy). */ export declare const GaussianSplattingWorkBufferShCopyShaderName = "gsWorkBufferShCopy"; /** * Integer SH relayout/backup copy fragment shader (GLSL/WebGL2). Copies one packed-u32 SH texture from a source * layout to a destination layout, one output texel per draw. Map mode (`uUseMap == 1`) reads each destination * texel's source splat index from `uMapTex` (R32F; negative = gap, discarded); identity mode copies texel-for-texel * (region backup/restore). `uSrcBaseOffset`/`uDstBaseRow` scope the copy to a hosted region's atlas rows (default 0). */ export declare const GaussianSplattingWorkBufferShCopyFragmentShaderGLSL = "precision highp float;\nprecision highp int;\nprecision highp usampler2D;\n\nuniform sampler2D uMapTex;\nuniform usampler2D uSrcSh;\nuniform int uDstWidth;\nuniform int uSrcWidth;\nuniform int uUseMap;\nuniform int uSrcBaseOffset;\nuniform int uDstBaseRow;\n\nlayout(location = 0) out uvec4 outSh;\n\nvoid main() {\n ivec2 p = ivec2(gl_FragCoord.xy);\n int srcIdx;\n if (uUseMap == 1) {\n float m = texelFetch(uMapTex, p, 0).r;\n if (m < 0.0) {\n discard;\n }\n srcIdx = uSrcBaseOffset + int(m + 0.5);\n } else {\n srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;\n }\n ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);\n outSh = texelFetch(uSrcSh, s, 0);\n}\n"; /** * Integer SH relayout/backup copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant. The integer output * (`vec4` fragData) requires the WGSL processor's integer-fragData support. */ export declare const GaussianSplattingWorkBufferShCopyFragmentShaderWGSL = "\nvar uMapTexSampler : sampler;\nvar uMapTex : texture_2d;\n// Integer source sampled via textureLoad only \u2014 NO paired sampler (a sampler on a Uint texture fails WebGPU\n// validation: \"None of the supported sample types (Uint)\"). Mirrors the draw shader's shTexture0 declaration.\nvar uSrcSh : texture_2d;\n\nuniform uDstWidth : i32;\nuniform uSrcWidth : i32;\nuniform uUseMap : i32;\nuniform uSrcBaseOffset : i32;\nuniform uDstBaseRow : i32;\n\n@fragment\nfn main(input : FragmentInputs) -> FragmentOutputs {\n let p : vec2 = vec2(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\n var srcIdx : i32;\n if (uniforms.uUseMap == 1) {\n let m : f32 = textureLoad(uMapTex, p, 0).r;\n if (m < 0.0) {\n discard;\n }\n srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);\n } else {\n srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;\n }\n let s : vec2 = vec2(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);\n // Wrap in an explicit vec4 so the WGSL processor emits an integer fragData location (its detection keys\n // off a literal vec4/vec4u in the assignment; a bare textureLoad(...) would default to vec4).\n fragmentOutputs.fragData0 = vec4(textureLoad(uSrcSh, s, 0));\n}\n"; /** * Shader name for the rotation/scale relayout/backup copy pass. Same index/map/base math as the four-out float * relayout shader, but moves the THREE half-float rotation/scale textures in one pass (their own separate atlas). */ export declare const GaussianSplattingWorkBufferRotCopyShaderName = "gsWorkBufferRotCopy"; /** * Rotation/scale relayout/backup copy fragment shader (GLSL/WebGL2). Copies the three half-float rotation/scale * textures from a source layout to a destination layout, one output texel per draw. Identical to the four-out * float relayout shader but with three attachments (the rotation atlas has no fourth texture). */ export declare const GaussianSplattingWorkBufferRotCopyFragmentShaderGLSL = "precision highp float;\nprecision highp int;\n\nuniform sampler2D uMapTex;\nuniform sampler2D uSrc0;\nuniform sampler2D uSrc1;\nuniform sampler2D uSrc2;\nuniform int uDstWidth;\nuniform int uSrcWidth;\nuniform int uUseMap;\nuniform int uSrcBaseOffset;\nuniform int uDstBaseRow;\n\nlayout(location = 0) out vec4 glFragData[3];\n\nvoid main() {\n ivec2 p = ivec2(gl_FragCoord.xy);\n int srcIdx;\n if (uUseMap == 1) {\n float m = texelFetch(uMapTex, p, 0).r;\n if (m < 0.0) {\n discard;\n }\n srcIdx = uSrcBaseOffset + int(m + 0.5);\n } else {\n srcIdx = (p.y - uDstBaseRow) * uDstWidth + p.x;\n }\n ivec2 s = ivec2(srcIdx - (srcIdx / uSrcWidth) * uSrcWidth, srcIdx / uSrcWidth);\n glFragData[0] = texelFetch(uSrc0, s, 0);\n glFragData[1] = texelFetch(uSrc1, s, 0);\n glFragData[2] = texelFetch(uSrc2, s, 0);\n}\n"; /** * Rotation/scale relayout/backup copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant, 3 attachments. */ export declare const GaussianSplattingWorkBufferRotCopyFragmentShaderWGSL = "\nvar uMapTexSampler : sampler;\nvar uMapTex : texture_2d;\nvar uSrc0Sampler : sampler;\nvar uSrc0 : texture_2d;\nvar uSrc1Sampler : sampler;\nvar uSrc1 : texture_2d;\nvar uSrc2Sampler : sampler;\nvar uSrc2 : texture_2d;\n\nuniform uDstWidth : i32;\nuniform uSrcWidth : i32;\nuniform uUseMap : i32;\nuniform uSrcBaseOffset : i32;\nuniform uDstBaseRow : i32;\n\n@fragment\nfn main(input : FragmentInputs) -> FragmentOutputs {\n let p : vec2 = vec2(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\n var srcIdx : i32;\n if (uniforms.uUseMap == 1) {\n let m : f32 = textureLoad(uMapTex, p, 0).r;\n if (m < 0.0) {\n discard;\n }\n srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);\n } else {\n srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;\n }\n let s : vec2 = vec2(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);\n fragmentOutputs.fragData0 = textureLoad(uSrc0, s, 0);\n fragmentOutputs.fragData1 = textureLoad(uSrc1, s, 0);\n fragmentOutputs.fragData2 = textureLoad(uSrc2, s, 0);\n}\n"; /** * Relayout copy fragment shader (WGSL/WebGPU) — same copy as the GLSL variant. */ export declare const GaussianSplattingWorkBufferRelayoutFragmentShaderWGSL = "\nvar uMapTexSampler : sampler;\nvar uMapTex : texture_2d;\nvar uSrc0Sampler : sampler;\nvar uSrc0 : texture_2d;\nvar uSrc1Sampler : sampler;\nvar uSrc1 : texture_2d;\nvar uSrc2Sampler : sampler;\nvar uSrc2 : texture_2d;\nvar uSrc3Sampler : sampler;\nvar uSrc3 : texture_2d;\n\nuniform uDstWidth : i32;\nuniform uSrcWidth : i32;\nuniform uUseMap : i32;\n// Region-scoped relayout (hosted compound atlas), both default 0 (standalone square path unchanged).\nuniform uSrcBaseOffset : i32;\nuniform uDstBaseRow : i32;\n\n@fragment\nfn main(input : FragmentInputs) -> FragmentOutputs {\n let p : vec2 = vec2(i32(fragmentInputs.position.x), i32(fragmentInputs.position.y));\n var srcIdx : i32;\n if (uniforms.uUseMap == 1) {\n let m : f32 = textureLoad(uMapTex, p, 0).r;\n if (m < 0.0) {\n discard;\n }\n srcIdx = uniforms.uSrcBaseOffset + i32(m + 0.5);\n } else {\n srcIdx = (p.y - uniforms.uDstBaseRow) * uniforms.uDstWidth + p.x;\n }\n let s : vec2 = vec2(srcIdx - (srcIdx / uniforms.uSrcWidth) * uniforms.uSrcWidth, srcIdx / uniforms.uSrcWidth);\n fragmentOutputs.fragData0 = textureLoad(uSrc0, s, 0);\n fragmentOutputs.fragData1 = textureLoad(uSrc1, s, 0);\n fragmentOutputs.fragData2 = textureLoad(uSrc2, s, 0);\n fragmentOutputs.fragData3 = textureLoad(uSrc3, s, 0);\n}\n";