@speridlabs/visus 0.3.0 → 1.0.0

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/dist/main.umd.js CHANGED
@@ -1,5 +1,5 @@
1
- (function(C,_){typeof exports=="object"&&typeof module<"u"?_(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],_):(C=typeof globalThis<"u"?globalThis:C||self,_(C.Visus={},C.THREE))})(this,function(C,_){"use strict";var Mt=Object.defineProperty;var zt=(C,_,j)=>_ in C?Mt(C,_,{enumerable:!0,configurable:!0,writable:!0,value:j}):C[_]=j;var f=(C,_,j)=>zt(C,typeof _!="symbol"?_+"":_,j);if(typeof THREE>"u")throw new Error(`Visus UMD build requires Three.js as a global "THREE".
2
- Please include <script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"><\/script> before loading visus/main.umd.js`);function j(B){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(B){for(const r in B)if(r!=="default"){const e=Object.getOwnPropertyDescriptor(B,r);Object.defineProperty(t,r,e.get?e:{enumerable:!0,get:()=>B[r]})}}return t.default=B,Object.freeze(t)}const o=j(_);class X{constructor(){f(this,"min",new o.Vector3(1/0,1/0,1/0));f(this,"max",new o.Vector3(-1/0,-1/0,-1/0));f(this,"center",new o.Vector3);f(this,"halfExtents",new o.Vector3)}reset(){this.min.set(1/0,1/0,1/0),this.max.set(-1/0,-1/0,-1/0),this.center.set(0,0,0),this.halfExtents.set(0,0,0)}expandByPoint(t){this.min.x=Math.min(this.min.x,t.x),this.min.y=Math.min(this.min.y,t.y),this.min.z=Math.min(this.min.z,t.z),this.max.x=Math.max(this.max.x,t.x),this.max.y=Math.max(this.max.y,t.y),this.max.z=Math.max(this.max.z,t.z),this.updateDerived()}expandByBox(t){this.min.x=Math.min(this.min.x,t.min.x),this.min.y=Math.min(this.min.y,t.min.y),this.min.z=Math.min(this.min.z,t.min.z),this.max.x=Math.max(this.max.x,t.max.x),this.max.y=Math.max(this.max.y,t.max.y),this.max.z=Math.max(this.max.z,t.max.z),this.updateDerived()}updateDerived(){this.center.addVectors(this.min,this.max).multiplyScalar(.5),this.halfExtents.subVectors(this.max,this.min).multiplyScalar(.5)}containsPoint(t){return t.x>=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y&&t.z>=this.min.z&&t.z<=this.max.z}toBox3(){return new o.Box3().set(this.min,this.max)}clone(){const t=new X;return t.min.copy(this.min),t.max.copy(this.max),t.center.copy(this.center),t.halfExtents.copy(this.halfExtents),t}}class it{constructor(t=0){f(this,"numSplats",0);f(this,"positions");f(this,"rotations");f(this,"scales");f(this,"colors");f(this,"opacities");f(this,"centers");f(this,"boundingBox",new X);this.numSplats=t,this.allocateBuffers(t)}allocateBuffers(t){this.positions=new Float32Array(t*3),this.rotations=new Float32Array(t*4),this.scales=new Float32Array(t*3),this.colors=new Float32Array(t*3),this.opacities=new Float32Array(t),this.centers=new Float32Array(t*3)}setSplat(t,r,e,n,s,i){if(t>=this.numSplats)throw new Error(`Splat index out of bounds: ${t} >= ${this.numSplats}`);const a=t*3,c=t*4,h=t*3,v=t*3;this.positions[a]=r.x,this.positions[a+1]=r.y,this.positions[a+2]=r.z,this.rotations[c]=e.x,this.rotations[c+1]=e.y,this.rotations[c+2]=e.z,this.rotations[c+3]=e.w,this.scales[h]=n.x,this.scales[h+1]=n.y,this.scales[h+2]=n.z,this.colors[v]=s.r,this.colors[v+1]=s.g,this.colors[v+2]=s.b,this.opacities[t]=i,this.centers[a]=r.x,this.centers[a+1]=r.y,this.centers[a+2]=r.z}getSplat(t){if(t>=this.numSplats)throw new Error(`Splat index out of bounds: ${t} >= ${this.numSplats}`);const r=t*3,e=t*4,n=t*3,s=t*3;return{position:new o.Vector3(this.positions[r],this.positions[r+1],this.positions[r+2]),rotation:new o.Quaternion(this.rotations[e],this.rotations[e+1],this.rotations[e+2],this.rotations[e+3]),scale:new o.Vector3(Math.exp(this.scales[n]),Math.exp(this.scales[n+1]),Math.exp(this.scales[n+2])),color:new o.Color(this.colors[s],this.colors[s+1],this.colors[s+2]),opacity:this.opacities[t]}}calculateBoundingBox(){this.boundingBox.reset();const t=new o.Vector3;for(let r=0;r<this.numSplats;r++){const e=r*3;t.set(this.positions[e],this.positions[e+1],this.positions[e+2]),this.boundingBox.expandByPoint(t)}return this.boundingBox}createDebugGeometry(){const t=new o.BufferGeometry;t.setAttribute("position",new o.BufferAttribute(this.positions,3));const r=new Float32Array(this.numSplats*3),e=new o.Quaternion,n=new o.Euler;for(let s=0;s<this.numSplats;s++){const i=s*4,a=s*3;e.set(this.rotations[i],this.rotations[i+1],this.rotations[i+2],this.rotations[i+3]),n.setFromQuaternion(e),r[a]=n.x,r[a+1]=n.y,r[a+2]=n.z}return t.setAttribute("rotation",new o.BufferAttribute(r,3)),t.setAttribute("scale",new o.BufferAttribute(this.scales,3)),t.setAttribute("color",new o.BufferAttribute(this.colors,3)),t.setAttribute("opacity",new o.BufferAttribute(this.opacities,1)),t}}class at extends o.EventDispatcher{constructor(){super();f(this,"worker");f(this,"centers",null);f(this,"orderTexture",null);f(this,"chunks",null);f(this,"lastCameraPosition",new o.Vector3);f(this,"lastCameraDirection",new o.Vector3);const r=this.createWorkerCode(),e=new Blob([r],{type:"application/javascript"});this.worker=new Worker(URL.createObjectURL(e)),this.worker.onmessage=this.onWorkerMessage.bind(this)}onWorkerMessage(r){if(!this.orderTexture||!this.orderTexture.image)return console.error("SplatSorter: Order texture not initialized!");const{order:e,count:n}=r.data,s=this.orderTexture.image.data;if(!(s instanceof Uint32Array))return console.error("SplatSorter: Order texture data is not a Uint32Array!");s.set(new Uint32Array(e)),this.orderTexture.needsUpdate=!0;const i=s.buffer.slice(0),a={order:i};this.worker.postMessage(a,[i]),this.dispatchEvent({type:"updated",count:n})}init(r,e,n){if(!r||!(r.image.data instanceof Uint32Array))throw new Error("SplatSorter: Invalid orderTexture provided. Must be DataTexture with Uint32Array data.");if(!e||e.length%3!==0)throw new Error("SplatSorter: Invalid centers array provided. Length must be multiple of 3.");if(r.image.data.length<e.length/3)throw new Error("SplatSorter: orderTexture data buffer is smaller than the number of splats.");const s=e.length/3;this.orderTexture=r,this.centers=e.slice();const i=this.orderTexture.image.data;for(let g=0;g<s;g++)i[g]=g;this.orderTexture.needsUpdate=!0;const a=i.buffer.slice(0),c=this.centers.buffer.slice(0),h={order:a,centers:c},v=[a,c];if(n){this.chunks=n.slice();const g=this.chunks.buffer.slice(0);h.chunks=g,v.push(g)}this.worker.postMessage(h,v)}setMapping(r){if(!this.centers)return console.warn("SplatSorter: Cannot set mapping before initialization.");let e;const n=[];if(!r){const c=this.centers.buffer.slice(0);return e={centers:c,mapping:null},n.push(c),this.worker.postMessage(e,n)}const s=new Float32Array(r.length*3);for(let c=0;c<r.length;c++){const h=r[c];if(h*3+2>=this.centers.length){console.warn(`SplatSorter: Mapping index ${h} out of bounds.`);continue}const v=h*3,g=c*3;s[g+0]=this.centers[v+0],s[g+1]=this.centers[v+1],s[g+2]=this.centers[v+2]}const i=s.buffer.slice(0),a=r.buffer.slice(0);e={centers:i,mapping:a},n.push(i,a),this.worker.postMessage(e,n)}setCamera(r,e){const n=this.lastCameraPosition.distanceToSquared(r)>1e-7,s=this.lastCameraDirection.dot(e)<.9999;if(!n&&!s)return;this.lastCameraPosition.copy(r),this.lastCameraDirection.copy(e);const i={cameraPosition:{x:r.x,y:r.y,z:r.z},cameraDirection:{x:e.x,y:e.y,z:e.z}};this.worker.postMessage(i)}dispose(){this.worker&&this.worker.terminate(),this.orderTexture=null,this.centers=null,this.chunks=null}createWorkerCode(){return`(${(function(){let e=null,n=null,s=null,i=null,a=null,c=null,h=!1;const v={x:0,y:0,z:0},g={x:0,y:0,z:0},p={x:0,y:0,z:0},u={x:0,y:0,z:0};let l=null,b=null;const A=32,q=new Array(A).fill(0),W=new Array(A).fill(0),R=new Array(A).fill(0),H=(V,z,D)=>{for(;V<=z;){const M=z+V>>1,m=D(M);if(m>0)V=M+1;else if(m<0)z=M-1;else return M}return~V},N=()=>{if(!e||!n||!a||!c)return;if(n.length===0){const y={order:e.buffer,count:0};self.postMessage(y,[e.buffer]),e=null;return}const V=a.x,z=a.y,D=a.z,M=c.x,m=c.y,F=c.z,O=1e-4,P=Math.abs(V-v.x)>O||Math.abs(z-v.y)>O||Math.abs(D-v.z)>O,x=Math.abs(M-g.x)>O||Math.abs(m-g.y)>O||Math.abs(F-g.z)>O;if(!h&&!P&&!x)return;h=!1,v.x=V,v.y=z,v.z=D,g.x=M,g.y=m,g.z=F;let d=1/0,S=-1/0;for(let y=0;y<8;++y){const k=y&1?p.x:u.x,E=y&2?p.y:u.y,w=y&4?p.z:u.z,U=k*M+E*m+w*F;d=Math.min(d,U),S=Math.max(S,U)}const T=n.length/3,Y=S-d,I=(1<<Math.max(10,Math.min(20,Math.ceil(Math.log2(T/4)))))+1;if((!l||l.length!==T)&&(l=new Uint32Array(T)),!b||b.length!==I?b=new Uint32Array(I):b.fill(0),Y<1e-7){for(let y=0;y<T;++y)l[y]=0;b[0]=T}else if(s&&s.length>0){const y=s.length/6;q.fill(0);for(let w=0;w<y;++w){const U=w*6,J=s[U+0],K=s[U+1],tt=s[U+2],G=s[U+3],Z=J*M+K*m+tt*F-d,et=Z-G,Q=Z+G,nt=Math.max(0,Math.floor(et*A/Y)),ot=Math.min(A,Math.ceil(Q*A/Y));for(let $=nt;$<ot;++$)q[$]++}let k=0;for(let w=0;w<A;++w)k+=q[w];R[0]=0,W[0]=0;for(let w=1;w<A;++w)R[w-1]=q[w-1]/k*I>>>0,W[w]=W[w-1]+R[w-1];R[A-1]=q[A-1]/k*I>>>0;const E=Y/A;for(let w=0;w<T;++w){const U=w*3,J=n[U+0],K=n[U+1],tt=n[U+2],G=J*M+K*m+tt*F,et=(S-G)/E,Q=Math.max(0,Math.min(A-1,Math.floor(et))),nt=et-Q,ot=W[Q]+R[Q]*nt>>>0,$=Math.min(ot,I-1);l[w]=$,b[$]++}}else{const y=(I-1)/Y;for(let k=0;k<T;++k){const E=k*3,w=n[E+0],U=n[E+1],J=n[E+2],K=w*M+U*m+J*F,G=(S-K)*y>>>0,Z=Math.min(G,I-1);l[k]=Z,b[Z]++}}for(let y=1;y<I;y++)b[y]+=b[y-1];for(let y=T-1;y>=0;y--){const k=l[y],E=--b[k];e[E]=i?i[y]:y}const wt=V*M+z*m+D*F,ut=y=>{if(!e)return-1/0;const k=e[y],E=k;if(!n||E*3+2>=n.length)return-1/0;const w=E*3;return n[w]*M+n[w+1]*m+n[w+2]*F-wt};let dt=T;if(T>0&&ut(T-1)<0){const y=H(0,T-1,ut);dt=y<0?~y:y}const bt={order:e.buffer,count:dt};self.postMessage(bt,[e.buffer]),e=null};self.onmessage=V=>{const z=V.data;z.order&&(e=new Uint32Array(z.order));let D=!1;if(z.centers&&(n=new Float32Array(z.centers),D=!0,h=!0),Object.prototype.hasOwnProperty.call(z,"mapping")&&(i=z.mapping?new Uint32Array(z.mapping):null,h=!0),z.chunks){if(s=new Float32Array(z.chunks),s.length>0&&s[3]>0)for(let M=0;M<s.length/6;++M){const m=M*6,F=s[m+0],O=s[m+1],P=s[m+2],x=s[m+3],d=s[m+4],S=s[m+5];s[m+0]=(F+x)*.5,s[m+1]=(O+d)*.5,s[m+2]=(P+S)*.5,s[m+3]=Math.sqrt((x-F)**2+(d-O)**2+(S-P)**2)*.5}h=!0}if(D&&n&&n.length>0){p.x=u.x=n[0],p.y=u.y=n[1],p.z=u.z=n[2];for(let M=1;M<n.length/3;M++){const m=M*3;p.x=Math.min(p.x,n[m+0]),u.x=Math.max(u.x,n[m+0]),p.y=Math.min(p.y,n[m+1]),u.y=Math.max(u.y,n[m+1]),p.z=Math.min(p.z,n[m+2]),u.z=Math.max(u.z,n[m+2])}}else D&&n&&n.length===0&&(p.x=u.x=p.y=u.y=p.z=u.z=0);z.cameraPosition&&(a=z.cameraPosition),z.cameraDirection&&(c=z.cameraDirection),N()}}).toString()})();`}}const ft=(B,t)=>{const r=Math.max(0,Math.min(65535,Math.round((B+1)/2*65535))),e=Math.max(0,Math.min(65535,Math.round((t+1)/2*65535)));return r<<16|e},pt=new ArrayBuffer(4),ct=new DataView(pt),mt=B=>(ct.setUint32(0,B,!0),ct.getFloat32(0,!0));class lt{constructor(t){f(this,"transformA");f(this,"transformB");f(this,"colorTexture");f(this,"orderTexture");f(this,"textureWidth");f(this,"textureHeight");const r=t.numSplats;this.textureWidth=Math.ceil(Math.sqrt(r)),this.textureHeight=Math.ceil(r/this.textureWidth),this.transformA=this.createTransformATexture(t),this.transformB=this.createTransformBTexture(t),this.colorTexture=this.createColorTexture(t),this.orderTexture=this.createOrderTexture(r)}createTransformATexture(t){const r=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let s=0;s<r;s++){const i=s*4,a=s*3,c=s*4;e[i]=t.positions[a],e[i+1]=t.positions[a+1],e[i+2]=t.positions[a+2];const h=t.rotations[c+1],v=t.rotations[c+2],g=ft(h,v);e[i+3]=mt(g)}const n=new o.DataTexture(e,this.textureWidth,this.textureHeight,o.RGBAFormat,o.FloatType);return n.needsUpdate=!0,n.magFilter=o.NearestFilter,n.minFilter=o.NearestFilter,n}createTransformBTexture(t){const r=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let s=0;s<r;s++){const i=s*4,a=s*3,c=s*4;e[i]=t.scales[a],e[i+1]=t.scales[a+1],e[i+2]=t.scales[a+2],e[i+3]=t.rotations[c]}const n=new o.DataTexture(e,this.textureWidth,this.textureHeight,o.RGBAFormat,o.FloatType);return n.needsUpdate=!0,n.magFilter=o.NearestFilter,n.minFilter=o.NearestFilter,n}createColorTexture(t){const r=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let s=0;s<r;s++){const i=s*4,a=s*3;e[i]=t.colors[a],e[i+1]=t.colors[a+1],e[i+2]=t.colors[a+2],e[i+3]=t.opacities[s]}const n=new o.DataTexture(e,this.textureWidth,this.textureHeight,o.RGBAFormat,o.FloatType);return n.needsUpdate=!0,n}createOrderTexture(t){const r=new Uint32Array(this.textureWidth*this.textureHeight);for(let n=0;n<t;n++)r[n]=n;const e=new o.DataTexture(r,this.textureWidth,this.textureHeight,o.RedIntegerFormat,o.UnsignedIntType);return e.needsUpdate=!0,e}dispose(){this.transformA.dispose(),this.transformB.dispose(),this.colorTexture.dispose(),this.orderTexture.dispose()}}const xt=`
1
+ (function(I,D){typeof exports=="object"&&typeof module<"u"?D(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],D):(I=typeof globalThis<"u"?globalThis:I||self,D(I.Visus={},I.THREE))})(this,function(I,D){"use strict";var Ct=Object.defineProperty;var St=(I,D,L)=>D in I?Ct(I,D,{enumerable:!0,configurable:!0,writable:!0,value:L}):I[D]=L;var f=(I,D,L)=>St(I,typeof D!="symbol"?D+"":D,L);if(typeof THREE>"u")throw new Error(`Visus UMD build requires Three.js as a global "THREE".
2
+ Please include <script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"><\/script> before loading visus/main.umd.js`);function L(T){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(T){for(const n in T)if(n!=="default"){const e=Object.getOwnPropertyDescriptor(T,n);Object.defineProperty(t,n,e.get?e:{enumerable:!0,get:()=>T[n]})}}return t.default=T,Object.freeze(t)}const i=L(D);class Q{constructor(){f(this,"min",new i.Vector3(1/0,1/0,1/0));f(this,"max",new i.Vector3(-1/0,-1/0,-1/0));f(this,"center",new i.Vector3);f(this,"halfExtents",new i.Vector3)}reset(){this.min.set(1/0,1/0,1/0),this.max.set(-1/0,-1/0,-1/0),this.center.set(0,0,0),this.halfExtents.set(0,0,0)}expandByPoint(t){this.min.x=Math.min(this.min.x,t.x),this.min.y=Math.min(this.min.y,t.y),this.min.z=Math.min(this.min.z,t.z),this.max.x=Math.max(this.max.x,t.x),this.max.y=Math.max(this.max.y,t.y),this.max.z=Math.max(this.max.z,t.z),this.updateDerived()}expandByBox(t){this.min.x=Math.min(this.min.x,t.min.x),this.min.y=Math.min(this.min.y,t.min.y),this.min.z=Math.min(this.min.z,t.min.z),this.max.x=Math.max(this.max.x,t.max.x),this.max.y=Math.max(this.max.y,t.max.y),this.max.z=Math.max(this.max.z,t.max.z),this.updateDerived()}updateDerived(){this.center.addVectors(this.min,this.max).multiplyScalar(.5),this.halfExtents.subVectors(this.max,this.min).multiplyScalar(.5)}containsPoint(t){return t.x>=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y&&t.z>=this.min.z&&t.z<=this.max.z}toBox3(){return new i.Box3().set(this.min,this.max)}clone(){const t=new Q;return t.min.copy(this.min),t.max.copy(this.max),t.center.copy(this.center),t.halfExtents.copy(this.halfExtents),t}}class it{constructor(t=0){f(this,"numSplats",0);f(this,"positions");f(this,"rotations");f(this,"scales");f(this,"colors");f(this,"opacities");f(this,"centers");f(this,"boundingBox",new Q);this.numSplats=t,this.allocateBuffers(t)}allocateBuffers(t){this.positions=new Float32Array(t*3),this.rotations=new Float32Array(t*4),this.scales=new Float32Array(t*3),this.colors=new Float32Array(t*3),this.opacities=new Float32Array(t),this.centers=new Float32Array(t*3)}setSplat(t,n,e,r,s,o){if(t>=this.numSplats)throw new Error(`Splat index out of bounds: ${t} >= ${this.numSplats}`);const a=t*3,c=t*4,h=t*3,v=t*3;this.positions[a]=n.x,this.positions[a+1]=n.y,this.positions[a+2]=n.z,this.rotations[c]=e.x,this.rotations[c+1]=e.y,this.rotations[c+2]=e.z,this.rotations[c+3]=e.w,this.scales[h]=r.x,this.scales[h+1]=r.y,this.scales[h+2]=r.z,this.colors[v]=s.r,this.colors[v+1]=s.g,this.colors[v+2]=s.b,this.opacities[t]=o,this.centers[a]=n.x,this.centers[a+1]=n.y,this.centers[a+2]=n.z}getSplat(t){if(t>=this.numSplats)throw new Error(`Splat index out of bounds: ${t} >= ${this.numSplats}`);const n=t*3,e=t*4,r=t*3,s=t*3;return{position:new i.Vector3(this.positions[n],this.positions[n+1],this.positions[n+2]),rotation:new i.Quaternion(this.rotations[e],this.rotations[e+1],this.rotations[e+2],this.rotations[e+3]),scale:new i.Vector3(Math.exp(this.scales[r]),Math.exp(this.scales[r+1]),Math.exp(this.scales[r+2])),color:new i.Color(this.colors[s],this.colors[s+1],this.colors[s+2]),opacity:this.opacities[t]}}calculateBoundingBox(){this.boundingBox.reset();const t=new i.Vector3;for(let n=0;n<this.numSplats;n++){const e=n*3;t.set(this.positions[e],this.positions[e+1],this.positions[e+2]),this.boundingBox.expandByPoint(t)}return this.boundingBox}createDebugGeometry(){const t=new i.BufferGeometry;t.setAttribute("position",new i.BufferAttribute(this.positions,3));const n=new Float32Array(this.numSplats*3),e=new i.Quaternion,r=new i.Euler;for(let s=0;s<this.numSplats;s++){const o=s*4,a=s*3;e.set(this.rotations[o],this.rotations[o+1],this.rotations[o+2],this.rotations[o+3]),r.setFromQuaternion(e),n[a]=r.x,n[a+1]=r.y,n[a+2]=r.z}return t.setAttribute("rotation",new i.BufferAttribute(n,3)),t.setAttribute("scale",new i.BufferAttribute(this.scales,3)),t.setAttribute("color",new i.BufferAttribute(this.colors,3)),t.setAttribute("opacity",new i.BufferAttribute(this.opacities,1)),t}}class at extends i.EventDispatcher{constructor(){super();f(this,"worker");f(this,"centers",null);f(this,"orderTexture",null);f(this,"chunks",null);f(this,"lastCameraPosition",new i.Vector3);f(this,"lastCameraDirection",new i.Vector3);const n=this.createWorkerCode(),e=new Blob([n],{type:"application/javascript"});this.worker=new Worker(URL.createObjectURL(e)),this.worker.onmessage=this.onWorkerMessage.bind(this)}onWorkerMessage(n){if(!this.orderTexture||!this.orderTexture.image)return console.error("SplatSorter: Order texture not initialized!");const{order:e,count:r}=n.data,s=this.orderTexture.image.data;if(!(s instanceof Uint32Array))return console.error("SplatSorter: Order texture data is not a Uint32Array!");s.set(new Uint32Array(e)),this.orderTexture.needsUpdate=!0;const o=s.buffer.slice(0),a={order:o};this.worker.postMessage(a,[o]),this.dispatchEvent({type:"updated",count:r})}init(n,e,r){if(!n||!(n.image.data instanceof Uint32Array))throw new Error("SplatSorter: Invalid orderTexture provided. Must be DataTexture with Uint32Array data.");if(!e||e.length%3!==0)throw new Error("SplatSorter: Invalid centers array provided. Length must be multiple of 3.");if(n.image.data.length<e.length/3)throw new Error("SplatSorter: orderTexture data buffer is smaller than the number of splats.");const s=e.length/3;this.orderTexture=n,this.centers=e.slice();const o=this.orderTexture.image.data;for(let y=0;y<s;y++)o[y]=y;this.orderTexture.needsUpdate=!0;const a=o.buffer.slice(0),c=this.centers.buffer.slice(0),h={order:a,centers:c},v=[a,c];if(r){this.chunks=r.slice();const y=this.chunks.buffer.slice(0);h.chunks=y,v.push(y)}this.worker.postMessage(h,v)}setMapping(n){if(!this.centers)return console.warn("SplatSorter: Cannot set mapping before initialization.");let e;const r=[];if(!n){const c=this.centers.buffer.slice(0);return e={centers:c,mapping:null},r.push(c),this.worker.postMessage(e,r)}const s=new Float32Array(n.length*3);for(let c=0;c<n.length;c++){const h=n[c];if(h*3+2>=this.centers.length){console.warn(`SplatSorter: Mapping index ${h} out of bounds.`);continue}const v=h*3,y=c*3;s[y+0]=this.centers[v+0],s[y+1]=this.centers[v+1],s[y+2]=this.centers[v+2]}const o=s.buffer.slice(0),a=n.buffer.slice(0);e={centers:o,mapping:a},r.push(o,a),this.worker.postMessage(e,r)}setCamera(n,e){const r=this.lastCameraPosition.distanceToSquared(n)>1e-7,s=this.lastCameraDirection.dot(e)<.9999;if(!r&&!s)return;this.lastCameraPosition.copy(n),this.lastCameraDirection.copy(e);const o={cameraPosition:{x:n.x,y:n.y,z:n.z},cameraDirection:{x:e.x,y:e.y,z:e.z}};this.worker.postMessage(o)}dispose(){this.worker&&this.worker.terminate(),this.orderTexture=null,this.centers=null,this.chunks=null}createWorkerCode(){return`(${(function(){let e=null,r=null,s=null,o=null,a=null,c=null,h=!1;const v={x:0,y:0,z:0},y={x:0,y:0,z:0},p={x:0,y:0,z:0},u={x:0,y:0,z:0};let l=null,b=null;const k=32,q=new Array(k).fill(0),W=new Array(k).fill(0),R=new Array(k).fill(0),H=(P,S,V)=>{for(;P<=S;){const M=S+P>>1,m=V(M);if(m>0)P=M+1;else if(m<0)S=M-1;else return M}return~P},N=()=>{if(!e||!r||!a||!c)return;if(r.length===0){const g={order:e.buffer,count:0};self.postMessage(g,[e.buffer]),e=null;return}const P=a.x,S=a.y,V=a.z,M=c.x,m=c.y,C=c.z,O=1e-4,_=Math.abs(P-v.x)>O||Math.abs(S-v.y)>O||Math.abs(V-v.z)>O,x=Math.abs(M-y.x)>O||Math.abs(m-y.y)>O||Math.abs(C-y.z)>O;if(!h&&!_&&!x)return;h=!1,v.x=P,v.y=S,v.z=V,y.x=M,y.y=m,y.z=C;let d=1/0,z=-1/0;for(let g=0;g<8;++g){const F=g&1?p.x:u.x,U=g&2?p.y:u.y,w=g&4?p.z:u.z,E=F*M+U*m+w*C;d=Math.min(d,E),z=Math.max(z,E)}const B=r.length/3,Y=z-d,A=(1<<Math.max(10,Math.min(20,Math.ceil(Math.log2(B/4)))))+1;if((!l||l.length!==B)&&(l=new Uint32Array(B)),!b||b.length!==A?b=new Uint32Array(A):b.fill(0),Y<1e-7){for(let g=0;g<B;++g)l[g]=0;b[0]=B}else if(s&&s.length>0){const g=s.length/6;q.fill(0);for(let w=0;w<g;++w){const E=w*6,$=s[E+0],J=s[E+1],tt=s[E+2],Z=s[E+3],G=$*M+J*m+tt*C-d,et=G-Z,K=G+Z,nt=Math.max(0,Math.floor(et*k/Y)),ot=Math.min(k,Math.ceil(K*k/Y));for(let X=nt;X<ot;++X)q[X]++}let F=0;for(let w=0;w<k;++w)F+=q[w];R[0]=0,W[0]=0;for(let w=1;w<k;++w)R[w-1]=q[w-1]/F*A>>>0,W[w]=W[w-1]+R[w-1];R[k-1]=q[k-1]/F*A>>>0;const U=Y/k;for(let w=0;w<B;++w){const E=w*3,$=r[E+0],J=r[E+1],tt=r[E+2],Z=$*M+J*m+tt*C,et=(z-Z)/U,K=Math.max(0,Math.min(k-1,Math.floor(et))),nt=et-K,ot=W[K]+R[K]*nt>>>0,X=Math.min(ot,A-1);l[w]=X,b[X]++}}else{const g=(A-1)/Y;for(let F=0;F<B;++F){const U=F*3,w=r[U+0],E=r[U+1],$=r[U+2],J=w*M+E*m+$*C,Z=(z-J)*g>>>0,G=Math.min(Z,A-1);l[F]=G,b[G]++}}for(let g=1;g<A;g++)b[g]+=b[g-1];for(let g=B-1;g>=0;g--){const F=l[g],U=--b[F];e[U]=o?o[g]:g}const bt=P*M+S*m+V*C,dt=g=>{if(!e)return-1/0;const F=e[g],U=F;if(!r||U*3+2>=r.length)return-1/0;const w=U*3;return r[w]*M+r[w+1]*m+r[w+2]*C-bt};let ft=B;if(B>0&&dt(B-1)<0){const g=H(0,B-1,dt);ft=g<0?~g:g}const Mt={order:e.buffer,count:ft};self.postMessage(Mt,[e.buffer]),e=null};self.onmessage=P=>{const S=P.data;S.order&&(e=new Uint32Array(S.order));let V=!1;if(S.centers&&(r=new Float32Array(S.centers),V=!0,h=!0),Object.prototype.hasOwnProperty.call(S,"mapping")&&(o=S.mapping?new Uint32Array(S.mapping):null,h=!0),S.chunks){if(s=new Float32Array(S.chunks),s.length>0&&s[3]>0)for(let M=0;M<s.length/6;++M){const m=M*6,C=s[m+0],O=s[m+1],_=s[m+2],x=s[m+3],d=s[m+4],z=s[m+5];s[m+0]=(C+x)*.5,s[m+1]=(O+d)*.5,s[m+2]=(_+z)*.5,s[m+3]=Math.sqrt((x-C)**2+(d-O)**2+(z-_)**2)*.5}h=!0}if(V&&r&&r.length>0){p.x=u.x=r[0],p.y=u.y=r[1],p.z=u.z=r[2];for(let M=1;M<r.length/3;M++){const m=M*3;p.x=Math.min(p.x,r[m+0]),u.x=Math.max(u.x,r[m+0]),p.y=Math.min(p.y,r[m+1]),u.y=Math.max(u.y,r[m+1]),p.z=Math.min(p.z,r[m+2]),u.z=Math.max(u.z,r[m+2])}}else V&&r&&r.length===0&&(p.x=u.x=p.y=u.y=p.z=u.z=0);S.cameraPosition&&(a=S.cameraPosition),S.cameraDirection&&(c=S.cameraDirection),N()}}).toString()})();`}}const pt=(T,t)=>{const n=ct(T),e=ct(t);return n|e<<16};function ct(T){const t=new Float32Array([T]),e=new Int32Array(t.buffer)[0];let r=e>>16&32768,s=e>>12&2047;const o=e>>23&255;return o<103?r:o>142?(r|=31744,r|=(o===255?0:1)&&e&8388607,r):o<113?(s|=2048,r|=(s>>114-o)+(s>>113-o&1),r):(r|=o-112<<10|s>>1,r+=s&1,r)}const mt=new ArrayBuffer(4),lt=new DataView(mt),xt=T=>(lt.setUint32(0,T,!0),lt.getFloat32(0,!0));class ht{constructor(t){f(this,"transformA");f(this,"transformB");f(this,"colorTexture");f(this,"orderTexture");f(this,"textureWidth");f(this,"textureHeight");const n=t.numSplats;this.textureWidth=Math.ceil(Math.sqrt(n)),this.textureHeight=Math.ceil(n/this.textureWidth),this.transformA=this.createTransformATexture(t),this.transformB=this.createTransformBTexture(t),this.colorTexture=this.createColorTexture(t),this.orderTexture=this.createOrderTexture(n)}createTransformATexture(t){const n=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let s=0;s<n;s++){const o=s*4,a=s*3,c=s*4;e[o]=t.positions[a],e[o+1]=t.positions[a+1],e[o+2]=t.positions[a+2];const h=t.rotations[c+0],v=t.rotations[c+1],y=pt(h,v);e[o+3]=xt(y)}const r=new i.DataTexture(e,this.textureWidth,this.textureHeight,i.RGBAFormat,i.FloatType);return r.needsUpdate=!0,r.magFilter=i.NearestFilter,r.minFilter=i.NearestFilter,r}createTransformBTexture(t){const n=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let s=0;s<n;s++){const o=s*4,a=s*3,c=s*4;e[o]=t.scales[a],e[o+1]=t.scales[a+1],e[o+2]=t.scales[a+2],e[o+3]=t.rotations[c+2]}const r=new i.DataTexture(e,this.textureWidth,this.textureHeight,i.RGBAFormat,i.FloatType);return r.needsUpdate=!0,r.magFilter=i.NearestFilter,r.minFilter=i.NearestFilter,r}createColorTexture(t){const n=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let s=0;s<n;s++){const o=s*4,a=s*3;e[o]=t.colors[a],e[o+1]=t.colors[a+1],e[o+2]=t.colors[a+2],e[o+3]=t.opacities[s]}const r=new i.DataTexture(e,this.textureWidth,this.textureHeight,i.RGBAFormat,i.FloatType);return r.needsUpdate=!0,r}createOrderTexture(t){const n=new Uint32Array(this.textureWidth*this.textureHeight);for(let r=0;r<t;r++)n[r]=r;const e=new i.DataTexture(n,this.textureWidth,this.textureHeight,i.RedIntegerFormat,i.UnsignedIntType);return e.needsUpdate=!0,e}dispose(){this.transformA.dispose(),this.transformB.dispose(),this.colorTexture.dispose(),this.orderTexture.dispose()}}const gt=`
3
3
  precision highp float;
