@speridlabs/visus 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.umd.js CHANGED
@@ -1,5 +1,5 @@
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=`
1
+ (function(A,P){typeof exports=="object"&&typeof module<"u"?P(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],P):(A=typeof globalThis<"u"?globalThis:A||self,P(A.Visus={},A.THREE))})(this,function(A,P){"use strict";var St=Object.defineProperty;var Ct=(A,P,L)=>P in A?St(A,P,{enumerable:!0,configurable:!0,writable:!0,value:L}):A[P]=L;var f=(A,P,L)=>Ct(A,typeof P!="symbol"?P+"":P,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 s in T)if(s!=="default"){const e=Object.getOwnPropertyDescriptor(T,s);Object.defineProperty(t,s,e.get?e:{enumerable:!0,get:()=>T[s]})}}return t.default=T,Object.freeze(t)}const i=L(P);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,s,e,r,n,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]=s.x,this.positions[a+1]=s.y,this.positions[a+2]=s.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]=n.r,this.colors[v+1]=n.g,this.colors[v+2]=n.b,this.opacities[t]=o,this.centers[a]=s.x,this.centers[a+1]=s.y,this.centers[a+2]=s.z}getSplat(t){if(t>=this.numSplats)throw new Error(`Splat index out of bounds: ${t} >= ${this.numSplats}`);const s=t*3,e=t*4,r=t*3,n=t*3;return{position:new i.Vector3(this.positions[s],this.positions[s+1],this.positions[s+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[n],this.colors[n+1],this.colors[n+2]),opacity:this.opacities[t]}}calculateBoundingBox(){this.boundingBox.reset();const t=new i.Vector3;for(let s=0;s<this.numSplats;s++){const e=s*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 s=new Float32Array(this.numSplats*3),e=new i.Quaternion,r=new i.Euler;for(let n=0;n<this.numSplats;n++){const o=n*4,a=n*3;e.set(this.rotations[o],this.rotations[o+1],this.rotations[o+2],this.rotations[o+3]),r.setFromQuaternion(e),s[a]=r.x,s[a+1]=r.y,s[a+2]=r.z}return t.setAttribute("rotation",new i.BufferAttribute(s,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 s=this.createWorkerCode(),e=new Blob([s],{type:"application/javascript"});this.worker=new Worker(URL.createObjectURL(e)),this.worker.onmessage=this.onWorkerMessage.bind(this)}onWorkerMessage(s){if(!this.orderTexture||!this.orderTexture.image)return console.error("SplatSorter: Order texture not initialized!");const{order:e,count:r}=s.data,n=this.orderTexture.image.data;if(!(n instanceof Uint32Array))return console.error("SplatSorter: Order texture data is not a Uint32Array!");n.set(new Uint32Array(e)),this.orderTexture.needsUpdate=!0;const o=n.buffer.slice(0),a={order:o};this.worker.postMessage(a,[o]),this.dispatchEvent({type:"updated",count:r})}init(s,e,r){if(!s||!(s.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(s.image.data.length<e.length/3)throw new Error("SplatSorter: orderTexture data buffer is smaller than the number of splats.");const n=e.length/3;this.orderTexture=s,this.centers=e.slice();const o=this.orderTexture.image.data;for(let g=0;g<n;g++)o[g]=g;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 g=this.chunks.buffer.slice(0);h.chunks=g,v.push(g)}this.worker.postMessage(h,v)}setMapping(s){if(!this.centers)return console.warn("SplatSorter: Cannot set mapping before initialization.");let e;const r=[];if(!s){const c=this.centers.buffer.slice(0);return e={centers:c,mapping:null},r.push(c),this.worker.postMessage(e,r)}const n=new Float32Array(s.length*3);for(let c=0;c<s.length;c++){const h=s[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;n[g+0]=this.centers[v+0],n[g+1]=this.centers[v+1],n[g+2]=this.centers[v+2]}const o=n.buffer.slice(0),a=s.buffer.slice(0);e={centers:o,mapping:a},r.push(o,a),this.worker.postMessage(e,r)}setCamera(s,e){const r=this.lastCameraPosition.distanceToSquared(s)>1e-7,n=this.lastCameraDirection.dot(e)<.9999;if(!r&&!n)return;this.lastCameraPosition.copy(s),this.lastCameraDirection.copy(e);const o={cameraPosition:{x:s.x,y:s.y,z:s.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,n=null,o=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 k=32,q=new Array(k).fill(0),W=new Array(k).fill(0),R=new Array(k).fill(0),H=(_,C,D)=>{for(;_<=C;){const M=C+_>>1,m=D(M);if(m>0)_=M+1;else if(m<0)C=M-1;else return M}return~_},N=()=>{if(!e||!r||!a||!c)return;if(r.length===0){const y={order:e.buffer,count:0};self.postMessage(y,[e.buffer]),e=null;return}const _=a.x,C=a.y,D=a.z,M=c.x,m=c.y,S=c.z,U=1e-4,E=Math.abs(_-v.x)>U||Math.abs(C-v.y)>U||Math.abs(D-v.z)>U,x=Math.abs(M-g.x)>U||Math.abs(m-g.y)>U||Math.abs(S-g.z)>U;if(!h&&!E&&!x)return;h=!1,v.x=_,v.y=C,v.z=D,g.x=M,g.y=m,g.z=S;let d=1/0,z=-1/0;for(let y=0;y<8;++y){const F=y&1?p.x:u.x,O=y&2?p.y:u.y,w=y&4?p.z:u.z,V=F*M+O*m+w*S;d=Math.min(d,V),z=Math.max(z,V)}const B=r.length/3,Y=z-d,I=(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!==I?b=new Uint32Array(I):b.fill(0),Y<1e-7){for(let y=0;y<B;++y)l[y]=0;b[0]=B}else if(n&&n.length>0){const y=n.length/6;q.fill(0);for(let w=0;w<y;++w){const V=w*6,$=n[V+0],J=n[V+1],tt=n[V+2],X=n[V+3],Z=$*M+J*m+tt*S-d,et=Z-X,K=Z+X,st=Math.max(0,Math.floor(et*k/Y)),ot=Math.min(k,Math.ceil(K*k/Y));for(let G=st;G<ot;++G)q[G]++}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*I>>>0,W[w]=W[w-1]+R[w-1];R[k-1]=q[k-1]/F*I>>>0;const O=Y/k;for(let w=0;w<B;++w){const V=w*3,$=r[V+0],J=r[V+1],tt=r[V+2],X=$*M+J*m+tt*S,et=(z-X)/O,K=Math.max(0,Math.min(k-1,Math.floor(et))),st=et-K,ot=W[K]+R[K]*st>>>0,G=Math.min(ot,I-1);l[w]=G,b[G]++}}else{const y=(I-1)/Y;for(let F=0;F<B;++F){const O=F*3,w=r[O+0],V=r[O+1],$=r[O+2],J=w*M+V*m+$*S,X=(z-J)*y>>>0,Z=Math.min(X,I-1);l[F]=Z,b[Z]++}}for(let y=1;y<I;y++)b[y]+=b[y-1];for(let y=B-1;y>=0;y--){const F=l[y],O=--b[F];e[O]=o?o[y]:y}const bt=_*M+C*m+D*S,dt=y=>{if(!e)return-1/0;const F=e[y],O=F;if(!r||O*3+2>=r.length)return-1/0;const w=O*3;return r[w]*M+r[w+1]*m+r[w+2]*S-bt};let ft=B;if(B>0&&dt(B-1)<0){const y=H(0,B-1,dt);ft=y<0?~y:y}const Mt={order:e.buffer,count:ft};self.postMessage(Mt,[e.buffer]),e=null};self.onmessage=_=>{const C=_.data;C.order&&(e=new Uint32Array(C.order));let D=!1;if(C.centers&&(r=new Float32Array(C.centers),D=!0,h=!0),Object.prototype.hasOwnProperty.call(C,"mapping")&&(o=C.mapping?new Uint32Array(C.mapping):null,h=!0),C.chunks){if(n=new Float32Array(C.chunks),n.length>0&&n[3]>0)for(let M=0;M<n.length/6;++M){const m=M*6,S=n[m+0],U=n[m+1],E=n[m+2],x=n[m+3],d=n[m+4],z=n[m+5];n[m+0]=(S+x)*.5,n[m+1]=(U+d)*.5,n[m+2]=(E+z)*.5,n[m+3]=Math.sqrt((x-S)**2+(d-U)**2+(z-E)**2)*.5}h=!0}if(D&&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 D&&r&&r.length===0&&(p.x=u.x=p.y=u.y=p.z=u.z=0);C.cameraPosition&&(a=C.cameraPosition),C.cameraDirection&&(c=C.cameraDirection),N()}}).toString()})();`}}const pt=(T,t)=>{const s=ct(T),e=ct(t);return s|e<<16};function ct(T){const t=new Float32Array([T]),e=new Int32Array(t.buffer)[0];let r=e>>16&32768,n=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?(n|=2048,r|=(n>>114-o)+(n>>113-o&1),r):(r|=o-112<<10|n>>1,r+=n&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 s=t.numSplats;this.textureWidth=Math.ceil(Math.sqrt(s)),this.textureHeight=Math.ceil(s/this.textureWidth),this.transformA=this.createTransformATexture(t),this.transformB=this.createTransformBTexture(t),this.colorTexture=this.createColorTexture(t),this.orderTexture=this.createOrderTexture(s)}createTransformATexture(t){const s=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let n=0;n<s;n++){const o=n*4,a=n*3,c=n*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],g=pt(h,v);e[o+3]=xt(g)}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 s=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let n=0;n<s;n++){const o=n*4,a=n*3,c=n*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 s=t.numSplats,e=new Float32Array(this.textureWidth*this.textureHeight*4);for(let n=0;n<s;n++){const o=n*4,a=n*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[n]}const r=new i.DataTexture(e,this.textureWidth,this.textureHeight,i.RGBAFormat,i.FloatType);return r.needsUpdate=!0,r}createOrderTexture(t){const s=new Uint32Array(this.textureWidth*this.textureHeight);for(let r=0;r<t;r++)s[r]=r;const e=new i.DataTexture(s,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 yt=`
3
3
  precision highp float;
4
4
  precision highp int;
5
5
  precision highp usampler2D;
@@ -203,6 +203,10 @@ void main(void) {
203
203
  float l1 = sqrt(lambda1) * scaleFactor; // scaleX
204
204
  float l2 = sqrt(lambda2) * scaleFactor; // scaleY
205
205
 
206
+ float vmin = min(512.0, min(viewport.x, viewport.y));
207
+ l1 = min(l1, 2.0 * vmin);
208
+ l2 = min(l2, 2.0 * vmin);
209
+
206
210
  // Early out tiny splats
207
211
  if (l1 < 2.0 && l2 < 2.0) { // Check if smaller than ~2 pixel
208
212
  gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
@@ -213,14 +217,15 @@ void main(void) {
213
217
  vec2 v1_scaled = l1 * v1_eigen;
214
218
  vec2 v2_scaled = l2 * v2_eigen;
215
219
 
216
- // --- FRUSTUM CHECK ---
220
+ // --- FRUSTUM CHECK (laxo, estilo PlayCanvas) ---
217
221
 
218
- vec2 clipRadius = vec2(max(l1, l2)) * (centerClip.w / viewport);
222
+ vec2 c = centerClip.ww / viewport; // pixel to clip
223
+ float r = max(l1, l2); // radius in pixels
219
224
 
220
- // Check if the bounding circle's edge is outside the [-w, w] range in clip space for x or y
221
- if (any(greaterThan(abs(centerClip.xy) + clipRadius, vec2(abs(centerClip.w))))) {
222
- gl_Position = vec4(2.0, 2.0, 2.0, 1.0); // Off-screen
223
- return;
225
+ // Remove if the center - radius is already out of -w..w
226
+ if (any(greaterThan(abs(centerClip.xy) - vec2(r) * c, centerClip.ww))) {
227
+ gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
228
+ return;
224
229
  }
225
230
 
226
231
  // --- END FRUSTUM CHECK ---
@@ -249,12 +254,20 @@ void main(void) {
249
254
  vColor = vec4(splatColor, splatOpacity);
250
255
  vUv = clippedCornerOffset;
251
256
  }
252
- `,yt=`
257
+ `,gt=`
253
258
  precision highp float;
254
259
 
255
260
  varying vec4 vColor; // Color and opacity passed from vertex shader
256
261
  varying vec2 vUv; // Quad UV coordinates (-1 to 1) passed from vertex shader
257
262
 
263
+ // Fast approximate e^x based on https://nic.schraudolph.org/pubs/Schraudolph99.pdf
264
+ const float EXP_A = 12102203.0; // ≈ 2^23 / ln(2)
265
+ const int EXP_BC_RMS = 1064866808; // (127 << 23) - 60801 * 8
266
+ float fastExp(float x) {
267
+ int i = int(EXP_A * x) + EXP_BC_RMS;
268
+ return intBitsToFloat(i);
269
+ }
270
+
258
271
  void main(void) {
259
272
 
260
273
  float distSq = dot(vUv, vUv); // Calculate squared distance from center (in the quad's coordinate system)
@@ -264,14 +277,14 @@ void main(void) {
264
277
  // The factor 4.0 corresponds to the original implementation's scaling.
265
278
  // factor = 1 / (2 * sigma^2), where sigma controls the spread.
266
279
  // Using 4.0 implies sigma^2 = 1/8.
267
- float alpha = exp(-distSq * 4.0) * vColor.a;
280
+ float alpha = fastExp(-distSq * 4.0) * vColor.a;
268
281
 
269
282
  if (alpha < 1.0 / 255.0) discard; // Discard fragments with very low alpha
270
283
 
271
284
  // Premultiply color by alpha (required for correct blending)
272
285
  gl_FragColor = vec4(vColor.rgb * alpha, alpha);
273
286
  }
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=`
287
+ `;class ut extends i.ShaderMaterial{constructor(t={}){const s={transformA:{value:null},transformB:{value:null},splatColor:{value:null},splatOrder:{value:null},viewport:{value:new i.Vector2(1,1)},numSplats:{value:0}};super({vertexShader:yt,fragmentShader:gt,uniforms:s,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,s){this.uniforms.viewport.value.set(t,s)}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(s,e={}){const r=new ut(e),n=j.createInstancedGeometry(s.numSplats,j.INSTANCE_SIZE);super(n,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=n,this.material=r,this.splatData=s,this.frustumCulled=!1,this.options={autoSort:!0,...e},this.textureManager=new ht(s),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=s.boundingBox.toBox3(),this.geometry.boundingSphere=new i.Sphere,this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere)}static createInstancedGeometry(s,e){const r=Math.ceil(s/e),n=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}n.setAttribute("position",new i.BufferAttribute(c,3)),n.setIndex(new i.BufferAttribute(h,1));const v=new i.InstancedBufferGeometry;v.index=n.index,v.setAttribute("position",n.getAttribute("position"));const g=new Uint32Array(r);for(let p=0;p<r;p++)g[p]=p*e;return v.setAttribute("splatInstanceIndex",new i.InstancedBufferAttribute(g,1,!1)),v.instanceCount=0,v}createChunks(){const s=this.splatData.boundingBox;return s.min.x===1/0||s.max.x===-1/0?null:new Float32Array([s.min.x,s.min.y,s.min.z,s.max.x,s.max.y,s.max.z])}updateViewport(s,e){this.material.updateViewport(s,e)}sort(s){const e=new i.Vector3,r=new i.Vector3;s.getWorldPosition(e),s.getWorldDirection(r),this.invModelMatrix.copy(this.matrixWorld).invert();const n=e.applyMatrix4(this.invModelMatrix),o=r.transformDirection(this.invModelMatrix),a=this.lastCameraPositionLocal.distanceToSquared(n)>1e-6,c=this.lastCameraDirectionLocal.dot(o)<.999;this.options.autoSort&&(a||c)&&(this.lastCameraPositionLocal.copy(n),this.lastCameraDirectionLocal.copy(o),this.sorter.setCamera(n,o))}onBeforeRender(s,e,r){this.sort(r);const n=s.getSize(new i.Vector2);let{width:o,height:a}=n;const c=s.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,s,e,r){const n=new i.FileLoader(this.manager);n.setResponseType("arraybuffer"),n.setRequestHeader(this.requestHeader),n.setPath(this.path),n.setWithCredentials(this.withCredentials),n.load(t,o=>{try{if(s){const a=this.parse(o);s(a)}}catch(a){r?r(a):console.error(a),this.manager.itemError(t)}},e,r)}loadAsync(t,s){return new Promise((e,r)=>{const n=new i.FileLoader(this.manager);n.setResponseType("arraybuffer"),n.setRequestHeader(this.requestHeader),n.setPath(this.path),n.setWithCredentials(this.withCredentials),n.load(t,o=>{try{const a=this.parse(o);e(a)}catch(a){r(a),this.manager.itemError(t)}},s,o=>{r(o),this.manager.itemError(t)})})}parse(t){const s=new TextDecoder,e=new Uint8Array(t),r=[112,108,121,10],n=`
275
288
  end_header
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"})});
289
+ `;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-n.length;x++){let d=!0;for(let z=0;z<n.length;z++)if(e[x+z]!==n.charCodeAt(z)){d=!1;break}if(d){o=x+n.length;break}}if(o===0)throw new Error("Invalid PLY file: Could not find end of header");const c=s.decode(e.slice(0,o)).split(`
290
+ `),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 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=o;const b=x=>g.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")],_=b("opacity");if([k,q,W,...R,...H,...N,_].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 i.Vector3,S=new i.Quaternion,U=new i.Vector3,E=new i.Color;for(let x=0;x<g.count;x++){const d=[];for(let B=0;B<g.properties.length;B++){const nt=g.properties[B].type;let I;switch(nt){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: ${nt}`)}d.push(I)}m.set(d[k],d[q],d[W]),S.set(d[R[1]],d[R[2]],d[R[3]],d[R[0]]).normalize(),S.w<0&&(S.x=-S.x,S.y=-S.y,S.z=-S.z,S.w=-S.w),U.set(d[H[0]],d[H[1]],d[H[2]]),E.set(.5+d[N[0]]*D,.5+d[N[1]]*D,.5+d[N[2]]*D),E.r=Math.max(0,Math.min(1,E.r)),E.g=Math.max(0,Math.min(1,E.g)),E.b=Math.max(0,Math.min(1,E.b));const z=M(d[_]);p.setSplat(x,m,S,U,E,z)}return p.calculateBoundingBox(),p}}const wt="0.3.0";A.BoundingBox=Q,A.PlyLoader=vt,A.SplatData=it,A.SplatMaterial=ut,A.SplatMesh=rt,A.SplatSorter=at,A.TextureManager=ht,A.VERSION=wt,Object.defineProperty(A,Symbol.toStringTag,{value:"Module"})});