@babylonjs/viewer
Version:
The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.
3 lines (2 loc) • 12.3 kB
JavaScript
import{p as e,o as n,B as t,F as r,t as a,n as o,b7 as i,g as s,b8 as l,b9 as u,ba as d,bA as c}from"./index-B8IgtevW.esm.min.js";import{r as f,d as v,a as x,u as p,p as y}from"./gltf-feature-gaussian-splatting-Ce1heiDe.esm.min.js";const m=[0,1,2,3,5];let h=null;function g(e){const n=(e+1)*(e+1)-1,t=3*n,r=Math.ceil(t/16);let a="";for(let e=0;e<r;e++)a+=`@group(1) @binding(${6+e}) var shTexture${e}: texture_2d<u32>;\n`;let o="";for(let e=0;e<r;e++)o+=` let sh${e}_u32 = textureLoad(shTexture${e}, splatUVi32, 0);\n`;let i=` var sh: array<vec3<f32>, ${n+1}>;\n sh[0] = vec3<f32>(0.0);\n`;const s=e=>`decompose(sh${e/16|0}_u32.${["x","y","z","w"][e%16/4|0]}).${["x","y","z","w"][e%4]}`;for(let e=0;e<n;e++){const n=3*e;i+=` sh[${e+1}] = vec3<f32>(${s(n)}, ${s(n+1)}, ${s(n+2)});\n`}let l=" result = sh[0];\n";e>=1&&(l+=" result += -SH_C1 * y * sh[1] + SH_C1 * z * sh[2] - SH_C1 * x * sh[3];\n"),e>=2&&(l+=" result +=\n SH_C2[0] * xy * sh[4] +\n SH_C2[1] * yz * sh[5] +\n SH_C2[2] * (2.0 * zz - xx - yy) * sh[6] +\n SH_C2[3] * xz * sh[7] +\n SH_C2[4] * (xx - yy) * sh[8];\n"),e>=3&&(l+=" result +=\n SH_C3[0] * y * (3.0 * xx - yy) * sh[9] +\n SH_C3[1] * xy * z * sh[10] +\n SH_C3[2] * y * (4.0 * zz - xx - yy) * sh[11] +\n SH_C3[3] * z * (2.0 * zz - 3.0 * xx - 3.0 * yy) * sh[12] +\n SH_C3[4] * x * (4.0 * zz - xx - yy) * sh[13] +\n SH_C3[5] * z * (xx - yy) * sh[14] +\n SH_C3[6] * x * (xx - 3.0 * yy) * sh[15];\n"),e>=4&&(l+=" result +=\n SH_C4[0] * x * y * (xx - yy) * sh[16] +\n SH_C4[1] * y * z * (3.0 * xx - yy) * sh[17] +\n SH_C4[2] * x * y * (7.0 * zz - 1.0) * sh[18] +\n SH_C4[3] * y * z * (7.0 * zz - 3.0) * sh[19] +\n SH_C4[4] * (zz * (35.0 * zz - 30.0) + 3.0) * sh[20] +\n SH_C4[5] * x * z * (7.0 * zz - 3.0) * sh[21] +\n SH_C4[6] * (xx - yy) * (7.0 * zz - 1.0) * sh[22] +\n SH_C4[7] * x * z * (xx - 3.0 * yy) * sh[23] +\n SH_C4[8] * (xx * (xx - 3.0 * yy) - yy * (3.0 * xx - yy)) * sh[24];\n");let u="const SH_C1: f32 = 0.48860251;\n";return e>=2&&(u+="const SH_C2: array<f32, 5> = array<f32, 5>(1.092548430, -1.09254843, 0.315391565, -1.09254843, 0.546274215);\n"),e>=3&&(u+="const SH_C3: array<f32, 7> = array<f32, 7>(-0.59004358, 2.890611442, -0.45704579, 0.373176332, -0.45704579, 1.445305721, -0.59004358);\n"),e>=4&&(u+="const SH_C4: array<f32, 9> = array<f32, 9>(2.5033429418, -1.7701307698, 0.9461746958, -0.6690465436, 0.1057855469, -0.6690465436, 0.4730873479, -1.7701307698, 0.6258357354);\n"),`// Gaussian Splatting — vertex + fragment WGSL (SH degree ${e}).\n// Generated by buildShShaderSource. Mirrors BJS gaussianSplatting.vertex.fx +\n// gaussianSplatting.fx (SH_DEGREE = ${e}, no compound parts).\nstruct U {\n world: mat4x4<f32>,\n view: mat4x4<f32>,\n projection: mat4x4<f32>,\n viewport: vec2<f32>,\n focal: vec2<f32>,\n dataSize: vec2<f32>,\n alpha: f32,\n _pad0: f32,\n eyePosition: vec3<f32>,\n _pad1: f32,\n};\n@group(1) @binding(0) var<uniform> u: U;\n@group(1) @binding(1) var samp: sampler;\n@group(1) @binding(2) var centersTex: texture_2d<f32>;\n@group(1) @binding(3) var covATex: texture_2d<f32>;\n@group(1) @binding(4) var covBTex: texture_2d<f32>;\n@group(1) @binding(5) var colorsTex: texture_2d<f32>;\n${a}\n\nstruct VOut {\n @builtin(position) pos: vec4<f32>,\n @location(0) vColor: vec4<f32>,\n @location(1) vPos: vec2<f32>,\n};\n\n${u}\n\nfn dataUv(idx: f32) -> vec2<f32> {\n let y = floor(idx / u.dataSize.x);\n let x = idx - y * u.dataSize.x;\n return vec2<f32>((x + 0.5) / u.dataSize.x, (y + 0.5) / u.dataSize.y);\n}\n\nfn dataUvI(idx: f32) -> vec2<i32> {\n let y = floor(idx / u.dataSize.x);\n let x = idx - y * u.dataSize.x;\n return vec2<i32>(i32(x), i32(y));\n}\n\n// Unpack a u32 of 4 packed bytes into (b0 b1 b2 b3) * 2/255 - 1.\nfn decompose(value: u32) -> vec4<f32> {\n let v = vec4<f32>(\n f32((value >> 0u) & 255u),\n f32((value >> 8u) & 255u),\n f32((value >> 16u) & 255u),\n f32((value >> 24u) & 255u));\n return v * vec4<f32>(2.0 / 255.0) - vec4<f32>(1.0);\n}\n\nfn inverseMat3(m: mat3x3<f32>) -> mat3x3<f32> {\n let a00 = m[0][0]; let a01 = m[0][1]; let a02 = m[0][2];\n let a10 = m[1][0]; let a11 = m[1][1]; let a12 = m[1][2];\n let a20 = m[2][0]; let a21 = m[2][1]; let a22 = m[2][2];\n let b01 = a22 * a11 - a12 * a21;\n let b11 = -a22 * a10 + a12 * a20;\n let b21 = a21 * a10 - a11 * a20;\n let det = a00 * b01 + a01 * b11 + a02 * b21;\n return mat3x3<f32>(\n vec3<f32>(b01 / det, (-a22 * a01 + a02 * a21) / det, (a12 * a01 - a02 * a11) / det),\n vec3<f32>(b11 / det, (a22 * a00 - a02 * a20) / det, (-a12 * a00 + a02 * a10) / det),\n vec3<f32>(b21 / det, (-a21 * a00 + a01 * a20) / det, (a11 * a00 - a01 * a10) / det));\n}\n\nfn computeSH(dir: vec3<f32>, splatUVi32: vec2<i32>) -> vec3<f32> {\n${o}${i} let x = dir.x;\n let y = dir.y;\n let z = dir.z;\n let xx = x * x; let yy = y * y; let zz = z * z;\n let xy = x * y; let yz = y * z; let xz = x * z;\n var result: vec3<f32>;\n${l} return result;\n}\n\n@vertex\nfn vs(@location(0) corner: vec2<f32>, @location(1) splatIndex: f32) -> VOut {\n var out: VOut;\n let uv = dataUv(splatIndex);\n let splatUVi32 = dataUvI(splatIndex);\n let center = textureSampleLevel(centersTex, samp, uv, 0.0).xyz;\n let color = textureSampleLevel(colorsTex, samp, uv, 0.0);\n let covA = textureSampleLevel(covATex, samp, uv, 0.0).xyz;\n let covB = textureSampleLevel(covBTex, samp, uv, 0.0).xyz;\n\n let worldPos = u.world * vec4<f32>(center, 1.0);\n let modelView = u.view * u.world;\n let camspace = u.view * worldPos;\n let pos2d = u.projection * camspace;\n\n let bounds = 1.2 * pos2d.w;\n if (pos2d.z < 0.0\n || pos2d.x < -bounds || pos2d.x > bounds\n || pos2d.y < -bounds || pos2d.y > bounds) {\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\n out.vColor = vec4<f32>(0.0);\n out.vPos = vec2<f32>(0.0);\n return out;\n }\n\n // ── View-dependent SH evaluation ───────────────────────────────────\n let worldRot = mat3x3<f32>(u.world[0].xyz, u.world[1].xyz, u.world[2].xyz);\n let normWorldRot = inverseMat3(worldRot);\n var dir = normalize(normWorldRot * (worldPos.xyz - u.eyePosition));\n // Lite-side Y-flip: compensates for our data-path Y pre-flip vs BJS's\n // mesh.scaling.y *= -1 (see file header for derivation).\n dir.y = -dir.y;\n let shColor = computeSH(dir, splatUVi32);\n\n let Vrk = mat3x3<f32>(\n vec3<f32>(covA.x, covA.y, covA.z),\n vec3<f32>(covA.y, covB.x, covB.y),\n vec3<f32>(covA.z, covB.y, covB.z));\n\n let invZ = 1.0 / camspace.z;\n let invZ2 = invZ * invZ;\n let J = mat3x3<f32>(\n vec3<f32>(u.focal.x * invZ, 0.0, -u.focal.x * camspace.x * invZ2),\n vec3<f32>(0.0, u.focal.y * invZ, -u.focal.y * camspace.y * invZ2),\n vec3<f32>(0.0, 0.0, 0.0));\n\n let mv3 = mat3x3<f32>(modelView[0].xyz, modelView[1].xyz, modelView[2].xyz);\n let T = transpose(mv3) * J;\n var cov2d = transpose(T) * Vrk * T;\n\n let kernelSize: f32 = 0.3;\n cov2d[0][0] += kernelSize;\n cov2d[1][1] += kernelSize;\n\n let mid = (cov2d[0][0] + cov2d[1][1]) * 0.5;\n let dxy = (cov2d[0][0] - cov2d[1][1]) * 0.5;\n let radius = length(vec2<f32>(dxy, cov2d[0][1]));\n let epsilon: f32 = 0.0001;\n let lambda1 = mid + radius + epsilon;\n let lambda2 = mid - radius + epsilon;\n if (lambda2 < 0.0) {\n out.pos = vec4<f32>(0.0, 0.0, 2.0, 1.0);\n out.vColor = vec4<f32>(0.0);\n out.vPos = vec2<f32>(0.0);\n return out;\n }\n\n let diag = normalize(vec2<f32>(cov2d[0][1], lambda1 - cov2d[0][0]));\n let majorAxis = min(sqrt(2.0 * lambda1), 1024.0) * diag;\n let minorAxis = min(sqrt(2.0 * lambda2), 1024.0) * vec2<f32>(diag.y, -diag.x);\n\n let vCenter = pos2d.xy;\n out.pos = vec4<f32>(\n vCenter + (corner.x * majorAxis + corner.y * minorAxis) * pos2d.w / u.viewport,\n pos2d.z, pos2d.w);\n out.vColor = vec4<f32>(color.rgb + shColor, color.a * u.alpha);\n out.vPos = corner;\n return out;\n}\n\n/*GS_FRAGMENT_DEFINITIONS*/\n@fragment\nfn fs(in: VOut) -> @location(0) vec4<f32> {\n /*GS_FRAGMENT_MAIN_BEGIN*/\n let A = -dot(in.vPos, in.vPos);\n if (A < -4.0) { discard; }\n let B = exp(A) * in.vColor.a;\n var finalColor = vec4<f32>(in.vColor.rgb, B);\n /*GS_FRAGMENT_BEFORE_FRAGCOLOR*/\n /*GS_FRAGMENT_MAIN_END*/\n return finalColor;\n}\n`}function b(e,n,f){const v=e.surface.engine,b=v._device,_=b.createBuffer({size:240,usage:t.UNIFORM|t.COPY_DST}),z=new r(60);z[52]=n.textureWidth,z[53]=n.textureHeight,z[54]=1,z[55]=0;const S=new Map,C=()=>{const t=e.camera;if(!t)return;p(b.queue,n);const r=l(v),a=r.width/r.height,o=u(t),i=d(t,a),s=n.worldMatrix,f=c(t);z.set(s,0),z.set(o,16),z.set(i,32),z[48]=r.width,z[49]=r.height,z[50]=.5*r.width*i[0],z[51]=.5*r.height*i[5],z[56]=f.x,z[57]=f.y,z[58]=f.z,z[59]=0,b.queue.writeBuffer(_,0,z.buffer,0,240),y(n,s,o)},w={order:200,isTransparent:!0,bind(e,t){const r=function(e,n,t,r){const l=e._device;h&&h.device===l||(h={device:l,modules:new Map,entries:new Map});const u=r&&r.length>0?"|"+r.map(e=>e.id).join(","):"";let d=h.modules.get(t+u);d||(d=l.createShaderModule({code:r&&r.length>0?x(g(t),r):g(t)}),h.modules.set(t+u,d));const c=`${a(n)}|sh${t}${u}`;let f=h.entries.get(c);if(f)return f;const v=m[t],p=[{binding:0,visibility:o.VERTEX|o.FRAGMENT,buffer:{type:"uniform"}},{binding:1,visibility:o.VERTEX,sampler:{type:"non-filtering"}},{binding:2,visibility:o.VERTEX,texture:{sampleType:"unfilterable-float"}},{binding:3,visibility:o.VERTEX,texture:{sampleType:"unfilterable-float"}},{binding:4,visibility:o.VERTEX,texture:{sampleType:"unfilterable-float"}},{binding:5,visibility:o.VERTEX,texture:{sampleType:"unfilterable-float"}}];for(let e=0;e<v;e++)p.push({binding:6+e,visibility:o.VERTEX,texture:{sampleType:"uint"}});const y=l.createBindGroupLayout({entries:p});return f={pipeline:l.createRenderPipeline({layout:l.createPipelineLayout({bindGroupLayouts:[s(e),y]}),vertex:{module:d,entryPoint:"vs",buffers:[{arrayStride:8,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x2"}]},{arrayStride:4,stepMode:"instance",attributes:[{shaderLocation:1,offset:0,format:"float32"}]}]},fragment:{module:d,entryPoint:"fs",targets:[{format:n._colorFormat,blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}},writeMask:i.ALL}]},primitive:{topology:"triangle-list",cullMode:"none"},depthStencil:{format:n._depthStencilFormat??"depth24plus-stencil8",depthCompare:n._depthCompare??"greater-equal",depthWriteEnabled:!1},multisample:{count:n._sampleCount}}),meshBindGroupLayout:y,shTextureCount:v},h.entries.set(c,f),f}(e,t,n.shDegree,f),l=(e=>{let t=S.get(e.pipeline);if(t)return t;const r=n._gs._shViews??[],a=[{binding:0,resource:{buffer:_}},{binding:1,resource:n._gs._sampler},{binding:2,resource:n._gs._centersView},{binding:3,resource:n._gs._covAView},{binding:4,resource:n._gs._covBView},{binding:5,resource:n._gs._colorsView}];for(let n=0;n<e.shTextureCount;n++)a.push({binding:6+n,resource:r[n]});return t=b.createBindGroup({layout:e.meshBindGroupLayout,entries:a}),S.set(e.pipeline,t),t})(r);return{renderable:w,pipeline:r.pipeline,update:C,draw:e=>(e.setBindGroup(1,l),e.setVertexBuffer(0,n._gs._quadBuffer),e.setVertexBuffer(1,n._gs._splatIndexBuffer),e.setIndexBuffer(n._gs._indexBuffer,"uint16"),e.drawIndexed(6,n.vertexCount),1)}}};return w}function _(t,r,a,o){const i=t.surface.engine._device,s=r.shDegree,l=3*((s+1)*(s+1)-1),u=Math.ceil(l/16),d=r.textureWidth,c=r.textureHeight,x=[],p=[],y=r.vertexCount;for(let t=0;t<u;t++){const r=new e(d*c*16),o=16*t,s=Math.min(16,l-o);for(let e=0;e<y;e++){const n=e*l+o,t=16*e;for(let e=0;e<s;e++)r[t+e]=a[n+e]}const u=i.createTexture({size:[d,c],format:"rgba32uint",usage:n.TEXTURE_BINDING|n.COPY_DST});i.queue.writeTexture({texture:u},r.buffer,{bytesPerRow:16*d},{width:d,height:c}),x.push(u),p.push(u.createView())}r._gs._shTextures=x,r._gs._shViews=p;const m=t;m._renderables.push(b(t,r,o));const h=f(t,r,()=>import("./gs-picking-pipeline-DUMOqxO3.esm.min.js"));m._disposables.push(()=>{h(),v(r)})}export{_ as attachGaussianSplattingMeshSH,b as buildGaussianSplattingRenderableSH};
//# sourceMappingURL=gaussian-splatting-pipeline-sh-BQI2m8Y8.esm.min.js.map