4
4
  precision highp int;
5
5
  precision highp usampler2D;
@@ -35,61 +35,53 @@ varying vec2 vUv; // For gaussian calculation in fragment shader
35
35
 
36
36
  // --- Helper Functions ---
37
37
 
38
- // Unpack two 16-bit floats (halfs) from a single 32-bit float (packed as uint bits)
39
- vec2 unpackHalf2x16FromFloat(float packedFloat) {
40
- uint packedUInt = floatBitsToUint(packedFloat);
41
- uint y_bits = packedUInt >> 16;
42
- uint z_bits = packedUInt & uint(0xFFFF);
43
-
44
- // NOTE: This assumes packing used "packNormalizedFloatToUint16Pair"
45
- // which maps [-1, 1] to [0, 65535]. Adjust if packing method changes.
46
- float y = (float(y_bits) / 65535.0) * 2.0 - 1.0;
47
- float z = (float(z_bits) / 65535.0) * 2.0 - 1.0;
48
- return vec2(y, z);
49
- }
38
+ // Use GLSL built-in unpackHalf2x16 for proper half-float unpacking
50
39
 
51
- // Reconstruct quaternion from packed components (x, yz_packed)
52
- vec4 unpackRotation(float yz_packed, float x) {
53
- vec2 yz = unpackHalf2x16FromFloat(yz_packed);
54
- float y = yz.x;
55
- float z = yz.y;
40
+ // Reconstruct quaternion from packed components (xy_packed, z)
41
+ // Returns (w,x,y,z) format for quatToMat3 compatibility
42
+ vec4 unpackRotation(float xy_packed, float z) {
43
+ vec2 xy = unpackHalf2x16(floatBitsToUint(xy_packed));
44
+ float x = xy.x;
45
+ float y = xy.y;
56
46
  float w_squared = 1.0 - x*x - y*y - z*z;
57
- float w = (w_squared < 0.0) ? 0.0 : sqrt(w_squared); // Calculate w
58
- return vec4(x, y, z, w);
47
+ float w = (w_squared < 0.0) ? 0.0 : sqrt(w_squared);
48
+ return vec4(w, x, y, z); // Return (w,x,y,z)
59
49
  }
60
50
 
61
51
  // Convert quaternion to 3x3 rotation matrix
62
- mat3 quatToMat3(vec4 q) {
63
- float x = q.x, y = q.y, z = q.z, w = q.w;
64
- float x2 = x + x, y2 = y + y, z2 = z + z;
65
- float xx = x * x2, xy = x * y2, xz = x * z2;
66
- float yy = y * y2, yz = y * z2, zz = z * z2;
67
- float wx = w * x2, wy = w * y2, wz = w * z2;
52
+ mat3 quatToMat3(vec4 R) {
53
+ vec4 R2 = R + R;
54
+ float X = R2.x * R.w;
55
+ vec4 Y = R2.y * R;
56
+ vec4 Z = R2.z * R;
57
+ float W = R2.w * R.w;
68
58
 
69
59
  return mat3(
70
- 1.0 - (yy + zz), xy + wz, xz - wy,
71
- xy - wz, 1.0 - (xx + zz), yz + wx,
72
- xz + wy, yz - wx, 1.0 - (xx + yy)
60
+ 1.0 - Z.z - W,
61
+ Y.z + X,
62
+ Y.w - Z.x,
63
+ Y.z - X,
64
+ 1.0 - Y.y - W,
65
+ Z.w + Y.x,
66
+ Y.w + Z.x,
67
+ Z.w - Y.x,
68
+ 1.0 - Y.y - Z.z
73
69
  );
74
70
  }
75
71
 
76
- // Calculate model-space covariance components R * S^2 * transpose(R)
72
+ // Calculate model-space covariance components
77
73
  void getModelCovariance(vec3 scale, vec4 rotation, out vec3 covA, out vec3 covB) {
78
- mat3 R = quatToMat3(rotation);
79
-
80
- // Define M = R * S (where S is the diagonal scale matrix)
81
- // Note R is column-major, so R[0] is the first column, etc.
82
- // We want M's rows to be R's rows scaled by the corresponding scale factor.
83
- mat3 M = mat3(
84
- R[0][0] * scale.x, R[0][1] * scale.y, R[0][2] * scale.z, // Row 0 = (R_row0 * S)
85
- R[1][0] * scale.x, R[1][1] * scale.y, R[1][2] * scale.z, // Row 1 = (R_row1 * S)
86
- R[2][0] * scale.x, R[2][1] * scale.y, R[2][2] * scale.z // Row 2 = (R_row2 * S)
87
- );
88
-
89
- // Now compute Vrk = M * transpose(M)
90
- // Vrk[i][j] = dot(M[i], M[j]) where M[i] is the i-th row vector of M.
91
- covA = vec3(dot(M[0], M[0]), dot(M[0], M[1]), dot(M[0], M[2])); // Vrk[0][0], Vrk[0][1], Vrk[0][2]
92
- covB = vec3(dot(M[1], M[1]), dot(M[1], M[2]), dot(M[2], M[2])); // Vrk[1][1], Vrk[1][2], Vrk[2][2]
74
+ mat3 rot = quatToMat3(rotation);
75
+
76
+ // M = S * R (scale COLUMNS, then transpose)
77
+ mat3 M = transpose(mat3(
78
+ scale.x * rot[0], // scale.x * column 0
79
+ scale.y * rot[1], // scale.y * column 1
80
+ scale.z * rot[2] // scale.z * column 2
81
+ ));
82
+
83
+ covA = vec3(dot(M[0], M[0]), dot(M[0], M[1]), dot(M[0], M[2]));
84
+ covB = vec3(dot(M[1], M[1]), dot(M[1], M[2]), dot(M[2], M[2]));
93
85
  }
94
86
 
95
87
  // --- Main Function ---
@@ -118,7 +110,7 @@ void main(void) {
118
110
 
119
111
  vec3 splatPosition = texTransformA.xyz;
120
112
  vec3 splatLogScale = texTransformB.xyz; // Assume stored as log scale
121
- vec4 splatRotation = unpackRotation(texTransformA.w, texTransformB.w); // Unpack rot yz, x
113
+ vec4 splatRotation = unpackRotation(texTransformA.w, texTransformB.w); // Unpack rot xy, z
122
114
  vec3 splatColor = texColor.rgb;
123
115
  float splatOpacity = texColor.a;
124
116
 
@@ -244,7 +236,6 @@ void main(void) {
244
236
  // Apply clip to the corner offset *before* calculating screen space offset
245
237
  vec2 clippedCornerOffset = cornerOffset * clip;
246
238
  vec2 screenOffsetPixels = clippedCornerOffset.x * v1_scaled + clippedCornerOffset.y * v2_scaled;
247
- //vec2 screenOffsetPixels = vec2(clippedCornerOffset.x, clippedCornerOffset.y);
248
239
 
249
240
  // Convert pixel offset to clip space offset
250
241
  vec2 clipOffset = screenOffsetPixels * (centerClip.w / viewport);
@@ -280,7 +271,7 @@ void main(void) {
280
271
  // Premultiply color by alpha (required for correct blending)
281
272
  gl_FragColor = vec4(vColor.rgb * alpha, alpha);
282
273
  }
283
- `;class ht extends o.ShaderMaterial{constructor(t={}){const r={transformA:{value:null},transformB:{value:null},splatColor:{value:null},splatOrder:{value:null},viewport:{value:new o.Vector2(1,1)},numSplats:{value:0}};super({vertexShader:xt,fragmentShader:yt,uniforms:r,transparent:!0,blending:o.CustomBlending,blendSrc:o.OneFactor,blendDst:o.OneMinusSrcAlphaFactor,blendSrcAlpha:o.OneFactor,blendDstAlpha:o.OneMinusSrcAlphaFactor,blendEquation:o.AddEquation,blendEquationAlpha:o.AddEquation,depthTest:!0,depthWrite:!1,side:o.DoubleSide,alphaTest:t.alphaTest!==void 0?t.alphaTest:0,toneMapped:t.toneMapped!==void 0?t.toneMapped:!1}),t.alphaHash&&(this.alphaHash=!0,this.depthWrite=!0,this.blending=o.NoBlending)}updateViewport(t,r){this.uniforms.viewport.value.set(t,r)}setTransformA(t){this.uniforms.transformA.value=t}setTransformB(t){this.uniforms.transformB.value=t}setColorTexture(t){this.uniforms.splatColor.value=t}setOrderTexture(t){this.uniforms.splatOrder.value=t}setNumSplats(t){this.uniforms.numSplats.value=t}}const L=class L extends o.Mesh{constructor(r,e={}){const n=new ht(e),s=L.createInstancedGeometry(r.numSplats,L.INSTANCE_SIZE);super(s,n);f(this,"sorter");f(this,"splatData");f(this,"options");f(this,"textureManager");f(this,"material");f(this,"geometry");f(this,"lastCameraPositionLocal",new o.Vector3);f(this,"lastCameraDirectionLocal",new o.Vector3);f(this,"invModelMatrix",new o.Matrix4);this.geometry=s,this.material=n,this.splatData=r,this.frustumCulled=!1,this.options={autoSort:!0,...e},this.textureManager=new lt(r),this.sorter=new at;let i=this.createChunks()||void 0;i===null&&console.warn("Visus: Could not create sorter chunks, bounding box might be invalid."),i=void 0,this.sorter.init(this.textureManager.orderTexture,this.splatData.centers,i??void 0),this.sorter.addEventListener("updated",a=>{const c=a.count;this.geometry.instanceCount=Math.ceil(c/L.INSTANCE_SIZE),this.material.setNumSplats(c)}),this.material.setTransformA(this.textureManager.transformA),this.material.setTransformB(this.textureManager.transformB),this.material.setColorTexture(this.textureManager.colorTexture),this.material.setOrderTexture(this.textureManager.orderTexture),this.material.setNumSplats(0),this.geometry.boundingBox=r.boundingBox.toBox3(),this.geometry.boundingSphere=new o.Sphere,this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere)}static createInstancedGeometry(r,e){const n=Math.ceil(r/e),s=new o.BufferGeometry,i=new Float32Array([-1,-1,0,1,-1,0,1,1,0,-1,1,0]),a=new Uint16Array([0,1,2,0,2,3]),c=new Float32Array(4*3*e);for(let p=0;p<e;p++){const u=p*4*3;for(let l=0;l<4;l++)c[u+l*3+0]=i[l*3+0],c[u+l*3+1]=i[l*3+1],c[u+l*3+2]=p}const h=new Uint32Array(6*e);for(let p=0;p<e;p++){const u=p*6,l=p*4;h[u+0]=a[0]+l,h[u+1]=a[1]+l,h[u+2]=a[2]+l,h[u+3]=a[3]+l,h[u+4]=a[4]+l,h[u+5]=a[5]+l}s.setAttribute("position",new o.BufferAttribute(c,3)),s.setIndex(new o.BufferAttribute(h,1));const v=new o.InstancedBufferGeometry;v.index=s.index,v.setAttribute("position",s.getAttribute("position"));const g=new Uint32Array(n);for(let p=0;p<n;p++)g[p]=p*e;return v.setAttribute("splatInstanceIndex",new o.InstancedBufferAttribute(g,1,!1)),v.instanceCount=0,v}createChunks(){const r=this.splatData.boundingBox;return r.min.x===1/0||r.max.x===-1/0?null:new Float32Array([r.min.x,r.min.y,r.min.z,r.max.x,r.max.y,r.max.z])}updateViewport(r,e){this.material.updateViewport(r,e)}sort(r){const e=new o.Vector3,n=new o.Vector3;r.getWorldPosition(e),r.getWorldDirection(n),this.invModelMatrix.copy(this.matrixWorld).invert();const s=e.applyMatrix4(this.invModelMatrix),i=n.transformDirection(this.invModelMatrix),a=this.lastCameraPositionLocal.distanceToSquared(s)>1e-6,c=this.lastCameraDirectionLocal.dot(i)<.999;this.options.autoSort&&(a||c)&&(this.lastCameraPositionLocal.copy(s),this.lastCameraDirectionLocal.copy(i),this.sorter.setCamera(s,i))}onBeforeRender(r,e,n){this.sort(n);const s=r.getSize(new o.Vector2);let{width:i,height:a}=s;const c=r.xr;if(c.enabled&&c.isPresenting){const h=c.getCamera().cameras[0].view;h&&(i=h.width,a=h.height)}this.updateViewport(i,a)}dispose(){this.sorter.dispose(),this.geometry.dispose(),this.material.dispose(),this.textureManager.dispose()}};f(L,"INSTANCE_SIZE",128);let rt=L;class gt extends o.Loader{load(t,r,e,n){const s=new o.FileLoader(this.manager);s.setResponseType("arraybuffer"),s.setRequestHeader(this.requestHeader),s.setPath(this.path),s.setWithCredentials(this.withCredentials),s.load(t,i=>{try{if(r){const a=this.parse(i);r(a)}}catch(a){n?n(a):console.error(a),this.manager.itemError(t)}},e,n)}loadAsync(t,r){return new Promise((e,n)=>{const s=new o.FileLoader(this.manager);s.setResponseType("arraybuffer"),s.setRequestHeader(this.requestHeader),s.setPath(this.path),s.setWithCredentials(this.withCredentials),s.load(t,i=>{try{const a=this.parse(i);e(a)}catch(a){n(a),this.manager.itemError(t)}},r,i=>{n(i),this.manager.itemError(t)})})}parse(t){const r=new TextDecoder,e=new Uint8Array(t),n=[112,108,121,10],s=`
274
+ `;class ut extends i.ShaderMaterial{constructor(t={}){const n={transformA:{value:null},transformB:{value:null},splatColor:{value:null},splatOrder:{value:null},viewport:{value:new i.Vector2(1,1)},numSplats:{value:0}};super({vertexShader:gt,fragmentShader:yt,uniforms:n,transparent:!0,blending:i.CustomBlending,blendSrc:i.OneFactor,blendDst:i.OneMinusSrcAlphaFactor,blendSrcAlpha:i.OneFactor,blendDstAlpha:i.OneMinusSrcAlphaFactor,blendEquation:i.AddEquation,blendEquationAlpha:i.AddEquation,depthTest:!0,depthWrite:!1,side:i.DoubleSide,alphaTest:t.alphaTest!==void 0?t.alphaTest:0,toneMapped:t.toneMapped!==void 0?t.toneMapped:!1}),t.alphaHash&&(this.alphaHash=!0,this.depthWrite=!0,this.blending=i.NoBlending)}updateViewport(t,n){this.uniforms.viewport.value.set(t,n)}setTransformA(t){this.uniforms.transformA.value=t}setTransformB(t){this.uniforms.transformB.value=t}setColorTexture(t){this.uniforms.splatColor.value=t}setOrderTexture(t){this.uniforms.splatOrder.value=t}setNumSplats(t){this.uniforms.numSplats.value=t}}const j=class j extends i.Mesh{constructor(n,e={}){const r=new ut(e),s=j.createInstancedGeometry(n.numSplats,j.INSTANCE_SIZE);super(s,r);f(this,"sorter");f(this,"splatData");f(this,"options");f(this,"textureManager");f(this,"material");f(this,"geometry");f(this,"lastCameraPositionLocal",new i.Vector3);f(this,"lastCameraDirectionLocal",new i.Vector3);f(this,"invModelMatrix",new i.Matrix4);this.geometry=s,this.material=r,this.splatData=n,this.frustumCulled=!1,this.options={autoSort:!0,...e},this.textureManager=new ht(n),this.sorter=new at;let o=this.createChunks()||void 0;o===null&&console.warn("Visus: Could not create sorter chunks, bounding box might be invalid."),o=void 0,this.sorter.init(this.textureManager.orderTexture,this.splatData.centers,o??void 0),this.sorter.addEventListener("updated",a=>{const c=a.count;this.geometry.instanceCount=Math.ceil(c/j.INSTANCE_SIZE),this.material.setNumSplats(c)}),this.material.setTransformA(this.textureManager.transformA),this.material.setTransformB(this.textureManager.transformB),this.material.setColorTexture(this.textureManager.colorTexture),this.material.setOrderTexture(this.textureManager.orderTexture),this.material.setNumSplats(0),this.geometry.boundingBox=n.boundingBox.toBox3(),this.geometry.boundingSphere=new i.Sphere,this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere)}static createInstancedGeometry(n,e){const r=Math.ceil(n/e),s=new i.BufferGeometry,o=new Float32Array([-1,-1,0,1,-1,0,1,1,0,-1,1,0]),a=new Uint16Array([0,1,2,0,2,3]),c=new Float32Array(4*3*e);for(let p=0;p<e;p++){const u=p*4*3;for(let l=0;l<4;l++)c[u+l*3+0]=o[l*3+0],c[u+l*3+1]=o[l*3+1],c[u+l*3+2]=p}const h=new Uint32Array(6*e);for(let p=0;p<e;p++){const u=p*6,l=p*4;h[u+0]=a[0]+l,h[u+1]=a[1]+l,h[u+2]=a[2]+l,h[u+3]=a[3]+l,h[u+4]=a[4]+l,h[u+5]=a[5]+l}s.setAttribute("position",new i.BufferAttribute(c,3)),s.setIndex(new i.BufferAttribute(h,1));const v=new i.InstancedBufferGeometry;v.index=s.index,v.setAttribute("position",s.getAttribute("position"));const y=new Uint32Array(r);for(let p=0;p<r;p++)y[p]=p*e;return v.setAttribute("splatInstanceIndex",new i.InstancedBufferAttribute(y,1,!1)),v.instanceCount=0,v}createChunks(){const n=this.splatData.boundingBox;return n.min.x===1/0||n.max.x===-1/0?null:new Float32Array([n.min.x,n.min.y,n.min.z,n.max.x,n.max.y,n.max.z])}updateViewport(n,e){this.material.updateViewport(n,e)}sort(n){const e=new i.Vector3,r=new i.Vector3;n.getWorldPosition(e),n.getWorldDirection(r),this.invModelMatrix.copy(this.matrixWorld).invert();const s=e.applyMatrix4(this.invModelMatrix),o=r.transformDirection(this.invModelMatrix),a=this.lastCameraPositionLocal.distanceToSquared(s)>1e-6,c=this.lastCameraDirectionLocal.dot(o)<.999;this.options.autoSort&&(a||c)&&(this.lastCameraPositionLocal.copy(s),this.lastCameraDirectionLocal.copy(o),this.sorter.setCamera(s,o))}onBeforeRender(n,e,r){this.sort(r);const s=n.getSize(new i.Vector2);let{width:o,height:a}=s;const c=n.xr;if(c.enabled&&c.isPresenting){const h=c.getCamera().cameras[0].view;h&&(o=h.width,a=h.height)}this.updateViewport(o,a)}dispose(){this.sorter.dispose(),this.geometry.dispose(),this.material.dispose(),this.textureManager.dispose()}};f(j,"INSTANCE_SIZE",128);let rt=j;class vt extends i.Loader{load(t,n,e,r){const s=new i.FileLoader(this.manager);s.setResponseType("arraybuffer"),s.setRequestHeader(this.requestHeader),s.setPath(this.path),s.setWithCredentials(this.withCredentials),s.load(t,o=>{try{if(n){const a=this.parse(o);n(a)}}catch(a){r?r(a):console.error(a),this.manager.itemError(t)}},e,r)}loadAsync(t,n){return new Promise((e,r)=>{const s=new i.FileLoader(this.manager);s.setResponseType("arraybuffer"),s.setRequestHeader(this.requestHeader),s.setPath(this.path),s.setWithCredentials(this.withCredentials),s.load(t,o=>{try{const a=this.parse(o);e(a)}catch(a){r(a),this.manager.itemError(t)}},n,o=>{r(o),this.manager.itemError(t)})})}parse(t){const n=new TextDecoder,e=new Uint8Array(t),r=[112,108,121,10],s=`
284
275
  end_header
285
- `;for(let x=0;x<n.length;x++)if(e[x]!==n[x])throw new Error("Invalid PLY file: Missing magic bytes");let i=0;for(let x=0;x<e.length-s.length;x++){let d=!0;for(let S=0;S<s.length;S++)if(e[x+S]!==s.charCodeAt(S)){d=!1;break}if(d){i=x+s.length;break}}if(i===0)throw new Error("Invalid PLY file: Could not find end of header");const c=r.decode(e.slice(0,i)).split(`
286
- `),h=[];let v=null;for(let x=1;x<c.length;x++){const d=c[x].trim();if(d===""||d==="end_header")continue;const S=d.split(" ");switch(S[0]){case"format":v=S[1];break;case"element":h.push({name:S[1],count:parseInt(S[2],10),properties:[]});break;case"property":if(h.length===0)throw new Error("Invalid PLY file: Property without element");h[h.length-1].properties.push({type:S[1],name:S[2],storage:null});break}}if(v!=="binary_little_endian")throw new Error(`Unsupported PLY format: ${v}`);const g=h.find(x=>x.name==="vertex");if(!g)throw new Error("Invalid PLY file: No vertex element found");const p=new it(g.count),u=new DataView(t);let l=i;const b=x=>g.properties.findIndex(d=>d.name===x),A=b("x"),q=b("y"),W=b("z"),R=[b("rot_0"),b("rot_1"),b("rot_2"),b("rot_3")],H=[b("scale_0"),b("scale_1"),b("scale_2")],N=[b("f_dc_0"),b("f_dc_1"),b("f_dc_2")],V=b("opacity");if([A,q,W,...R,...H,...N,V].some(x=>x===-1))throw new Error("Invalid PLY file: Missing required properties");const D=.28209479177387814,M=x=>{if(x>0)return 1/(1+Math.exp(-x));const d=Math.exp(x);return d/(1+d)},m=new o.Vector3,F=new o.Quaternion,O=new o.Vector3,P=new o.Color;for(let x=0;x<g.count;x++){const d=[];for(let T=0;T<g.properties.length;T++){const st=g.properties[T].type;let I;switch(st){case"char":I=u.getInt8(l),l+=1;break;case"uchar":I=u.getUint8(l),l+=1;break;case"short":I=u.getInt16(l,!0),l+=2;break;case"ushort":I=u.getUint16(l,!0),l+=2;break;case"int":I=u.getInt32(l,!0),l+=4;break;case"uint":I=u.getUint32(l,!0),l+=4;break;case"float":I=u.getFloat32(l,!0),l+=4;break;case"double":I=u.getFloat64(l,!0),l+=8;break;default:throw new Error(`Unsupported property type: ${st}`)}d.push(I)}m.set(d[A],d[q],d[W]),F.set(d[R[1]],d[R[2]],d[R[3]],d[R[0]]).normalize(),O.set(d[H[0]],d[H[1]],d[H[2]]),P.set(.5+d[N[0]]*D,.5+d[N[1]]*D,.5+d[N[2]]*D),P.r=Math.max(0,Math.min(1,P.r)),P.g=Math.max(0,Math.min(1,P.g)),P.b=Math.max(0,Math.min(1,P.b));const S=M(d[V]);p.setSplat(x,m,F,O,P,S)}return p.calculateBoundingBox(),p}}const vt="0.2.0";C.BoundingBox=X,C.PlyLoader=gt,C.SplatData=it,C.SplatMaterial=ht,C.SplatMesh=rt,C.SplatSorter=at,C.TextureManager=lt,C.VERSION=vt,Object.defineProperty(C,Symbol.toStringTag,{value:"Module"})});
276
+ `;for(let x=0;x<r.length;x++)if(e[x]!==r[x])throw new Error("Invalid PLY file: Missing magic bytes");let o=0;for(let x=0;x<e.length-s.length;x++){let d=!0;for(let z=0;z<s.length;z++)if(e[x+z]!==s.charCodeAt(z)){d=!1;break}if(d){o=x+s.length;break}}if(o===0)throw new Error("Invalid PLY file: Could not find end of header");const c=n.decode(e.slice(0,o)).split(`
277
+ `),h=[];let v=null;for(let x=1;x<c.length;x++){const d=c[x].trim();if(d===""||d==="end_header")continue;const z=d.split(" ");switch(z[0]){case"format":v=z[1];break;case"element":h.push({name:z[1],count:parseInt(z[2],10),properties:[]});break;case"property":if(h.length===0)throw new Error("Invalid PLY file: Property without element");h[h.length-1].properties.push({type:z[1],name:z[2],storage:null});break}}if(v!=="binary_little_endian")throw new Error(`Unsupported PLY format: ${v}`);const y=h.find(x=>x.name==="vertex");if(!y)throw new Error("Invalid PLY file: No vertex element found");const p=new it(y.count),u=new DataView(t);let l=o;const b=x=>y.properties.findIndex(d=>d.name===x),k=b("x"),q=b("y"),W=b("z"),R=[b("rot_0"),b("rot_1"),b("rot_2"),b("rot_3")],H=[b("scale_0"),b("scale_1"),b("scale_2")],N=[b("f_dc_0"),b("f_dc_1"),b("f_dc_2")],P=b("opacity");if([k,q,W,...R,...H,...N,P].some(x=>x===-1))throw new Error("Invalid PLY file: Missing required properties");const V=.28209479177387814,M=x=>{if(x>0)return 1/(1+Math.exp(-x));const d=Math.exp(x);return d/(1+d)},m=new i.Vector3,C=new i.Quaternion,O=new i.Vector3,_=new i.Color;for(let x=0;x<y.count;x++){const d=[];for(let B=0;B<y.properties.length;B++){const st=y.properties[B].type;let A;switch(st){case"char":A=u.getInt8(l),l+=1;break;case"uchar":A=u.getUint8(l),l+=1;break;case"short":A=u.getInt16(l,!0),l+=2;break;case"ushort":A=u.getUint16(l,!0),l+=2;break;case"int":A=u.getInt32(l,!0),l+=4;break;case"uint":A=u.getUint32(l,!0),l+=4;break;case"float":A=u.getFloat32(l,!0),l+=4;break;case"double":A=u.getFloat64(l,!0),l+=8;break;default:throw new Error(`Unsupported property type: ${st}`)}d.push(A)}m.set(d[k],d[q],d[W]),C.set(d[R[1]],d[R[2]],d[R[3]],d[R[0]]).normalize(),C.w<0&&(C.x=-C.x,C.y=-C.y,C.z=-C.z,C.w=-C.w),O.set(d[H[0]],d[H[1]],d[H[2]]),_.set(.5+d[N[0]]*V,.5+d[N[1]]*V,.5+d[N[2]]*V),_.r=Math.max(0,Math.min(1,_.r)),_.g=Math.max(0,Math.min(1,_.g)),_.b=Math.max(0,Math.min(1,_.b));const z=M(d[P]);p.setSplat(x,m,C,O,_,z)}return p.calculateBoundingBox(),p}}const wt="0.3.0";I.BoundingBox=Q,I.PlyLoader=vt,I.SplatData=it,I.SplatMaterial=ut,I.SplatMesh=rt,I.SplatSorter=at,I.TextureManager=ht,I.VERSION=wt,Object.defineProperty(I,Symbol.toStringTag,{value:"Module"})});