@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.
1,221 lines (1,203 loc) • 169 kB
JavaScript
import { S as ShaderStore, K as PushMaterial, aK as PrepareDefinesForMisc, aL as PrepareDefinesForFrameBoundValues, aM as PrepareDefinesForAttributes, aN as PrepareAttributesForInstances, m as VertexBuffer, aO as PrepareUniformsAndSamplersList, A as AddClipPlaneUniforms, a2 as Camera, r as BindClipPlane, X as BindFogParameters, W as BindLogDepth, Y as SerializationHelper, y as MaterialDefines, R as RegisterClass, aP as functions, aQ as HighestCommonFactor, g as Mesh, M as Matrix, V as Vector3, f as VertexData, aR as SubMesh, aS as TmpVectors, L as Logger, H as EngineStore, aT as runCoroutineAsync, aU as createYieldingScheduler, b as Tools, e as ToHalfFloat, C as Constants, aV as runCoroutineSync, a7 as Vector2, j as Color4, Q as Quaternion, aH as Color3, i as Vector4, aW as RandomRange, B as BaseTexture, aX as SPLATFileLoaderMetadata, aG as RegisterSceneLoaderPlugin } from './index-FzOfPXLV.esm.js';
import './clipPlaneFragment-OFOZXtyS.esm.js';
import './logDepthDeclaration-CD9elcsa.esm.js';
import './fogFragment-D9sBwpvW.esm.js';
import './sceneUboDeclaration-CeGVxetF.esm.js';
import './meshUboDeclaration-f8uifp9L.esm.js';
import './clipPlaneVertex-wC8bw87F.esm.js';
import './logDepthVertex-D7mEQN_F.esm.js';
import './helperFunctions-CLFdU2UC.esm.js';
import './clipPlaneFragment-Ci63y_Qd.esm.js';
import './logDepthDeclaration-LUOezDoj.esm.js';
import './fogFragment-B43lgz9g.esm.js';
import './sceneUboDeclaration-81FvQqbq.esm.js';
import './meshUboDeclaration-CjMfZXLK.esm.js';
import './helperFunctions-4InRZPbu.esm.js';
import './clipPlaneVertex-D_rrr4Jo.esm.js';
import './logDepthVertex-CnFPHy8Z.esm.js';
import { R as RawTexture } from './rawTexture-B2DimmQ5.esm.js';
import './thinInstanceMesh-BeyNtce0.esm.js';
import { A as AssetContainer } from './assetContainer-8JZnoDWQ.esm.js';
import { Ray } from './ray-D5OoQOyP.esm.js';
import { S as StandardMaterial } from './standardMaterial-DpmQ1Io2.esm.js';
// Do not edit.
const name$9 = "gaussianSplattingFragmentDeclaration";
const shader$9 = `vec4 gaussianColor(vec4 inColor)
{float A=-dot(vPosition,vPosition);if (A<-4.0) discard;float B=exp(A)*inColor.a;
#include<logDepthFragment>
vec3 color=inColor.rgb;
#ifdef FOG
#include<fogFragment>
#endif
return vec4(color,B);}
`;
// Sideeffect
if (!ShaderStore.IncludesShadersStore[name$9]) {
ShaderStore.IncludesShadersStore[name$9] = shader$9;
}
// Do not edit.
const name$8 = "gaussianSplattingPixelShader";
const shader$8 = `#include<clipPlaneFragmentDeclaration>
#include<logDepthDeclaration>
#include<fogFragmentDeclaration>
varying vec4 vColor;varying vec2 vPosition;
#include<gaussianSplattingFragmentDeclaration>
void main () {
#include<clipPlaneFragment>
gl_FragColor=gaussianColor(vColor);}
`;
// Sideeffect
if (!ShaderStore.ShadersStore[name$8]) {
ShaderStore.ShadersStore[name$8] = shader$8;
}
/** @internal */
const gaussianSplattingPixelShader = { name: name$8, shader: shader$8 };
var gaussianSplatting_fragment$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
gaussianSplattingPixelShader: gaussianSplattingPixelShader
});
// Do not edit.
const name$7 = "gaussianSplattingVertexDeclaration";
const shader$7 = `attribute vec2 position;uniform mat4 view;uniform mat4 projection;uniform mat4 world;uniform vec4 vEyePosition;`;
// Sideeffect
if (!ShaderStore.IncludesShadersStore[name$7]) {
ShaderStore.IncludesShadersStore[name$7] = shader$7;
}
// Do not edit.
const name$6 = "gaussianSplattingUboDeclaration";
const shader$6 = `#include<sceneUboDeclaration>
#include<meshUboDeclaration>
attribute vec2 position;`;
// Sideeffect
if (!ShaderStore.IncludesShadersStore[name$6]) {
ShaderStore.IncludesShadersStore[name$6] = shader$6;
}
// Do not edit.
const name$5 = "gaussianSplatting";
const shader$5 = `#if !defined(WEBGL2) && !defined(WEBGPU) && !defined(NATIVE)
mat3 transpose(mat3 matrix) {return mat3(matrix[0][0],matrix[1][0],matrix[2][0],
matrix[0][1],matrix[1][1],matrix[2][1],
matrix[0][2],matrix[1][2],matrix[2][2]);}
#endif
vec2 getDataUV(float index,vec2 textureSize) {float y=floor(index/textureSize.x);float x=index-y*textureSize.x;return vec2((x+0.5)/textureSize.x,(y+0.5)/textureSize.y);}
#if SH_DEGREE>0
ivec2 getDataUVint(float index,vec2 textureSize) {float y=floor(index/textureSize.x);float x=index-y*textureSize.x;return ivec2(uint(x+0.5),uint(y+0.5));}
#endif
struct Splat {vec4 center;vec4 color;vec4 covA;vec4 covB;
#if SH_DEGREE>0
uvec4 sh0;
#endif
#if SH_DEGREE>1
uvec4 sh1;
#endif
#if SH_DEGREE>2
uvec4 sh2;
#endif
};Splat readSplat(float splatIndex)
{Splat splat;vec2 splatUV=getDataUV(splatIndex,dataTextureSize);splat.center=texture2D(centersTexture,splatUV);splat.color=texture2D(colorsTexture,splatUV);splat.covA=texture2D(covariancesATexture,splatUV)*splat.center.w;splat.covB=texture2D(covariancesBTexture,splatUV)*splat.center.w;
#if SH_DEGREE>0
ivec2 splatUVint=getDataUVint(splatIndex,dataTextureSize);splat.sh0=texelFetch(shTexture0,splatUVint,0);
#endif
#if SH_DEGREE>1
splat.sh1=texelFetch(shTexture1,splatUVint,0);
#endif
#if SH_DEGREE>2
splat.sh2=texelFetch(shTexture2,splatUVint,0);
#endif
return splat;}
#if defined(WEBGL2) || defined(WEBGPU) || defined(NATIVE)
vec3 computeColorFromSHDegree(vec3 dir,const vec3 sh[16])
{const float SH_C0=0.28209479;const float SH_C1=0.48860251;float SH_C2[5];SH_C2[0]=1.092548430;SH_C2[1]=-1.09254843;SH_C2[2]=0.315391565;SH_C2[3]=-1.09254843;SH_C2[4]=0.546274215;float SH_C3[7];SH_C3[0]=-0.59004358;SH_C3[1]=2.890611442;SH_C3[2]=-0.45704579;SH_C3[3]=0.373176332;SH_C3[4]=-0.45704579;SH_C3[5]=1.445305721;SH_C3[6]=-0.59004358;vec3 result=/*SH_C0**/sh[0];
#if SH_DEGREE>0
float x=dir.x;float y=dir.y;float z=dir.z;result+=- SH_C1*y*sh[1]+SH_C1*z*sh[2]-SH_C1*x*sh[3];
#if SH_DEGREE>1
float xx=x*x,yy=y*y,zz=z*z;float xy=x*y,yz=y*z,xz=x*z;result+=
SH_C2[0]*xy*sh[4] +
SH_C2[1]*yz*sh[5] +
SH_C2[2]*(2.0*zz-xx-yy)*sh[6] +
SH_C2[3]*xz*sh[7] +
SH_C2[4]*(xx-yy)*sh[8];
#if SH_DEGREE>2
result+=
SH_C3[0]*y*(3.0*xx-yy)*sh[9] +
SH_C3[1]*xy*z*sh[10] +
SH_C3[2]*y*(4.0*zz-xx-yy)*sh[11] +
SH_C3[3]*z*(2.0*zz-3.0*xx-3.0*yy)*sh[12] +
SH_C3[4]*x*(4.0*zz-xx-yy)*sh[13] +
SH_C3[5]*z*(xx-yy)*sh[14] +
SH_C3[6]*x*(xx-3.0*yy)*sh[15];
#endif
#endif
#endif
return result;}
vec4 decompose(uint value)
{vec4 components=vec4(
float((value ) & 255u),
float((value>>uint( 8)) & 255u),
float((value>>uint(16)) & 255u),
float((value>>uint(24)) & 255u));return components*vec4(2./255.)-vec4(1.);}
vec3 computeSH(Splat splat,vec3 dir)
{vec3 sh[16];sh[0]=vec3(0.,0.,0.);
#if SH_DEGREE>0
vec4 sh00=decompose(splat.sh0.x);vec4 sh01=decompose(splat.sh0.y);vec4 sh02=decompose(splat.sh0.z);sh[1]=vec3(sh00.x,sh00.y,sh00.z);sh[2]=vec3(sh00.w,sh01.x,sh01.y);sh[3]=vec3(sh01.z,sh01.w,sh02.x);
#endif
#if SH_DEGREE>1
vec4 sh03=decompose(splat.sh0.w);vec4 sh04=decompose(splat.sh1.x);vec4 sh05=decompose(splat.sh1.y);sh[4]=vec3(sh02.y,sh02.z,sh02.w);sh[5]=vec3(sh03.x,sh03.y,sh03.z);sh[6]=vec3(sh03.w,sh04.x,sh04.y);sh[7]=vec3(sh04.z,sh04.w,sh05.x);sh[8]=vec3(sh05.y,sh05.z,sh05.w);
#endif
#if SH_DEGREE>2
vec4 sh06=decompose(splat.sh1.z);vec4 sh07=decompose(splat.sh1.w);vec4 sh08=decompose(splat.sh2.x);vec4 sh09=decompose(splat.sh2.y);vec4 sh10=decompose(splat.sh2.z);vec4 sh11=decompose(splat.sh2.w);sh[9]=vec3(sh06.x,sh06.y,sh06.z);sh[10]=vec3(sh06.w,sh07.x,sh07.y);sh[11]=vec3(sh07.z,sh07.w,sh08.x);sh[12]=vec3(sh08.y,sh08.z,sh08.w);sh[13]=vec3(sh09.x,sh09.y,sh09.z);sh[14]=vec3(sh09.w,sh10.x,sh10.y);sh[15]=vec3(sh10.z,sh10.w,sh11.x);
#endif
return computeColorFromSHDegree(dir,sh);}
#else
vec3 computeSH(Splat splat,vec3 dir)
{return vec3(0.,0.,0.);}
#endif
vec4 gaussianSplatting(vec2 meshPos,vec3 worldPos,vec2 scale,vec3 covA,vec3 covB,mat4 worldMatrix,mat4 viewMatrix,mat4 projectionMatrix)
{mat4 modelView=viewMatrix*worldMatrix;vec4 camspace=viewMatrix*vec4(worldPos,1.);vec4 pos2d=projectionMatrix*camspace;float bounds=1.2*pos2d.w;if (pos2d.z<-pos2d.w || pos2d.x<-bounds || pos2d.x>bounds
|| pos2d.y<-bounds || pos2d.y>bounds) {return vec4(0.0,0.0,2.0,1.0);}
mat3 Vrk=mat3(
covA.x,covA.y,covA.z,
covA.y,covB.x,covB.y,
covA.z,covB.y,covB.z
);mat3 J=mat3(
focal.x/camspace.z,0.,-(focal.x*camspace.x)/(camspace.z*camspace.z),
0.,focal.y/camspace.z,-(focal.y*camspace.y)/(camspace.z*camspace.z),
0.,0.,0.
);mat3 invy=mat3(1,0,0,0,-1,0,0,0,1);mat3 T=invy*transpose(mat3(modelView))*J;mat3 cov2d=transpose(T)*Vrk*T;
#if COMPENSATION
float c00=cov2d[0][0];float c11=cov2d[1][1];float c01=cov2d[0][1];float detOrig=c00*c11-c01*c01;
#endif
cov2d[0][0]+=kernelSize;cov2d[1][1]+=kernelSize;
#if COMPENSATION
vec3 c2d=vec3(cov2d[0][0],c01,cov2d[1][1]);float detBlur=c2d.x*c2d.z-c2d.y*c2d.y;float compensation=sqrt(max(0.,detOrig/detBlur));vColor.w*=compensation;
#endif
float mid=(cov2d[0][0]+cov2d[1][1])/2.0;float radius=length(vec2((cov2d[0][0]-cov2d[1][1])/2.0,cov2d[0][1]));float epsilon=0.0001;float lambda1=mid+radius+epsilon,lambda2=mid-radius+epsilon;if (lambda2<0.0)
{return vec4(0.0,0.0,2.0,1.0);}
vec2 diagonalVector=normalize(vec2(cov2d[0][1],lambda1-cov2d[0][0]));vec2 majorAxis=min(sqrt(2.0*lambda1),1024.0)*diagonalVector;vec2 minorAxis=min(sqrt(2.0*lambda2),1024.0)*vec2(diagonalVector.y,-diagonalVector.x);vec2 vCenter=vec2(pos2d);return vec4(
vCenter
+ ((meshPos.x*majorAxis
+ meshPos.y*minorAxis)*invViewport*pos2d.w)*scale,pos2d.zw);}`;
// Sideeffect
if (!ShaderStore.IncludesShadersStore[name$5]) {
ShaderStore.IncludesShadersStore[name$5] = shader$5;
}
// Do not edit.
const name$4 = "gaussianSplattingVertexShader";
const shader$4 = `#include<__decl__gaussianSplattingVertex>
#ifdef LOGARITHMICDEPTH
#extension GL_EXT_frag_depth : enable
#endif
#include<clipPlaneVertexDeclaration>
#include<fogVertexDeclaration>
#include<logDepthDeclaration>
#include<helperFunctions>
attribute float splatIndex;uniform vec2 invViewport;uniform vec2 dataTextureSize;uniform vec2 focal;uniform float kernelSize;uniform vec3 eyePosition;uniform vec3 viewDirectionFactor;uniform sampler2D covariancesATexture;uniform sampler2D covariancesBTexture;uniform sampler2D centersTexture;uniform sampler2D colorsTexture;
#if SH_DEGREE>0
uniform highp usampler2D shTexture0;
#endif
#if SH_DEGREE>1
uniform highp usampler2D shTexture1;
#endif
#if SH_DEGREE>2
uniform highp usampler2D shTexture2;
#endif
varying vec4 vColor;varying vec2 vPosition;
#include<gaussianSplatting>
void main () {Splat splat=readSplat(splatIndex);vec3 covA=splat.covA.xyz;vec3 covB=vec3(splat.covA.w,splat.covB.xy);vec4 worldPos=world*vec4(splat.center.xyz,1.0);vColor=splat.color;vPosition=position;
#if SH_DEGREE>0
mat3 worldRot=mat3(world);mat3 normWorldRot=inverseMat3(worldRot);vec3 dir=normalize(normWorldRot*(worldPos.xyz-eyePosition));dir*=viewDirectionFactor;vColor.xyz=splat.color.xyz+computeSH(splat,dir);
#endif
gl_Position=gaussianSplatting(position,worldPos.xyz,vec2(1.,1.),covA,covB,world,view,projection);
#include<clipPlaneVertex>
#include<fogVertex>
#include<logDepthVertex>
}
`;
// Sideeffect
if (!ShaderStore.ShadersStore[name$4]) {
ShaderStore.ShadersStore[name$4] = shader$4;
}
/** @internal */
const gaussianSplattingVertexShader = { name: name$4, shader: shader$4 };
var gaussianSplatting_vertex$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
gaussianSplattingVertexShader: gaussianSplattingVertexShader
});
// Do not edit.
const name$3 = "gaussianSplattingFragmentDeclaration";
const shader$3 = `fn gaussianColor(inColor: vec4f,inPosition: vec2f)->vec4f
{var A : f32=-dot(inPosition,inPosition);if (A>-4.0)
{var B: f32=exp(A)*inColor.a;
#include<logDepthFragment>
var color: vec3f=inColor.rgb;
#ifdef FOG
#include<fogFragment>
#endif
return vec4f(color,B);} else {return vec4f(0.0);}}
`;
// Sideeffect
if (!ShaderStore.IncludesShadersStoreWGSL[name$3]) {
ShaderStore.IncludesShadersStoreWGSL[name$3] = shader$3;
}
// Do not edit.
const name$2 = "gaussianSplattingPixelShader";
const shader$2 = `#include<clipPlaneFragmentDeclaration>
#include<logDepthDeclaration>
#include<fogFragmentDeclaration>
varying vColor: vec4f;varying vPosition: vec2f;
#include<gaussianSplattingFragmentDeclaration>
@fragment
fn main(input: FragmentInputs)->FragmentOutputs {
#include<clipPlaneFragment>
fragmentOutputs.color=gaussianColor(input.vColor,input.vPosition);}
`;
// Sideeffect
if (!ShaderStore.ShadersStoreWGSL[name$2]) {
ShaderStore.ShadersStoreWGSL[name$2] = shader$2;
}
/** @internal */
const gaussianSplattingPixelShaderWGSL = { name: name$2, shader: shader$2 };
var gaussianSplatting_fragment = /*#__PURE__*/Object.freeze({
__proto__: null,
gaussianSplattingPixelShaderWGSL: gaussianSplattingPixelShaderWGSL
});
// Do not edit.
const name$1 = "gaussianSplatting";
const shader$1 = `fn getDataUV(index: f32,dataTextureSize: vec2f)->vec2<f32> {let y: f32=floor(index/dataTextureSize.x);let x: f32=index-y*dataTextureSize.x;return vec2f((x+0.5),(y+0.5));}
struct Splat {center: vec4f,
color: vec4f,
covA: vec4f,
covB: vec4f,
#if SH_DEGREE>0
sh0: vec4<u32>,
#endif
#if SH_DEGREE>1
sh1: vec4<u32>,
#endif
#if SH_DEGREE>2
sh2: vec4<u32>,
#endif
};fn readSplat(splatIndex: f32,dataTextureSize: vec2f)->Splat {var splat: Splat;let splatUV=getDataUV(splatIndex,dataTextureSize);let splatUVi32=vec2<i32>(i32(splatUV.x),i32(splatUV.y));splat.center=textureLoad(centersTexture,splatUVi32,0);splat.color=textureLoad(colorsTexture,splatUVi32,0);splat.covA=textureLoad(covariancesATexture,splatUVi32,0)*splat.center.w;splat.covB=textureLoad(covariancesBTexture,splatUVi32,0)*splat.center.w;
#if SH_DEGREE>0
splat.sh0=textureLoad(shTexture0,splatUVi32,0);
#endif
#if SH_DEGREE>1
splat.sh1=textureLoad(shTexture1,splatUVi32,0);
#endif
#if SH_DEGREE>2
splat.sh2=textureLoad(shTexture2,splatUVi32,0);
#endif
return splat;}
fn computeColorFromSHDegree(dir: vec3f,sh: array<vec3<f32>,16>)->vec3f
{let SH_C0: f32=0.28209479;let SH_C1: f32=0.48860251;var SH_C2: array<f32,5>=array<f32,5>(
1.092548430,
-1.09254843,
0.315391565,
-1.09254843,
0.546274215
);var SH_C3: array<f32,7>=array<f32,7>(
-0.59004358,
2.890611442,
-0.45704579,
0.373176332,
-0.45704579,
1.445305721,
-0.59004358
);var result: vec3f=/*SH_C0**/sh[0];
#if SH_DEGREE>0
let x: f32=dir.x;let y: f32=dir.y;let z: f32=dir.z;result+=-SH_C1*y*sh[1]+SH_C1*z*sh[2]-SH_C1*x*sh[3];
#if SH_DEGREE>1
let xx: f32=x*x;let yy: f32=y*y;let zz: f32=z*z;let xy: f32=x*y;let yz: f32=y*z;let xz: f32=x*z;result+=
SH_C2[0]*xy*sh[4] +
SH_C2[1]*yz*sh[5] +
SH_C2[2]*(2.0f*zz-xx-yy)*sh[6] +
SH_C2[3]*xz*sh[7] +
SH_C2[4]*(xx-yy)*sh[8];
#if SH_DEGREE>2
result+=
SH_C3[0]*y*(3.0f*xx-yy)*sh[9] +
SH_C3[1]*xy*z*sh[10] +
SH_C3[2]*y*(4.0f*zz-xx-yy)*sh[11] +
SH_C3[3]*z*(2.0f*zz-3.0f*xx-3.0f*yy)*sh[12] +
SH_C3[4]*x*(4.0f*zz-xx-yy)*sh[13] +
SH_C3[5]*z*(xx-yy)*sh[14] +
SH_C3[6]*x*(xx-3.0f*yy)*sh[15];
#endif
#endif
#endif
return result;}
fn decompose(value: u32)->vec4f
{let components : vec4f=vec4f(
f32((value ) & 255u),
f32((value>>u32( 8)) & 255u),
f32((value>>u32(16)) & 255u),
f32((value>>u32(24)) & 255u));return components*vec4f(2./255.)-vec4f(1.);}
fn computeSH(splat: Splat,dir: vec3f)->vec3f
{var sh: array<vec3<f32>,16>;sh[0]=vec3f(0.,0.,0.);
#if SH_DEGREE>0
let sh00: vec4f=decompose(splat.sh0.x);let sh01: vec4f=decompose(splat.sh0.y);let sh02: vec4f=decompose(splat.sh0.z);sh[1]=vec3f(sh00.x,sh00.y,sh00.z);sh[2]=vec3f(sh00.w,sh01.x,sh01.y);sh[3]=vec3f(sh01.z,sh01.w,sh02.x);
#endif
#if SH_DEGREE>1
let sh03: vec4f=decompose(splat.sh0.w);let sh04: vec4f=decompose(splat.sh1.x);let sh05: vec4f=decompose(splat.sh1.y);sh[4]=vec3f(sh02.y,sh02.z,sh02.w);sh[5]=vec3f(sh03.x,sh03.y,sh03.z);sh[6]=vec3f(sh03.w,sh04.x,sh04.y);sh[7]=vec3f(sh04.z,sh04.w,sh05.x);sh[8]=vec3f(sh05.y,sh05.z,sh05.w);
#endif
#if SH_DEGREE>2
let sh06: vec4f=decompose(splat.sh1.z);let sh07: vec4f=decompose(splat.sh1.w);let sh08: vec4f=decompose(splat.sh2.x);let sh09: vec4f=decompose(splat.sh2.y);let sh10: vec4f=decompose(splat.sh2.z);let sh11: vec4f=decompose(splat.sh2.w);sh[9]=vec3f(sh06.x,sh06.y,sh06.z);sh[10]=vec3f(sh06.w,sh07.x,sh07.y);sh[11]=vec3f(sh07.z,sh07.w,sh08.x);sh[12]=vec3f(sh08.y,sh08.z,sh08.w);sh[13]=vec3f(sh09.x,sh09.y,sh09.z);sh[14]=vec3f(sh09.w,sh10.x,sh10.y);sh[15]=vec3f(sh10.z,sh10.w,sh11.x);
#endif
return computeColorFromSHDegree(dir,sh);}
fn gaussianSplatting(
meshPos: vec2<f32>,
worldPos: vec3<f32>,
scale: vec2<f32>,
covA: vec3<f32>,
covB: vec3<f32>,
worldMatrix: mat4x4<f32>,
viewMatrix: mat4x4<f32>,
projectionMatrix: mat4x4<f32>,
focal: vec2f,
invViewport: vec2f,
kernelSize: f32
)->vec4f {let modelView=viewMatrix*worldMatrix;let camspace=viewMatrix*vec4f(worldPos,1.0);let pos2d=projectionMatrix*camspace;let bounds=1.2*pos2d.w;if (pos2d.z<0. || pos2d.x<-bounds || pos2d.x>bounds || pos2d.y<-bounds || pos2d.y>bounds) {return vec4f(0.0,0.0,2.0,1.0);}
let Vrk=mat3x3<f32>(
covA.x,covA.y,covA.z,
covA.y,covB.x,covB.y,
covA.z,covB.y,covB.z
);let J=mat3x3<f32>(
focal.x/camspace.z,0.0,-(focal.x*camspace.x)/(camspace.z*camspace.z),
0.0,focal.y/camspace.z,-(focal.y*camspace.y)/(camspace.z*camspace.z),
0.0,0.0,0.0
);let invy=mat3x3<f32>(
1.0,0.0,0.0,
0.0,-1.0,0.0,
0.0,0.0,1.0
);let T=invy*transpose(mat3x3<f32>(
modelView[0].xyz,
modelView[1].xyz,
modelView[2].xyz))*J;var cov2d=transpose(T)*Vrk*T;
#if COMPENSATION
let c00: f32=cov2d[0][0];let c11: f32=cov2d[1][1];let c01: f32=cov2d[0][1];let detOrig: f32=c00*c11-c01*c01;
#endif
cov2d[0][0]+=kernelSize;cov2d[1][1]+=kernelSize;
#if COMPENSATION
let c2d: vec3f=vec3f(cov2d[0][0],c01,cov2d[1][1]);let detBlur: f32=c2d.x*c2d.z-c2d.y*c2d.y;let compensation: f32=sqrt(max(0.,detOrig/detBlur));vertexOutputs.vColor.w*=compensation;
#endif
let mid=(cov2d[0][0]+cov2d[1][1])/2.0;let radius=length(vec2<f32>((cov2d[0][0]-cov2d[1][1])/2.0,cov2d[0][1]));let lambda1=mid+radius;let lambda2=mid-radius;if (lambda2<0.0) {return vec4f(0.0,0.0,2.0,1.0);}
let diagonalVector=normalize(vec2<f32>(cov2d[0][1],lambda1-cov2d[0][0]));let majorAxis=min(sqrt(2.0*lambda1),1024.0)*diagonalVector;let minorAxis=min(sqrt(2.0*lambda2),1024.0)*vec2<f32>(diagonalVector.y,-diagonalVector.x);let vCenter=vec2<f32>(pos2d.x,pos2d.y);return vec4f(
vCenter+((meshPos.x*majorAxis+meshPos.y*minorAxis)*invViewport*pos2d.w)*scale,
pos2d.z,
pos2d.w
);}
`;
// Sideeffect
if (!ShaderStore.IncludesShadersStoreWGSL[name$1]) {
ShaderStore.IncludesShadersStoreWGSL[name$1] = shader$1;
}
// Do not edit.
const name = "gaussianSplattingVertexShader";
const shader = `#include<sceneUboDeclaration>
#include<meshUboDeclaration>
#include<helperFunctions>
#include<clipPlaneVertexDeclaration>
#include<fogVertexDeclaration>
#include<logDepthDeclaration>
attribute splatIndex: f32;attribute position: vec2f;uniform invViewport: vec2f;uniform dataTextureSize: vec2f;uniform focal: vec2f;uniform kernelSize: f32;uniform eyePosition: vec3f;uniform viewDirectionFactor: vec3f;var covariancesATexture: texture_2d<f32>;var covariancesBTexture: texture_2d<f32>;var centersTexture: texture_2d<f32>;var colorsTexture: texture_2d<f32>;
#if SH_DEGREE>0
var shTexture0: texture_2d<u32>;
#endif
#if SH_DEGREE>1
var shTexture1: texture_2d<u32>;
#endif
#if SH_DEGREE>2
var shTexture2: texture_2d<u32>;
#endif
varying vColor: vec4f;varying vPosition: vec2f;
#include<gaussianSplatting>
@vertex
fn main(input : VertexInputs)->FragmentInputs {var splat: Splat=readSplat(input.splatIndex,uniforms.dataTextureSize);var covA: vec3f=splat.covA.xyz;var covB: vec3f=vec3f(splat.covA.w,splat.covB.xy);let worldPos: vec4f=mesh.world*vec4f(splat.center.xyz,1.0);vertexOutputs.vPosition=input.position;
#if SH_DEGREE>0
let worldRot: mat3x3f= mat3x3f(mesh.world[0].xyz,mesh.world[1].xyz,mesh.world[2].xyz);let normWorldRot: mat3x3f=inverseMat3(worldRot);var dir: vec3f=normalize(normWorldRot*(worldPos.xyz-uniforms.eyePosition.xyz));dir*=viewDirectionFactor;vertexOutputs.vColor=vec4f(splat.color.xyz+computeSH(splat,dir),splat.color.w);
#else
vertexOutputs.vColor=splat.color;
#endif
vertexOutputs.position=gaussianSplatting(input.position,worldPos.xyz,vec2f(1.0,1.0),covA,covB,mesh.world,scene.view,scene.projection,uniforms.focal,uniforms.invViewport,uniforms.kernelSize);
#include<clipPlaneVertex>
#include<fogVertex>
#include<logDepthVertex>
}
`;
// Sideeffect
if (!ShaderStore.ShadersStoreWGSL[name]) {
ShaderStore.ShadersStoreWGSL[name] = shader;
}
/** @internal */
const gaussianSplattingVertexShaderWGSL = { name, shader };
var gaussianSplatting_vertex = /*#__PURE__*/Object.freeze({
__proto__: null,
gaussianSplattingVertexShaderWGSL: gaussianSplattingVertexShaderWGSL
});
/**
* @internal
*/
class GaussianSplattingMaterialDefines extends MaterialDefines {
/**
* Constructor of the defines.
*/
constructor() {
super();
this.FOG = false;
this.THIN_INSTANCES = true;
this.LOGARITHMICDEPTH = false;
this.CLIPPLANE = false;
this.CLIPPLANE2 = false;
this.CLIPPLANE3 = false;
this.CLIPPLANE4 = false;
this.CLIPPLANE5 = false;
this.CLIPPLANE6 = false;
this.SH_DEGREE = 0;
this.COMPENSATION = false;
this.rebuild();
}
}
/**
* GaussianSplattingMaterial material used to render Gaussian Splatting
* @experimental
*/
class GaussianSplattingMaterial extends PushMaterial {
/**
* Instantiates a Gaussian Splatting Material in the given scene
* @param name The friendly name of the material
* @param scene The scene to add the material to
*/
constructor(name, scene) {
super(name, scene);
/**
* Point spread function (default 0.3). Can be overriden per GS material, otherwise, using default static `KernelSize` value
*/
this.kernelSize = GaussianSplattingMaterial.KernelSize;
this._compensation = GaussianSplattingMaterial.Compensation;
// set to true when material defines are dirty
this._isDirty = false;
this.backFaceCulling = false;
}
/**
* Set compensation default value is `GaussianSplattingMaterial.Compensation`
*/
set compensation(value) {
this._isDirty = this._isDirty != value;
this._compensation = value;
}
/**
* Get compensation
*/
get compensation() {
return this._compensation;
}
/**
* Gets a boolean indicating that current material needs to register RTT
*/
get hasRenderTargetTextures() {
return false;
}
/**
* Specifies whether or not this material should be rendered in alpha test mode.
* @returns false
*/
needAlphaTesting() {
return false;
}
/**
* Specifies whether or not this material should be rendered in alpha blend mode.
* @returns true
*/
needAlphaBlending() {
return true;
}
/**
* Checks whether the material is ready to be rendered for a given mesh.
* @param mesh The mesh to render
* @param subMesh The submesh to check against
* @returns true if all the dependencies are ready (Textures, Effects...)
*/
isReadyForSubMesh(mesh, subMesh) {
const useInstances = true;
const drawWrapper = subMesh._drawWrapper;
let defines = subMesh.materialDefines;
if (defines && this._isDirty) {
defines.markAsUnprocessed();
}
if (drawWrapper.effect && this.isFrozen) {
if (drawWrapper._wasPreviouslyReady && drawWrapper._wasPreviouslyUsingInstances === useInstances) {
return true;
}
}
if (!subMesh.materialDefines) {
defines = subMesh.materialDefines = new GaussianSplattingMaterialDefines();
}
const scene = this.getScene();
if (this._isReadyForSubMesh(subMesh)) {
return true;
}
const engine = scene.getEngine();
const gsMesh = mesh;
// Misc.
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, false, defines);
// Values that need to be evaluated on every frame
PrepareDefinesForFrameBoundValues(scene, engine, this, defines, useInstances, null, true);
// Attribs
PrepareDefinesForAttributes(mesh, defines, false, false);
// SH is disabled for webGL1
if (engine.version > 1 || engine.isWebGPU) {
defines["SH_DEGREE"] = gsMesh.shDegree;
}
// Compensation
const splatMaterial = gsMesh.material;
defines["COMPENSATION"] = splatMaterial && splatMaterial.compensation ? splatMaterial.compensation : GaussianSplattingMaterial.Compensation;
// Get correct effect
if (defines.isDirty) {
defines.markAsProcessed();
scene.resetCachedMaterial();
//Attributes
const attribs = [VertexBuffer.PositionKind, "splatIndex"];
PrepareAttributesForInstances(attribs, defines);
const uniforms = [
"world",
"view",
"projection",
"vFogInfos",
"vFogColor",
"logarithmicDepthConstant",
"invViewport",
"dataTextureSize",
"focal",
"eyePosition",
"kernelSize",
"viewDirectionFactor",
];
const samplers = ["covariancesATexture", "covariancesBTexture", "centersTexture", "colorsTexture", "shTexture0", "shTexture1", "shTexture2"];
const uniformBuffers = ["Scene", "Mesh"];
PrepareUniformsAndSamplersList({
uniformsNames: uniforms,
uniformBuffersNames: uniformBuffers,
samplers: samplers,
defines: defines,
});
AddClipPlaneUniforms(uniforms);
const join = defines.toString();
const effect = scene.getEngine().createEffect("gaussianSplatting", {
attributes: attribs,
uniformsNames: uniforms,
uniformBuffersNames: uniformBuffers,
samplers: samplers,
defines: join,
onCompiled: this.onCompiled,
onError: this.onError,
indexParameters: {},
shaderLanguage: this._shaderLanguage,
extraInitializationsAsync: async () => {
if (this._shaderLanguage === 1 /* ShaderLanguage.WGSL */) {
await Promise.all([Promise.resolve().then(function () { return gaussianSplatting_fragment; }), Promise.resolve().then(function () { return gaussianSplatting_vertex; })]);
}
else {
await Promise.all([Promise.resolve().then(function () { return gaussianSplatting_fragment$1; }), Promise.resolve().then(function () { return gaussianSplatting_vertex$1; })]);
}
},
}, engine);
subMesh.setEffect(effect, defines, this._materialContext);
}
if (!subMesh.effect || !subMesh.effect.isReady()) {
return false;
}
defines._renderId = scene.getRenderId();
drawWrapper._wasPreviouslyReady = true;
drawWrapper._wasPreviouslyUsingInstances = useInstances;
this._isDirty = false;
return true;
}
/**
* Bind material effect for a specific Gaussian Splatting mesh
* @param mesh Gaussian splatting mesh
* @param effect Splatting material or node material
* @param scene scene that contains mesh and camera used for rendering
*/
static BindEffect(mesh, effect, scene) {
const engine = scene.getEngine();
const camera = scene.activeCamera;
const renderWidth = engine.getRenderWidth();
const renderHeight = engine.getRenderHeight();
const gsMesh = mesh;
const gsMaterial = gsMesh.material;
// check if rigcamera, get number of rigs
const numberOfRigs = camera?.rigParent?.rigCameras.length || 1;
effect.setFloat2("invViewport", 1 / (renderWidth / numberOfRigs), 1 / renderHeight);
let focal = 1000;
if (camera) {
/*
more explicit version:
const t = camera.getProjectionMatrix().m[5];
const FovY = Math.atan(1.0 / t) * 2.0;
focal = renderHeight / 2.0 / Math.tan(FovY / 2.0);
Using a shorter version here to not have tan(atan) and 2.0 factor
*/
const t = camera.getProjectionMatrix().m[5];
if (camera.fovMode == Camera.FOVMODE_VERTICAL_FIXED) {
focal = (renderHeight * t) / 2.0;
}
else {
focal = (renderWidth * t) / 2.0;
}
}
effect.setFloat2("focal", focal, focal);
effect.setVector3("viewDirectionFactor", gsMesh.viewDirectionFactor);
effect.setFloat("kernelSize", gsMaterial && gsMaterial.kernelSize ? gsMaterial.kernelSize : GaussianSplattingMaterial.KernelSize);
scene.bindEyePosition(effect, "eyePosition", true);
if (gsMesh.covariancesATexture) {
const textureSize = gsMesh.covariancesATexture.getSize();
effect.setFloat2("dataTextureSize", textureSize.width, textureSize.height);
effect.setTexture("covariancesATexture", gsMesh.covariancesATexture);
effect.setTexture("covariancesBTexture", gsMesh.covariancesBTexture);
effect.setTexture("centersTexture", gsMesh.centersTexture);
effect.setTexture("colorsTexture", gsMesh.colorsTexture);
if (gsMesh.shTextures) {
for (let i = 0; i < gsMesh.shTextures?.length; i++) {
effect.setTexture(`shTexture${i}`, gsMesh.shTextures[i]);
}
}
}
}
/**
* Binds the submesh to this material by preparing the effect and shader to draw
* @param world defines the world transformation matrix
* @param mesh defines the mesh containing the submesh
* @param subMesh defines the submesh to bind the material to
*/
bindForSubMesh(world, mesh, subMesh) {
const scene = this.getScene();
const defines = subMesh.materialDefines;
if (!defines) {
return;
}
const effect = subMesh.effect;
if (!effect) {
return;
}
this._activeEffect = effect;
// Matrices Mesh.
mesh.getMeshUniformBuffer().bindToEffect(effect, "Mesh");
mesh.transferToEffect(world);
// Bind data
const mustRebind = this._mustRebind(scene, effect, subMesh, mesh.visibility);
if (mustRebind) {
this.bindView(effect);
this.bindViewProjection(effect);
GaussianSplattingMaterial.BindEffect(mesh, this._activeEffect, scene);
// Clip plane
BindClipPlane(effect, this, scene);
}
else if (scene.getEngine()._features.needToAlwaysBindUniformBuffers) {
this._needToBindSceneUbo = true;
}
// Fog
BindFogParameters(scene, mesh, effect);
// Log. depth
if (this.useLogarithmicDepth) {
BindLogDepth(defines, effect, scene);
}
this._afterBind(mesh, this._activeEffect, subMesh);
}
/**
* Clones the material.
* @param name The cloned name.
* @returns The cloned material.
*/
clone(name) {
return SerializationHelper.Clone(() => new GaussianSplattingMaterial(name, this.getScene()), this);
}
/**
* Serializes the current material to its JSON representation.
* @returns The JSON representation.
*/
serialize() {
const serializationObject = super.serialize();
serializationObject.customType = "BABYLON.GaussianSplattingMaterial";
return serializationObject;
}
/**
* Gets the class name of the material
* @returns "GaussianSplattingMaterial"
*/
getClassName() {
return "GaussianSplattingMaterial";
}
/**
* Parse a JSON input to create back a Gaussian Splatting material.
* @param source The JSON data to parse
* @param scene The scene to create the parsed material in
* @param rootUrl The root url of the assets the material depends upon
* @returns the instantiated GaussianSplattingMaterial.
*/
static Parse(source, scene, rootUrl) {
return SerializationHelper.Parse(() => new GaussianSplattingMaterial(source.name, scene), source, scene, rootUrl);
}
}
/**
* Point spread function (default 0.3). Can be overriden per GS material
*/
GaussianSplattingMaterial.KernelSize = 0.3;
/**
* Compensation
*/
GaussianSplattingMaterial.Compensation = false;
RegisterClass("BABYLON.GaussianSplattingMaterial", GaussianSplattingMaterial);
/* eslint-disable @typescript-eslint/naming-convention */
const HCF = HighestCommonFactor;
/**
* Scalar computation library
*/
const Scalar = {
...functions,
/**
* Two pi constants convenient for computation.
*/
TwoPi: Math.PI * 2,
/**
* Returns -1 if value is negative and +1 is value is positive.
* @param value the value
* @returns the value itself if it's equal to zero.
*/
Sign: Math.sign,
/**
* the log2 of value.
* @param value the value to compute log2 of
* @returns the log2 of value.
*/
Log2: Math.log2,
/**
* Returns the highest common factor of two integers.
* @param a first parameter
* @param b second parameter
* @returns HCF of a and b
*/
HCF,
};
/* eslint-enable @typescript-eslint/naming-convention */
// @internal
const UnpackUnorm = (value, bits) => {
const t = (1 << bits) - 1;
return (value & t) / t;
};
// @internal
const Unpack111011 = (value, result) => {
result.x = UnpackUnorm(value >>> 21, 11);
result.y = UnpackUnorm(value >>> 11, 10);
result.z = UnpackUnorm(value, 11);
};
// @internal
const Unpack8888 = (value, result) => {
result[0] = UnpackUnorm(value >>> 24, 8) * 255;
result[1] = UnpackUnorm(value >>> 16, 8) * 255;
result[2] = UnpackUnorm(value >>> 8, 8) * 255;
result[3] = UnpackUnorm(value, 8) * 255;
};
// @internal
// unpack quaternion with 2,10,10,10 format (largest element, 3x10bit element)
const UnpackRot = (value, result) => {
const norm = 1.0 / (Math.sqrt(2) * 0.5);
const a = (UnpackUnorm(value >>> 20, 10) - 0.5) * norm;
const b = (UnpackUnorm(value >>> 10, 10) - 0.5) * norm;
const c = (UnpackUnorm(value, 10) - 0.5) * norm;
const m = Math.sqrt(1.0 - (a * a + b * b + c * c));
switch (value >>> 30) {
case 0:
result.set(m, a, b, c);
break;
case 1:
result.set(a, m, b, c);
break;
case 2:
result.set(a, b, m, c);
break;
case 3:
result.set(a, b, c, m);
break;
}
};
/**
* Representation of the types
*/
var PLYType;
(function (PLYType) {
PLYType[PLYType["FLOAT"] = 0] = "FLOAT";
PLYType[PLYType["INT"] = 1] = "INT";
PLYType[PLYType["UINT"] = 2] = "UINT";
PLYType[PLYType["DOUBLE"] = 3] = "DOUBLE";
PLYType[PLYType["UCHAR"] = 4] = "UCHAR";
PLYType[PLYType["UNDEFINED"] = 5] = "UNDEFINED";
})(PLYType || (PLYType = {}));
/**
* Usage types of the PLY values
*/
var PLYValue;
(function (PLYValue) {
PLYValue[PLYValue["MIN_X"] = 0] = "MIN_X";
PLYValue[PLYValue["MIN_Y"] = 1] = "MIN_Y";
PLYValue[PLYValue["MIN_Z"] = 2] = "MIN_Z";
PLYValue[PLYValue["MAX_X"] = 3] = "MAX_X";
PLYValue[PLYValue["MAX_Y"] = 4] = "MAX_Y";
PLYValue[PLYValue["MAX_Z"] = 5] = "MAX_Z";
PLYValue[PLYValue["MIN_SCALE_X"] = 6] = "MIN_SCALE_X";
PLYValue[PLYValue["MIN_SCALE_Y"] = 7] = "MIN_SCALE_Y";
PLYValue[PLYValue["MIN_SCALE_Z"] = 8] = "MIN_SCALE_Z";
PLYValue[PLYValue["MAX_SCALE_X"] = 9] = "MAX_SCALE_X";
PLYValue[PLYValue["MAX_SCALE_Y"] = 10] = "MAX_SCALE_Y";
PLYValue[PLYValue["MAX_SCALE_Z"] = 11] = "MAX_SCALE_Z";
PLYValue[PLYValue["PACKED_POSITION"] = 12] = "PACKED_POSITION";
PLYValue[PLYValue["PACKED_ROTATION"] = 13] = "PACKED_ROTATION";
PLYValue[PLYValue["PACKED_SCALE"] = 14] = "PACKED_SCALE";
PLYValue[PLYValue["PACKED_COLOR"] = 15] = "PACKED_COLOR";
PLYValue[PLYValue["X"] = 16] = "X";
PLYValue[PLYValue["Y"] = 17] = "Y";
PLYValue[PLYValue["Z"] = 18] = "Z";
PLYValue[PLYValue["SCALE_0"] = 19] = "SCALE_0";
PLYValue[PLYValue["SCALE_1"] = 20] = "SCALE_1";
PLYValue[PLYValue["SCALE_2"] = 21] = "SCALE_2";
PLYValue[PLYValue["DIFFUSE_RED"] = 22] = "DIFFUSE_RED";
PLYValue[PLYValue["DIFFUSE_GREEN"] = 23] = "DIFFUSE_GREEN";
PLYValue[PLYValue["DIFFUSE_BLUE"] = 24] = "DIFFUSE_BLUE";
PLYValue[PLYValue["OPACITY"] = 25] = "OPACITY";
PLYValue[PLYValue["F_DC_0"] = 26] = "F_DC_0";
PLYValue[PLYValue["F_DC_1"] = 27] = "F_DC_1";
PLYValue[PLYValue["F_DC_2"] = 28] = "F_DC_2";
PLYValue[PLYValue["F_DC_3"] = 29] = "F_DC_3";
PLYValue[PLYValue["ROT_0"] = 30] = "ROT_0";
PLYValue[PLYValue["ROT_1"] = 31] = "ROT_1";
PLYValue[PLYValue["ROT_2"] = 32] = "ROT_2";
PLYValue[PLYValue["ROT_3"] = 33] = "ROT_3";
PLYValue[PLYValue["MIN_COLOR_R"] = 34] = "MIN_COLOR_R";
PLYValue[PLYValue["MIN_COLOR_G"] = 35] = "MIN_COLOR_G";
PLYValue[PLYValue["MIN_COLOR_B"] = 36] = "MIN_COLOR_B";
PLYValue[PLYValue["MAX_COLOR_R"] = 37] = "MAX_COLOR_R";
PLYValue[PLYValue["MAX_COLOR_G"] = 38] = "MAX_COLOR_G";
PLYValue[PLYValue["MAX_COLOR_B"] = 39] = "MAX_COLOR_B";
PLYValue[PLYValue["SH_0"] = 40] = "SH_0";
PLYValue[PLYValue["SH_1"] = 41] = "SH_1";
PLYValue[PLYValue["SH_2"] = 42] = "SH_2";
PLYValue[PLYValue["SH_3"] = 43] = "SH_3";
PLYValue[PLYValue["SH_4"] = 44] = "SH_4";
PLYValue[PLYValue["SH_5"] = 45] = "SH_5";
PLYValue[PLYValue["SH_6"] = 46] = "SH_6";
PLYValue[PLYValue["SH_7"] = 47] = "SH_7";
PLYValue[PLYValue["SH_8"] = 48] = "SH_8";
PLYValue[PLYValue["SH_9"] = 49] = "SH_9";
PLYValue[PLYValue["SH_10"] = 50] = "SH_10";
PLYValue[PLYValue["SH_11"] = 51] = "SH_11";
PLYValue[PLYValue["SH_12"] = 52] = "SH_12";
PLYValue[PLYValue["SH_13"] = 53] = "SH_13";
PLYValue[PLYValue["SH_14"] = 54] = "SH_14";
PLYValue[PLYValue["SH_15"] = 55] = "SH_15";
PLYValue[PLYValue["SH_16"] = 56] = "SH_16";
PLYValue[PLYValue["SH_17"] = 57] = "SH_17";
PLYValue[PLYValue["SH_18"] = 58] = "SH_18";
PLYValue[PLYValue["SH_19"] = 59] = "SH_19";
PLYValue[PLYValue["SH_20"] = 60] = "SH_20";
PLYValue[PLYValue["SH_21"] = 61] = "SH_21";
PLYValue[PLYValue["SH_22"] = 62] = "SH_22";
PLYValue[PLYValue["SH_23"] = 63] = "SH_23";
PLYValue[PLYValue["SH_24"] = 64] = "SH_24";
PLYValue[PLYValue["SH_25"] = 65] = "SH_25";
PLYValue[PLYValue["SH_26"] = 66] = "SH_26";
PLYValue[PLYValue["SH_27"] = 67] = "SH_27";
PLYValue[PLYValue["SH_28"] = 68] = "SH_28";
PLYValue[PLYValue["SH_29"] = 69] = "SH_29";
PLYValue[PLYValue["SH_30"] = 70] = "SH_30";
PLYValue[PLYValue["SH_31"] = 71] = "SH_31";
PLYValue[PLYValue["SH_32"] = 72] = "SH_32";
PLYValue[PLYValue["SH_33"] = 73] = "SH_33";
PLYValue[PLYValue["SH_34"] = 74] = "SH_34";
PLYValue[PLYValue["SH_35"] = 75] = "SH_35";
PLYValue[PLYValue["SH_36"] = 76] = "SH_36";
PLYValue[PLYValue["SH_37"] = 77] = "SH_37";
PLYValue[PLYValue["SH_38"] = 78] = "SH_38";
PLYValue[PLYValue["SH_39"] = 79] = "SH_39";
PLYValue[PLYValue["SH_40"] = 80] = "SH_40";
PLYValue[PLYValue["SH_41"] = 81] = "SH_41";
PLYValue[PLYValue["SH_42"] = 82] = "SH_42";
PLYValue[PLYValue["SH_43"] = 83] = "SH_43";
PLYValue[PLYValue["SH_44"] = 84] = "SH_44";
PLYValue[PLYValue["UNDEFINED"] = 85] = "UNDEFINED";
})(PLYValue || (PLYValue = {}));
/**
* Class used to render a gaussian splatting mesh
*/
class GaussianSplattingMesh extends Mesh {
/**
* View direction factor used to compute the SH view direction in the shader.
*/
get viewDirectionFactor() {
return this._viewDirectionFactor;
}
/**
* SH degree. 0 = no sh (default). 1 = 3 parameters. 2 = 8 parameters. 3 = 15 parameters.
*/
get shDegree() {
return this._shDegree;
}
/**
* returns the splats data array buffer that contains in order : postions (3 floats), size (3 floats), color (4 bytes), orientation quaternion (4 bytes)
*/
get splatsData() {
return this._splatsData;
}
/**
* Gets the covariancesA texture
*/
get covariancesATexture() {
return this._covariancesATexture;
}
/**
* Gets the covariancesB texture
*/
get covariancesBTexture() {
return this._covariancesBTexture;
}
/**
* Gets the centers texture
*/
get centersTexture() {
return this._centersTexture;
}
/**
* Gets the colors texture
*/
get colorsTexture() {
return this._colorsTexture;
}
/**
* Gets the SH textures
*/
get shTextures() {
return this._shTextures;
}
/**
* set rendering material
*/
set material(value) {
this._material = value;
this._material.backFaceCulling = true;
this._material.cullBackFaces = false;
value.resetDrawCache();
}
/**
* get rendering material
*/
get material() {
return this._material;
}
/**
* Creates a new gaussian splatting mesh
* @param name defines the name of the mesh
* @param url defines the url to load from (optional)
* @param scene defines the hosting scene (optional)
* @param keepInRam keep datas in ram for editing purpose
*/
constructor(name, url = null, scene = null, keepInRam = false) {
super(name, scene);
this._vertexCount = 0;
this._worker = null;
this._frameIdLastUpdate = -1;
this._modelViewMatrix = Matrix.Identity();
this._canPostToWorker = true;
this._readyToDisplay = false;
this._covariancesATexture = null;
this._covariancesBTexture = null;
this._centersTexture = null;
this._colorsTexture = null;
this._splatPositions = null;
this._splatIndex = null;
this._shTextures = null;
this._splatsData = null;
this._sh = null;
this._keepInRam = false;
this._delayedTextureUpdate = null;
this._oldDirection = new Vector3();
this._useRGBACovariants = false;
this._material = null;
this._tmpCovariances = [0, 0, 0, 0, 0, 0];
this._sortIsDirty = false;
this._shDegree = 0;
this._viewDirectionFactor = new Vector3(1, 1, -1);
const vertexData = new VertexData();
// Use an intanced quad or triangle. Triangle might be a bit faster because of less shader invocation but I didn't see any difference.
// Keeping both and use triangle for now.
// for quad, use following lines
//vertexData.positions = [-2, -2, 0, 2, -2, 0, 2, 2, 0, -2, 2, 0];
//vertexData.indices = [0, 1, 2, 0, 2, 3];
vertexData.positions = [-3, -2, 0, 3, -2, 0, 0, 4, 0];
vertexData.indices = [0, 1, 2];
vertexData.applyToMesh(this);
this.subMeshes = [];
// for quad, use following line
//new SubMesh(0, 0, 4, 0, 6, this);
new SubMesh(0, 0, 3, 0, 3, this);
this.setEnabled(false);
// webGL2 and webGPU support for RG texture with float16 is fine. not webGL1
this._useRGBACovariants = !this.getEngine().isWebGPU && this.getEngine().version === 1.0;
this._keepInRam = keepInRam;
if (url) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.loadFileAsync(url);
}
this._material = new GaussianSplattingMaterial(this.name + "_material", this._scene);
}
/**
* Returns the class name
* @returns "GaussianSplattingMesh"
*/
getClassName() {
return "GaussianSplattingMesh";
}
/**
* Returns the total number of vertices (splats) within the mesh
* @returns the total number of vertices
*/
getTotalVertices() {
return this._vertexCount;
}
/**
* Is this node ready to be used/rendered
* @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
* @returns true when ready
*/
isReady(completeCheck = false) {
if (!super.isReady(completeCheck, true)) {
return false;
}
if (!this._readyToDisplay) {
// mesh is ready when worker has done at least 1 sorting
this._postToWorker(true);
return false;
}
return true;
}
/** @internal */
_postToWorker(forced = false) {
const frameId = this.getScene().getFrameId();
if ((forced || frameId !== this._frameIdLastUpdate) && this._worker && this._scene.activeCamera && this._canPostToWorker) {
const cameraMatrix = this._scene.activeCamera.getViewMatrix();
this.getWorldMatrix().multiplyToRef(cameraMatrix, this._modelViewMatrix);
cameraMatrix.invertToRef(TmpVectors.Matrix[0]);
this.getWorldMatrix().multiplyToRef(TmpVectors.Matrix[0], TmpVectors.Matrix[1]);
Vector3.TransformNormalToRef(Vector3.Forward(this._scene.useRightHandedSystem), TmpVectors.Matrix[1], TmpVectors.Vector3[2]);
TmpVectors.Vector3[2].normalize();
const dot = Vector3.Dot(TmpVectors.Vector3[2], this._oldDirection);
if (forced || Math.abs(dot - 1) >= 0.01) {
this._oldDirection.copyFrom(TmpVectors.Vector3[2]);
this._frameIdLastUpdate = frameId;
this._canPostToWorker = false;
this._worker.postMessage({ view: this._modelViewMatrix.m, depthMix: this._depthMix, useRightHandedSystem: this._scene.useRightHandedSystem }, [
this._depthMix.buffer,
]);
}
}
}
/**
* Triggers the draw call for the mesh. Usually, you don't need to call this method by your own because the mesh rendering is handled by the scene rendering manager
* @param subMesh defines the subMesh to render
* @param enableAlphaMode defines if alpha mode can be changed
* @param effectiveMeshReplacement defines an optional mesh used to provide info for the rendering
* @returns the current mesh
*/
render(subMesh, enableAlphaMode, effectiveMeshReplacement) {
this._postToWorker();
return super.render(subMesh, enableAlphaMode, effectiveMeshReplacement);
}
static _TypeNameToEnum(name) {
switch (name) {
case "float":
return 0 /* PLYType.FLOAT */;
case "int":
return 1 /* PLYType.INT */;
case "uint":
return 2 /* PLYType.UINT */;
case "double":
return 3 /* PLYType.DOUBLE */;
case "uchar":
return 4 /* PLYType.UCHAR */;
}
return 5 /* PLYType.UNDEFINED */;
}
static _ValueNameToEnum(name) {
switch (name) {
case "min_x":
return 0 /* PLYValue.MIN_X */;
case "min_y":
return 1 /* PLYValue.MIN_Y */;
case "min_z":
return 2 /* PLYValue.MIN_Z */;
case "max_x":
return 3 /* PLYValue.MAX_X */;
case "max_y":
return 4 /* PLYValue.MAX_Y */;
case "max_z":
return 5 /* PLYValue.MAX_Z */;
case "min_scale_x":
return 6 /* PLYValue.MIN_SCALE_X */;
case "min_scale_y":
return 7 /* PLYValue.MIN_SCALE_Y */;
case "min_scale_z":
return 8 /* PLYValue.MIN_SCALE_Z */;
case "max_scale_x":
return 9 /* PLYValue.MAX_SCALE_X */;
case "max_scale_y":
return 10 /* PLYValue.MAX_SCALE_Y */;
case "max_scale_z":
return 11 /* PLYValue.MAX_SCALE_Z */;
case "packed_position":
return 12 /* PLYValue.PACKED_POSITION */;
case "packed_rotation":
return 13 /* PLYValue.PACKED_ROTATION */;
case "packed_scale":
return 14 /* PLYValue.PACKED_SCALE */;
case "packed_color":
return 15 /* PLYValue.PACKED_COLOR */;
case "x":
return 16 /* PLYValue.X */;
case "y":
return 17 /* PLYValue.Y */;
case "z":
return 18 /* PLYValue.Z */;
case "scale_0":
return 19 /* PLYValue.SCALE_0 */;
case "scale_1":
return 20 /* PLYValue.SCALE_1 */;
case "scale_2":
return 21 /* PLYValue.SCALE_2 */;
case "diffuse_red":
case "red":
return 22 /* PLYValue.DIFFUSE_RED */;
case "diffuse_green":
case "green":
return 23 /* PLYValue.DIFFUSE_GREEN */;
case "diffuse_blue":
case "blue":
return 24 /* PLYValue.DIFFUSE_BLUE */;
case "f_dc_0":
return 26 /* PLYValue.F_DC_0 */;
case "f_dc_1":
return 27 /* PLYValue.F_DC_1 */;
case "f_dc_2":
return 28 /* PLYValue.F_DC_2 */;
case "f_dc_3":
return 29 /* PLYValue.F_DC_3 */;
case "opacity":
return 25 /* PLYValue.OPACITY */;
case "rot_0":
return 30 /* PLYValue.ROT_0 */;
case "rot_1":
return 31 /* PLYValue.ROT_1 */;
case "rot_2":
return 32 /* PLYValue.ROT_2 */;
case "rot_3":
return 33 /* PLYValue.ROT_3 */;
case "min_r":
return 34 /* PLYValue.MIN_COLOR_R */;
case "min_g":
return 35 /* PLYValue.MIN_COLOR_G */;