1+ import { Debug } from '../../core/debug.js' ;
12import { Quat } from '../../core/math/quat.js' ;
23import { Vec3 } from '../../core/math/vec3.js' ;
34import { Vec4 } from '../../core/math/vec4.js' ;
@@ -18,6 +19,9 @@ import glslGsplatPackingPS from '../shader-lib/glsl/chunks/gsplat/frag/gsplatPac
1819import wgslGsplatSogsReorderSH from '../shader-lib/wgsl/chunks/gsplat/frag/gsplatSogsReorderSh.js' ;
1920import wgslGsplatPackingPS from '../shader-lib/wgsl/chunks/gsplat/frag/gsplatPacking.js' ;
2021
22+ import glslSogsCentersPS from '../shader-lib/glsl/chunks/gsplat/frag/gsplatSogsCenters.js' ;
23+ import wgslSogsCentersPS from '../shader-lib/wgsl/chunks/gsplat/frag/gsplatSogsCenters.js' ;
24+
2125const SH_C0 = 0.28209479177387814 ;
2226
2327const readImageDataAsync = ( texture ) => {
@@ -169,6 +173,14 @@ class GSplatSogsData {
169173
170174 packedShN ;
171175
176+ /**
177+ * Cached centers array (x, y, z per splat), length = numSplats * 3.
178+ *
179+ * @type {Float32Array | null }
180+ * @private
181+ */
182+ _centers = null ;
183+
172184 // Marked when resource is destroyed, to abort any in-flight async preparation
173185 destroyed = false ;
174186
@@ -212,41 +224,12 @@ class GSplatSogsData {
212224 ) ;
213225 }
214226
215- getCenters ( result ) {
216- const { meta, means_l, means_u, numSplats } = this ;
217- const { means } = meta ;
218-
219- const means_u_data = new Uint32Array ( means_u . _levels [ 0 ] . buffer ) ;
220- const means_l_data = new Uint32Array ( means_l . _levels [ 0 ] . buffer ) ;
221-
222- const mx = means . mins [ 0 ] / 65535 ;
223- const my = means . mins [ 1 ] / 65535 ;
224- const mz = means . mins [ 2 ] / 65535 ;
225- const Mx = means . maxs [ 0 ] / 65535 ;
226- const My = means . maxs [ 1 ] / 65535 ;
227- const Mz = means . maxs [ 2 ] / 65535 ;
228-
229- for ( let i = 0 ; i < numSplats ; i ++ ) {
230- const idx = i ;
231-
232- const means_u = means_u_data [ idx ] ;
233- const means_l = means_l_data [ idx ] ;
234-
235- const wx = ( ( means_u << 8 ) & 0xff00 ) | ( means_l & 0xff ) ;
236- const wy = ( means_u & 0xff00 ) | ( ( means_l >>> 8 ) & 0xff ) ;
237- const wz = ( ( means_u >>> 8 ) & 0xff00 ) | ( ( means_l >>> 16 ) & 0xff ) ;
238-
239- const nx = mx * ( 65535 - wx ) + Mx * wx ;
240- const ny = my * ( 65535 - wy ) + My * wy ;
241- const nz = mz * ( 65535 - wz ) + Mz * wz ;
242-
243- const ax = nx < 0 ? - nx : nx ;
244- const ay = ny < 0 ? - ny : ny ;
245- const az = nz < 0 ? - nz : nz ;
246- result [ i * 3 ] = ( nx < 0 ? - 1 : 1 ) * ( Math . exp ( ax ) - 1 ) ;
247- result [ i * 3 + 1 ] = ( ny < 0 ? - 1 : 1 ) * ( Math . exp ( ay ) - 1 ) ;
248- result [ i * 3 + 2 ] = ( nz < 0 ? - 1 : 1 ) * ( Math . exp ( az ) - 1 ) ;
249- }
227+ getCenters ( ) {
228+ // centers can be only copied once to avoid making copies.
229+ Debug . assert ( this . _centers ) ;
230+ const centers = /** @type {Float32Array } */ this . _centers ;
231+ this . _centers = null ;
232+ return centers ;
250233 }
251234
252235 // use bound center for focal point
@@ -363,6 +346,69 @@ class GSplatSogsData {
363346 } ] ) ;
364347 }
365348
349+ async generateCenters ( ) {
350+ const { device, width, height } = this . means_l ;
351+ const { scope } = device ;
352+
353+ // create a temporary texture to render centers into
354+ const centersTexture = new Texture ( device , {
355+ name : 'sogsCentersTexture' ,
356+ width,
357+ height,
358+ format : PIXELFORMAT_RGBA32U ,
359+ mipmaps : false
360+ } ) ;
361+
362+ const shader = ShaderUtils . createShader ( device , {
363+ uniqueName : 'GsplatSogsCentersShader' ,
364+ attributes : { vertex_position : SEMANTIC_POSITION } ,
365+ vertexChunk : 'fullscreenQuadVS' ,
366+ fragmentGLSL : glslSogsCentersPS ,
367+ fragmentWGSL : wgslSogsCentersPS ,
368+ fragmentOutputTypes : [ 'uvec4' ] ,
369+ fragmentIncludes : new Map ( [ [ 'gsplatPackingPS' , device . isWebGPU ? wgslGsplatPackingPS : glslGsplatPackingPS ] ] )
370+ } ) ;
371+
372+ const renderTarget = new RenderTarget ( {
373+ colorBuffer : centersTexture ,
374+ depth : false ,
375+ mipLevel : 0
376+ } ) ;
377+
378+ device . setCullMode ( CULLFACE_NONE ) ;
379+ device . setBlendState ( BlendState . NOBLEND ) ;
380+ device . setDepthState ( DepthState . NODEPTH ) ;
381+
382+ resolve ( scope , {
383+ means_l : this . means_l ,
384+ means_u : this . means_u ,
385+ numSplats : this . numSplats ,
386+ means_mins : this . meta . means . mins ,
387+ means_maxs : this . meta . means . maxs
388+ } ) ;
389+
390+ drawQuadWithShader ( device , renderTarget , shader ) ;
391+
392+ renderTarget . destroy ( ) ;
393+
394+ const u32 = await readImageDataAsync ( centersTexture ) ;
395+ if ( this . destroyed || device . _destroyed ) {
396+ centersTexture . destroy ( ) ;
397+ return ;
398+ }
399+
400+ const asFloat = new Float32Array ( u32 . buffer ) ;
401+ const result = new Float32Array ( this . numSplats * 3 ) ;
402+ for ( let i = 0 ; i < this . numSplats ; i ++ ) {
403+ const base = i * 4 ;
404+ result [ i * 3 + 0 ] = asFloat [ base + 0 ] ;
405+ result [ i * 3 + 1 ] = asFloat [ base + 1 ] ;
406+ result [ i * 3 + 2 ] = asFloat [ base + 2 ] ;
407+ }
408+ this . _centers = result ;
409+ centersTexture . destroy ( ) ;
410+ }
411+
366412 // pack the means, quats, scales and sh_labels data into one RGBA32U texture
367413 packGpuMemory ( ) {
368414 const { meta, means_l, means_u, quats, scales, sh0, sh_labels, numSplats } = this ;
@@ -456,13 +502,6 @@ class GSplatSogsData {
456502 async prepareGpuData ( ) {
457503 const { device, height, width } = this . means_l ;
458504
459- // copy back means_l and means_u data so cpu reorder has access to it
460- if ( this . destroyed || device . _destroyed ) return ; // skip the rest if the resource was destroyed
461- this . means_l . _levels [ 0 ] = await readImageDataAsync ( this . means_l ) ;
462-
463- if ( this . destroyed || device . _destroyed ) return ; // skip the rest if the resource was destroyed
464- this . means_u . _levels [ 0 ] = await readImageDataAsync ( this . means_u ) ;
465-
466505 if ( this . destroyed || device . _destroyed ) return ; // skip the rest if the resource was destroyed
467506 this . packedTexture = new Texture ( device , {
468507 name : 'sogsPackedTexture' ,
@@ -495,6 +534,9 @@ class GSplatSogsData {
495534 }
496535 } ) ;
497536
537+ if ( this . destroyed || device . _destroyed ) return ; // skip the rest if the resource was destroyed
538+ await this . generateCenters ( ) ;
539+
498540 if ( this . destroyed || device . _destroyed ) return ; // skip the rest if the resource was destroyed
499541 this . packGpuMemory ( ) ;
500542 if ( this . packedShN ) {
0 commit comments