diff --git a/README.md b/README.md index 8e21119..194b783 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ Needs few seconds to load splats. | cutoutEntity | selector to a box primitive that uses scale and position to define the bounds of splat points to render | | | pixelRatio | Pixel ratio for rendering. Reducing the value decreases the resolution and improves performance. If a negative value is set, the device's native value will be applied. | 1.0 | | xrPixelRatio | Same as pixelRatio. Applied to XR devices. | 0.5 | +| depthWrite | Force writing to the depth Buffer. This may help fixing occlusion issues | false | +| discardFilter | Value from 0 to 1, Discard splats blobs that are under a certain opacity (0 basically means no discarding). This may help fixing occlusion issues with Splats clarity tradeof. | 0 | ### Example custom scan to gaussian splat workflow * Use a service such as https://lumalabs.ai/ to process a scan into splat (an alternative is https://poly.cam/) diff --git a/dist/aframe-gaussian-splatting-component.min.js b/dist/aframe-gaussian-splatting-component.min.js index 71fc777..fe02229 100644 --- a/dist/aframe-gaussian-splatting-component.min.js +++ b/dist/aframe-gaussian-splatting-component.min.js @@ -1,13 +1,15 @@ -AFRAME.registerComponent("gaussian_splatting",{schema:{src:{type:"string",default:"train.splat"},cutoutEntity:{type:"selector"},pixelRatio:{type:"number",default:1},xrPixelRatio:{type:"number",default:.5}},init:function(){0this.maxVertexes&&(console.log("numVertexes limited to ",this.maxVertexes,numVertexes),numVertexes=this.maxVertexes),this.bufferTextureWidth=gl,this.bufferTextureHeight=Math.floor((numVertexes-1)/gl)+1,this.centerAndScaleData=new Float32Array(this.bufferTextureWidth*this.bufferTextureHeight*4),this.covAndColorData=new Uint32Array(this.bufferTextureWidth*this.bufferTextureHeight*4),this.centerAndScaleTexture=new THREE.DataTexture(this.centerAndScaleData,this.bufferTextureWidth,this.bufferTextureHeight,THREE.RGBA,THREE.FloatType),this.centerAndScaleTexture.needsUpdate=!0,this.covAndColorTexture=new THREE.DataTexture(this.covAndColorData,this.bufferTextureWidth,this.bufferTextureHeight,THREE.RGBAIntegerFormat,THREE.UnsignedIntType),this.covAndColorTexture.internalFormat="RGBA32UI",this.covAndColorTexture.needsUpdate=!0,new Uint32Array(this.bufferTextureWidth*this.bufferTextureHeight)),gl=new THREE.InstancedBufferAttribute(numVertexes,1,!1),numVertexes=(gl.setUsage(THREE.DynamicDrawUsage),new THREE.BufferGeometry),positionsArray=new Float32Array(18),positionsArray=new THREE.BufferAttribute(positionsArray,3),positionsArray=(numVertexes.setAttribute("position",positionsArray),positionsArray.setXYZ(2,-2,2,0),positionsArray.setXYZ(1,2,2,0),positionsArray.setXYZ(0,-2,-2,0),positionsArray.setXYZ(5,-2,-2,0),positionsArray.setXYZ(4,2,2,0),positionsArray.setXYZ(3,2,-2,0),positionsArray.needsUpdate=!0,(new THREE.InstancedBufferGeometry).copy(numVertexes));positionsArray.setAttribute("splatIndex",gl),positionsArray.instanceCount=1;const material=new THREE.ShaderMaterial({uniforms:{viewport:{value:new Float32Array([1980,1080])},focal:{value:1e3},centerAndScaleTexture:{value:this.centerAndScaleTexture},covAndColorTexture:{value:this.covAndColorTexture},gsProjectionMatrix:{value:this.getProjectionMatrix()},gsModelViewMatrix:{value:this.getModelViewMatrix()}},vertexShader:` +AFRAME.registerComponent("gaussian_splatting",{schema:{src:{type:"string",default:"train.splat"},cutoutEntity:{type:"selector"},pixelRatio:{type:"number",default:1},xrPixelRatio:{type:"number",default:.5},depthWrite:{type:"boolean",default:!1},discardFilter:{type:"number",default:0}},init:function(){0{this.loadData(this.el.sceneEl.camera.el.components.camera.camera,this.el.object3D,this.el.sceneEl.renderer,this.data.src),this.data.cutoutEntity&&(this.cutout=this.data.cutoutEntity.object3D)})},initGL:async function(numVertexes){console.log("initGL",numVertexes),this.object.frustumCulled=!1;var gl=this.renderer.getContext(),gl=gl.getParameter(gl.MAX_TEXTURE_SIZE),gl=(this.maxVertexes=gl*gl,numVertexes>this.maxVertexes&&(console.log("numVertexes limited to ",this.maxVertexes,numVertexes),numVertexes=this.maxVertexes),this.bufferTextureWidth=gl,this.bufferTextureHeight=Math.floor((numVertexes-1)/gl)+1,this.centerAndScaleData=new Float32Array(this.bufferTextureWidth*this.bufferTextureHeight*4),this.covAndColorData=new Uint32Array(this.bufferTextureWidth*this.bufferTextureHeight*4),this.centerAndScaleTexture=new THREE.DataTexture(this.centerAndScaleData,this.bufferTextureWidth,this.bufferTextureHeight,THREE.RGBA,THREE.FloatType),this.centerAndScaleTexture.needsUpdate=!0,this.covAndColorTexture=new THREE.DataTexture(this.covAndColorData,this.bufferTextureWidth,this.bufferTextureHeight,THREE.RGBAIntegerFormat,THREE.UnsignedIntType),this.covAndColorTexture.internalFormat="RGBA32UI",this.covAndColorTexture.needsUpdate=!0,new Uint32Array(this.bufferTextureWidth*this.bufferTextureHeight)),gl=new THREE.InstancedBufferAttribute(gl,1,!1),baseGeometry=(gl.setUsage(THREE.DynamicDrawUsage),new THREE.BufferGeometry),positionsArray=new Float32Array(18),positionsArray=new THREE.BufferAttribute(positionsArray,3),positionsArray=(baseGeometry.setAttribute("position",positionsArray),positionsArray.setXYZ(2,-2,2,0),positionsArray.setXYZ(1,2,2,0),positionsArray.setXYZ(0,-2,-2,0),positionsArray.setXYZ(5,-2,-2,0),positionsArray.setXYZ(4,2,2,0),positionsArray.setXYZ(3,2,-2,0),positionsArray.needsUpdate=!0,(new THREE.InstancedBufferGeometry).copy(baseGeometry));positionsArray.setAttribute("splatIndex",gl),positionsArray.instanceCount=1;const material=new THREE.ShaderMaterial({uniforms:{viewport:{value:new Float32Array([1980,1080])},focal:{value:1e3},centerAndScaleTexture:{value:this.centerAndScaleTexture},covAndColorTexture:{value:this.covAndColorTexture},gsProjectionMatrix:{value:this.getProjectionMatrix()},gsModelViewMatrix:{value:this.getModelViewMatrix()},discardFilter:{value:this.data.discardFilter}},vertexShader:` precision highp sampler2D; precision highp usampler2D; out vec4 vColor; out vec2 vPosition; + out float fDF; uniform vec2 viewport; uniform float focal; uniform mat4 gsProjectionMatrix; uniform mat4 gsModelViewMatrix; + uniform float discardFilter; attribute uint splatIndex; uniform sampler2D centerAndScaleTexture; @@ -80,6 +82,7 @@ AFRAME.registerComponent("gaussian_splatting",{schema:{src:{type:"string",defaul float(colorUint >> uint(24)) / 255.0 ); vPosition = position.xy; + fDF = discardFilter; gl_Position = vec4( vCenter @@ -89,11 +92,13 @@ AFRAME.registerComponent("gaussian_splatting",{schema:{src:{type:"string",defaul `,fragmentShader:` in vec4 vColor; in vec2 vPosition; + in float fDF; void main () { float A = -dot(vPosition, vPosition); if (A < -4.0) discard; float B = exp(A) * vColor.a; + if(B < fDF) discard; gl_FragColor = vec4(vColor.rgb, B); } - `,blending:THREE.CustomBlending,blendSrcAlpha:THREE.OneFactor,depthTest:!0,depthWrite:!1,transparent:!0}),mesh=(material.onBeforeRender=(renderer,scene,camera,geometry,object,group)=>{var projectionMatrix=this.getProjectionMatrix(camera),camera=(mesh.material.uniforms.gsProjectionMatrix.value=projectionMatrix,mesh.material.uniforms.gsModelViewMatrix.value=this.getModelViewMatrix(camera),new THREE.Vector4),renderer=(renderer.getCurrentViewport(camera),camera.w/2*Math.abs(projectionMatrix.elements[5]));material.uniforms.viewport.value[0]=camera.z,material.uniforms.viewport.value[1]=camera.w,material.uniforms.focal.value=renderer},new THREE.Mesh(positionsArray,material));for(mesh.frustumCulled=!1,this.object.add(mesh),this.worker.onmessage=e=>{e=new Uint32Array(e.data.sortedIndexes);mesh.geometry.attributes.splatIndex.set(e),mesh.geometry.attributes.splatIndex.needsUpdate=!0,mesh.geometry.instanceCount=e.length,this.sortReady=!0};;){var centerAndScaleTextureProperties=this.renderer.properties.get(this.centerAndScaleTexture),covAndColorTextureProperties=this.renderer.properties.get(this.covAndColorTexture);if(centerAndScaleTextureProperties&¢erAndScaleTextureProperties.__webglTexture&&covAndColorTextureProperties&¢erAndScaleTextureProperties.__webglTexture)break;await new Promise(resolve=>setTimeout(resolve,10))}this.sortReady=!0},loadData:function(camera,object,renderer,src){this.camera=camera,this.object=object,this.renderer=renderer,this.loadedVertexCount=0,this.rowLength=32,this.worker=new Worker(URL.createObjectURL(new Blob(["(",this.createWorker.toString(),")(self)"],{type:"application/javascript"}))),this.worker.postMessage({method:"clear"}),fetch(src).then(async data=>{var reader=data.body.getReader();let glInitialized=!1,bytesDownloaded=0,bytesProcesses=0;var data=data.headers.get("Content-Length"),totalDownloadBytes=data?parseInt(data):void 0,chunks=(null!=totalDownloadBytes&&(data=Math.floor(totalDownloadBytes/this.rowLength),await this.initGL(data),glInitialized=!0),[]),start=Date.now();let lastReportedProgress=0;for(var isPly=src.endsWith(".ply");;)try{var mbps,percent,{value,done}=await reader.read();if(done){console.log("Completed download.");break}bytesDownloaded+=value.length,null!=totalDownloadBytes?(mbps=bytesDownloaded/1024/1024/((Date.now()-start)/1e3),1<(percent=bytesDownloaded/totalDownloadBytes*100)-lastReportedProgress&&(console.log("download progress:",percent.toFixed(2)+"%",mbps.toFixed(2)+" Mbps"),lastReportedProgress=percent)):console.log("download progress:",bytesDownloaded,", unknown total"),chunks.push(value);var bytesRemains=bytesDownloaded-bytesProcesses;if(!isPly&&null!=totalDownloadBytes&&bytesRemains>this.rowLength){var extra_data,vertexCount=Math.floor(bytesRemains/this.rowLength),concatenatedChunksbuffer=new Uint8Array(bytesRemains);let offset=0;for(const chunk of chunks)concatenatedChunksbuffer.set(chunk,offset),offset+=chunk.length;chunks.length=0,bytesRemains>vertexCount*this.rowLength&&((extra_data=new Uint8Array(bytesRemains-vertexCount*this.rowLength)).set(concatenatedChunksbuffer.subarray(bytesRemains-extra_data.length,bytesRemains),0),chunks.push(extra_data));var buffer=new Uint8Array(vertexCount*this.rowLength);buffer.set(concatenatedChunksbuffer.subarray(0,buffer.byteLength),0),this.pushDataBuffer(buffer.buffer,vertexCount),bytesProcesses+=vertexCount*this.rowLength}}catch(error){console.error(error);break}if(0acc+chunk.length,0)),offset=0;for(const chunk of chunks)concatenatedChunks.set(chunk,offset),offset+=chunk.length;isPly&&(concatenatedChunks=new Uint8Array(this.processPlyBuffer(concatenatedChunks.buffer)));let numVertexes=Math.floor(concatenatedChunks.byteLength/this.rowLength);glInitialized||(await this.initGL(numVertexes),glInitialized=!0),this.pushDataBuffer(concatenatedChunks.buffer,numVertexes)}})},pushDataBuffer:function(buffer,vertexCount){if(this.loadedVertexCount+vertexCount>this.maxVertexes&&(console.log("vertexCount limited to ",this.maxVertexes,vertexCount),vertexCount=this.maxVertexes-this.loadedVertexCount),!(vertexCount<=0)){var u_buffer=new Uint8Array(buffer),f_buffer=new Float32Array(buffer),matrices=new Float32Array(16*vertexCount),covAndColorData_uint8=new Uint8Array(this.covAndColorData.buffer),covAndColorData_int16=new Int16Array(this.covAndColorData.buffer);for(let i=0;imax_value&&(max_value=Math.abs(mtx.elements[cov_indexes[j]]));let destOffset=4*this.loadedVertexCount+4*i;this.centerAndScaleData[destOffset+0]=center.x,this.centerAndScaleData[destOffset+1]=center.y,this.centerAndScaleData[destOffset+2]=center.z,this.centerAndScaleData[destOffset+3]=max_value/32767,destOffset=8*this.loadedVertexCount+4*i*2;for(let j=0;j-1e-4*depth&&cutoutArea&&(depthList[validCount]=depth,validIndexList[validCount]=i,validCount++,depth>maxDepth&&(maxDepth=depth),depth{if("clear"==e.data.method&&(matrices=void 0),"push"==e.data.method&&(new_matrices=new Float32Array(e.data.matrices),matrices=void 0===matrices?new_matrices:((resized=new Float32Array(matrices.length+new_matrices.length)).set(matrices),resized.set(new_matrices,matrices.length),resized)),"sort"==e.data.method)if(void 0===matrices){var new_matrices=new Uint32Array(1);self.postMessage({sortedIndexes:new_matrices},[new_matrices.buffer])}else{new_matrices=new Float32Array(e.data.view),e=void 0!==e.data.cutout?new Float32Array(e.data.cutout):void 0;const sortedIndexes=sortSplats(matrices,new_matrices,e);self.postMessage({sortedIndexes:sortedIndexes},[sortedIndexes.buffer])}}},processPlyBuffer:function(inputBuffer){var ubuf=new Uint8Array(inputBuffer),ubuf=(new TextDecoder).decode(ubuf.slice(0,10240)),header_end_index=ubuf.indexOf("end_header\n");if(header_end_index<0)throw new Error("Unable to read .ply file header");var vertexCount=parseInt(/element vertex (\d+)\n/.exec(ubuf)[1]);console.log("Vertex Count",vertexCount);let row_offset=0,offsets={},types={};var prop,TYPE_MAP={double:"getFloat64",int:"getInt32",uint:"getUint32",float:"getFloat32",short:"getInt16",ushort:"getUint16",uchar:"getUint8"};for(prop of ubuf.slice(0,header_end_index).split("\n").filter(k=>k.startsWith("property "))){var[,type,name]=prop.split(" "),type=TYPE_MAP[type]||"getInt8";types[name]=type,offsets[name]=row_offset,row_offset+=parseInt(type.replace(/[^\d]/g,""))/8}console.log("Bytes per row",row_offset,types,offsets);let dataView=new DataView(inputBuffer,header_end_index+"end_header\n".length),row=0;var attrs=new Proxy({},{get(target,prop){if(types[prop])return dataView[types[prop]](row*row_offset+offsets[prop],!0);throw new Error(prop+" not found")}});console.time("calculate importance");let sizeList=new Float32Array(vertexCount);var size,opacity,sizeIndex=new Uint32Array(vertexCount);for(row=0;rowsizeList[a]-sizeList[b]),console.timeEnd("sort");var buffer=new ArrayBuffer(32*vertexCount);console.time("build buffer");for(let j=0;j{var projectionMatrix=this.getProjectionMatrix(camera),viewport=(mesh.material.uniforms.gsProjectionMatrix.value=projectionMatrix,mesh.material.uniforms.gsModelViewMatrix.value=this.getModelViewMatrix(camera),new THREE.Vector4),projectionMatrix=(renderer.getCurrentViewport(viewport),viewport.w/2*Math.abs(projectionMatrix.elements[5]));material.uniforms.viewport.value[0]=viewport.z,material.uniforms.viewport.value[1]=viewport.w,material.uniforms.focal.value=projectionMatrix},new THREE.Mesh(positionsArray,material));for(mesh.frustumCulled=!1,this.object.add(mesh),this.worker.onmessage=e=>{var indexes=new Uint32Array(e.data.sortedIndexes);mesh.geometry.attributes.splatIndex.set(indexes),mesh.geometry.attributes.splatIndex.needsUpdate=!0,mesh.geometry.instanceCount=indexes.length,this.sortReady=!0};;){var centerAndScaleTextureProperties=this.renderer.properties.get(this.centerAndScaleTexture),covAndColorTextureProperties=this.renderer.properties.get(this.covAndColorTexture);if(centerAndScaleTextureProperties&¢erAndScaleTextureProperties.__webglTexture&&covAndColorTextureProperties&¢erAndScaleTextureProperties.__webglTexture)break;await new Promise(resolve=>setTimeout(resolve,10))}this.sortReady=!0},loadData:async function(camera,object,renderer,src){this.camera=camera,this.object=object,this.renderer=renderer,this.loadedVertexCount=0,this.rowLength=32,this.worker=new Worker(URL.createObjectURL(new Blob(["(",this.createWorker.toString(),")(self)"],{type:"application/javascript"}))),this.worker.postMessage({method:"clear"});try{for(;;){if((data=await fetch(src)).ok)break;console.log("retry",src),await new Promise(resolve=>setTimeout(resolve,1e3))}this.parseData(data,src)}catch(error){console.error(error)}},parseData:async function(data,src){console.log("parseData",data,src);var reader=data.body.getReader();let glInitialized=!1,bytesDownloaded=0,bytesProcesses=0;var _totalDownloadBytes=data.headers.get("Content-Length"),totalDownloadBytes=_totalDownloadBytes?parseInt(_totalDownloadBytes):void 0,chunks=(null!=totalDownloadBytes&&(_totalDownloadBytes=Math.floor(totalDownloadBytes/this.rowLength),await this.initGL(_totalDownloadBytes),glInitialized=!0),[]),start=Date.now();let lastReportedProgress=0;for(var isPly=src.endsWith(".ply");;)try{var mbps,percent,{value,done}=await reader.read();if(done){console.log("Completed download.");break}bytesDownloaded+=value.length,null!=totalDownloadBytes?(mbps=bytesDownloaded/1024/1024/((Date.now()-start)/1e3),1<(percent=bytesDownloaded/totalDownloadBytes*100)-lastReportedProgress&&(console.log("download progress:",percent.toFixed(2)+"%",mbps.toFixed(2)+" Mbps"),lastReportedProgress=percent)):console.log("download progress:",bytesDownloaded,", unknown total"),chunks.push(value);var bytesRemains=bytesDownloaded-bytesProcesses;if(!isPly&&null!=totalDownloadBytes&&bytesRemains>this.rowLength){var extra_data,vertexCount=Math.floor(bytesRemains/this.rowLength),concatenatedChunksbuffer=new Uint8Array(bytesRemains);let offset=0;for(const chunk of chunks)concatenatedChunksbuffer.set(chunk,offset),offset+=chunk.length;chunks.length=0,bytesRemains>vertexCount*this.rowLength&&((extra_data=new Uint8Array(bytesRemains-vertexCount*this.rowLength)).set(concatenatedChunksbuffer.subarray(bytesRemains-extra_data.length,bytesRemains),0),chunks.push(extra_data));var buffer=new Uint8Array(vertexCount*this.rowLength);buffer.set(concatenatedChunksbuffer.subarray(0,buffer.byteLength),0),this.pushDataBuffer(buffer.buffer,vertexCount),bytesProcesses+=vertexCount*this.rowLength}}catch(error){console.error(error);break}if(0acc+chunk.length,0)),offset=0;for(const chunk of chunks)concatenatedChunks.set(chunk,offset),offset+=chunk.length;isPly&&(concatenatedChunks=new Uint8Array(this.processPlyBuffer(concatenatedChunks.buffer)));let numVertexes=Math.floor(concatenatedChunks.byteLength/this.rowLength);glInitialized||(await this.initGL(numVertexes),glInitialized=!0),this.pushDataBuffer(concatenatedChunks.buffer,numVertexes)}},pushDataBuffer:function(buffer,vertexCount){if(this.loadedVertexCount+vertexCount>this.maxVertexes&&(console.log("vertexCount limited to ",this.maxVertexes,vertexCount),vertexCount=this.maxVertexes-this.loadedVertexCount),!(vertexCount<=0)){var u_buffer=new Uint8Array(buffer),f_buffer=new Float32Array(buffer),matrices=new Float32Array(16*vertexCount),covAndColorData_uint8=new Uint8Array(this.covAndColorData.buffer),covAndColorData_int16=new Int16Array(this.covAndColorData.buffer);for(let i=0;imax_value&&(max_value=Math.abs(mtx.elements[cov_indexes[j]]));let destOffset=4*this.loadedVertexCount+4*i;this.centerAndScaleData[destOffset+0]=center.x,this.centerAndScaleData[destOffset+1]=center.y,this.centerAndScaleData[destOffset+2]=center.z,this.centerAndScaleData[destOffset+3]=max_value/32767,destOffset=8*this.loadedVertexCount+4*i*2;for(let j=0;j-1e-4*depth&&cutoutArea&&(depthList[validCount]=depth,validIndexList[validCount]=i,validCount++,depth>maxDepth&&(maxDepth=depth),depth{if("clear"==e.data.method&&(matrices=void 0),"push"==e.data.method&&(new_matrices=new Float32Array(e.data.matrices),matrices=void 0===matrices?new_matrices:((resized=new Float32Array(matrices.length+new_matrices.length)).set(matrices),resized.set(new_matrices,matrices.length),resized)),"sort"==e.data.method)if(void 0===matrices){var new_matrices=new Uint32Array(1);self.postMessage({sortedIndexes:new_matrices},[new_matrices.buffer])}else{var new_matrices=new Float32Array(e.data.view),cutout=void 0!==e.data.cutout?new Float32Array(e.data.cutout):void 0;const sortedIndexes=sortSplats(matrices,new_matrices,cutout);self.postMessage({sortedIndexes:sortedIndexes},[sortedIndexes.buffer])}}},processPlyBuffer:function(inputBuffer){var ubuf=new Uint8Array(inputBuffer),ubuf=(new TextDecoder).decode(ubuf.slice(0,10240)),header_end_index=ubuf.indexOf("end_header\n");if(header_end_index<0)throw new Error("Unable to read .ply file header");var vertexCount=parseInt(/element vertex (\d+)\n/.exec(ubuf)[1]);console.log("Vertex Count",vertexCount);let row_offset=0,offsets={},types={};var prop,TYPE_MAP={double:"getFloat64",int:"getInt32",uint:"getUint32",float:"getFloat32",short:"getInt16",ushort:"getUint16",uchar:"getUint8"};for(prop of ubuf.slice(0,header_end_index).split("\n").filter(k=>k.startsWith("property "))){var[,type,name]=prop.split(" "),type=TYPE_MAP[type]||"getInt8";types[name]=type,offsets[name]=row_offset,row_offset+=parseInt(type.replace(/[^\d]/g,""))/8}console.log("Bytes per row",row_offset,types,offsets);let dataView=new DataView(inputBuffer,header_end_index+"end_header\n".length),row=0;var attrs=new Proxy({},{get(target,prop){if(types[prop])return dataView[types[prop]](row*row_offset+offsets[prop],!0);throw new Error(prop+" not found")}});console.time("calculate importance");let sizeList=new Float32Array(vertexCount);var size,opacity,sizeIndex=new Uint32Array(vertexCount);for(row=0;rowsizeList[a]-sizeList[b]),console.timeEnd("sort");var buffer=new ArrayBuffer(32*vertexCount);console.time("build buffer");for(let j=0;j> uint(24)) / 255.0 ); vPosition = position.xy; + fDF = discardFilter; gl_Position = vec4( vCenter @@ -166,18 +172,20 @@ AFRAME.registerComponent("gaussian_splatting", { fragmentShader: ` in vec4 vColor; in vec2 vPosition; + in float fDF; void main () { float A = -dot(vPosition, vPosition); if (A < -4.0) discard; float B = exp(A) * vColor.a; + if(B < fDF) discard; gl_FragColor = vec4(vColor.rgb, B); } `, blending : THREE.CustomBlending, blendSrcAlpha : THREE.OneFactor, depthTest : true, - depthWrite: false, + depthWrite: this.data.depthWrite, transparent: true } ); @@ -219,7 +227,7 @@ AFRAME.registerComponent("gaussian_splatting", { this.sortReady = true; }, - loadData: function(camera, object, renderer, src) { + loadData: async function(camera, object, renderer, src) { this.camera = camera; this.object = object; this.renderer = renderer; @@ -235,95 +243,107 @@ AFRAME.registerComponent("gaussian_splatting", { ); this.worker.postMessage({method: "clear"}); - fetch(src) - .then(async (data) => { - const reader = data.body.getReader(); - - let glInitialized = false; - let bytesDownloaded = 0; - let bytesProcesses = 0; - let _totalDownloadBytes = data.headers.get("Content-Length"); - let totalDownloadBytes = _totalDownloadBytes ? parseInt(_totalDownloadBytes) : undefined; - - if(totalDownloadBytes != undefined){ - let numVertexes = Math.floor(totalDownloadBytes / this.rowLength); - await this.initGL(numVertexes); - glInitialized = true; + try { + while(true){ + data = await fetch(src) + if(data.ok)break + console.log("retry", src); + await new Promise(resolve => setTimeout(resolve, 1000)); + } - - const chunks = []; - const start = Date.now(); - let lastReportedProgress = 0; - let isPly = src.endsWith(".ply"); - - while (true) { - try { - const { value, done } = await reader.read(); - if (done) { - console.log("Completed download."); - break; + this.parseData(data,src); + } + catch (error) { + console.error(error); + } + }, + parseData: async function(data,src) { + const reader = data.body.getReader(); + + let glInitialized = false; + let bytesDownloaded = 0; + let bytesProcesses = 0; + let _totalDownloadBytes = data.headers.get("Content-Length"); + let totalDownloadBytes = _totalDownloadBytes ? parseInt(_totalDownloadBytes) : undefined; + + if(totalDownloadBytes != undefined){ + let numVertexes = Math.floor(totalDownloadBytes / this.rowLength); + await this.initGL(numVertexes); + glInitialized = true; + } + + const chunks = []; + const start = Date.now(); + let lastReportedProgress = 0; + let isPly = src.endsWith(".ply"); + + while (true) { + try { + const { value, done } = await reader.read(); + if (done) { + console.log("Completed download."); + break; + } + bytesDownloaded += value.length; + if (totalDownloadBytes != undefined) { + const mbps = (bytesDownloaded / 1024 / 1024) / ((Date.now() - start) / 1000); + const percent = bytesDownloaded / totalDownloadBytes * 100; + if (percent - lastReportedProgress > 1) { + console.log("download progress:", percent.toFixed(2) + "%", mbps.toFixed(2) + " Mbps"); + lastReportedProgress = percent; } - bytesDownloaded += value.length; - if (totalDownloadBytes != undefined) { - const mbps = (bytesDownloaded / 1024 / 1024) / ((Date.now() - start) / 1000); - const percent = bytesDownloaded / totalDownloadBytes * 100; - if (percent - lastReportedProgress > 1) { - console.log("download progress:", percent.toFixed(2) + "%", mbps.toFixed(2) + " Mbps"); - lastReportedProgress = percent; - } - } else { - console.log("download progress:", bytesDownloaded, ", unknown total"); + } else { + console.log("download progress:", bytesDownloaded, ", unknown total"); + } + chunks.push(value); + + const bytesRemains = bytesDownloaded - bytesProcesses; + if(!isPly && totalDownloadBytes != undefined && bytesRemains > this.rowLength){ + let vertexCount = Math.floor(bytesRemains / this.rowLength); + const concatenatedChunksbuffer = new Uint8Array(bytesRemains); + let offset = 0; + for (const chunk of chunks) { + concatenatedChunksbuffer.set(chunk, offset); + offset += chunk.length; } - chunks.push(value); - - const bytesRemains = bytesDownloaded - bytesProcesses; - if(!isPly && totalDownloadBytes != undefined && bytesRemains > this.rowLength){ - let vertexCount = Math.floor(bytesRemains / this.rowLength); - const concatenatedChunksbuffer = new Uint8Array(bytesRemains); - let offset = 0; - for (const chunk of chunks) { - concatenatedChunksbuffer.set(chunk, offset); - offset += chunk.length; - } - chunks.length = 0; - if(bytesRemains > vertexCount * this.rowLength){ - const extra_data = new Uint8Array(bytesRemains - vertexCount * this.rowLength); - extra_data.set(concatenatedChunksbuffer.subarray(bytesRemains - extra_data.length, bytesRemains), 0); - chunks.push(extra_data); - } - const buffer = new Uint8Array(vertexCount * this.rowLength); - buffer.set(concatenatedChunksbuffer.subarray(0, buffer.byteLength), 0); - this.pushDataBuffer(buffer.buffer, vertexCount); - bytesProcesses += vertexCount * this.rowLength; + chunks.length = 0; + if(bytesRemains > vertexCount * this.rowLength){ + const extra_data = new Uint8Array(bytesRemains - vertexCount * this.rowLength); + extra_data.set(concatenatedChunksbuffer.subarray(bytesRemains - extra_data.length, bytesRemains), 0); + chunks.push(extra_data); } - } catch (error) { - console.error(error); - break; + const buffer = new Uint8Array(vertexCount * this.rowLength); + buffer.set(concatenatedChunksbuffer.subarray(0, buffer.byteLength), 0); + this.pushDataBuffer(buffer.buffer, vertexCount); + bytesProcesses += vertexCount * this.rowLength; } + } catch (error) { + console.error(error); + break; } + } - if(bytesDownloaded - bytesProcesses > 0){ - // Concatenate the chunks into a single Uint8Array - let concatenatedChunks = new Uint8Array( - chunks.reduce((acc, chunk) => acc + chunk.length, 0) - ); - let offset = 0; - for (const chunk of chunks) { - concatenatedChunks.set(chunk, offset); - offset += chunk.length; - } - if(isPly){ - concatenatedChunks = new Uint8Array(this.processPlyBuffer(concatenatedChunks.buffer)); - } + if(bytesDownloaded - bytesProcesses > 0){ + // Concatenate the chunks into a single Uint8Array + let concatenatedChunks = new Uint8Array( + chunks.reduce((acc, chunk) => acc + chunk.length, 0) + ); + let offset = 0; + for (const chunk of chunks) { + concatenatedChunks.set(chunk, offset); + offset += chunk.length; + } + if(isPly){ + concatenatedChunks = new Uint8Array(this.processPlyBuffer(concatenatedChunks.buffer)); + } - let numVertexes = Math.floor(concatenatedChunks.byteLength/this.rowLength); - if(!glInitialized){ - await this.initGL(numVertexes); - glInitialized = true; - } - this.pushDataBuffer(concatenatedChunks.buffer, numVertexes); + let numVertexes = Math.floor(concatenatedChunks.byteLength/this.rowLength); + if(!glInitialized){ + await this.initGL(numVertexes); + glInitialized = true; } - }); + this.pushDataBuffer(concatenatedChunks.buffer, numVertexes); + } }, pushDataBuffer: function(buffer, vertexCount) { if(this.loadedVertexCount + vertexCount > this.maxVertexes){ diff --git a/package.json b/package.json index b9c8def..b8c1c05 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dist": "uglifyjs ./index.js -c --keep-fnames --source-map --output ./dist/aframe-gaussian-splatting-component.min.js" + "dist": "uglifyjs ./index.js -c --keep-fnames --webkit --source-map --output ./dist/aframe-gaussian-splatting-component.min.js" }, "repository": { "type": "git", diff --git a/transparency-sorting.html b/transparency-sorting.html new file mode 100644 index 0000000..3b79137 --- /dev/null +++ b/transparency-sorting.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + +