@@ -114,17 +114,16 @@ function SortWorker() {
114114 distances [ i ] = 0 ;
115115 countBuffer [ 0 ] ++ ;
116116 }
117- } else if ( chunks ) {
118- // handle sort with compressed chunks
119- const numChunks = chunks . length / 6 ;
117+ } else {
118+ // use chunks to calculate rough histogram of splats per distance
119+ const numChunks = chunks . length / 4 ;
120120
121- // calculate a histogram of chunk distances to camera
122121 binCount . fill ( 0 ) ;
123122 for ( let i = 0 ; i < numChunks ; ++ i ) {
124- const x = chunks [ i * 6 + 0 ] ;
125- const y = chunks [ i * 6 + 1 ] ;
126- const z = chunks [ i * 6 + 2 ] ;
127- const r = chunks [ i * 6 + 3 ] ;
123+ const x = chunks [ i * 4 + 0 ] ;
124+ const y = chunks [ i * 4 + 1 ] ;
125+ const z = chunks [ i * 4 + 2 ] ;
126+ const r = chunks [ i * 4 + 3 ] ;
128127 const d = x * dx + y * dy + z * dz - minDist ;
129128
130129 const binMin = Math . max ( 0 , Math . floor ( ( d - r ) * numBins / range ) ) ;
@@ -159,23 +158,6 @@ function SortWorker() {
159158
160159 distances [ i ] = sortKey ;
161160
162- // count occurrences of each distance
163- countBuffer [ sortKey ] ++ ;
164- }
165- } else {
166- // generate per vertex distance to camera for uncompressed data
167- const divider = ( 2 ** compareBits ) / range ;
168- let ii = 0 ;
169- for ( let i = 0 ; i < numVertices ; ++ i ) {
170- const x = centers [ ii ++ ] ;
171- const y = centers [ ii ++ ] ;
172- const z = centers [ ii ++ ] ;
173-
174- const d = ( x * dx + y * dy + z * dz - minDist ) * divider ;
175- const sortKey = d >>> 0 ;
176-
177- distances [ i ] = sortKey ;
178-
179161 // count occurrences of each distance
180162 countBuffer [ sortKey ] ++ ;
181163 }
@@ -230,61 +212,90 @@ function SortWorker() {
230212 centers = new Float32Array ( message . data . centers ) ;
231213 forceUpdate = true ;
232214
233- // calculate bounds
234- let initialized = false ;
235- const numVertices = centers . length / 3 ;
236- for ( let i = 0 ; i < numVertices ; ++ i ) {
237- let x = centers [ i * 3 + 0 ] ;
238- let y = centers [ i * 3 + 1 ] ;
239- let z = centers [ i * 3 + 2 ] ;
240-
241- if ( isNaN ( x ) ) {
242- x = centers [ i * 3 + 0 ] = 0 ;
243- }
244- if ( isNaN ( y ) ) {
245- y = centers [ i * 3 + 1 ] = 0 ;
215+ if ( message . data . chunks ) {
216+ const chunksSrc = new Float32Array ( message . data . chunks ) ;
217+ // reuse chunks memory, but we only need 4 floats per chunk
218+ chunks = new Float32Array ( message . data . chunks , 0 , chunksSrc . length * 4 / 6 ) ;
219+
220+ boundMin . x = chunksSrc [ 0 ] ;
221+ boundMin . y = chunksSrc [ 1 ] ;
222+ boundMin . z = chunksSrc [ 2 ] ;
223+ boundMax . x = chunksSrc [ 3 ] ;
224+ boundMax . y = chunksSrc [ 4 ] ;
225+ boundMax . z = chunksSrc [ 5 ] ;
226+
227+ // convert chunk min/max to center/radius
228+ for ( let i = 0 ; i < chunksSrc . length / 6 ; ++ i ) {
229+ const mx = chunksSrc [ i * 6 + 0 ] ;
230+ const my = chunksSrc [ i * 6 + 1 ] ;
231+ const mz = chunksSrc [ i * 6 + 2 ] ;
232+ const Mx = chunksSrc [ i * 6 + 3 ] ;
233+ const My = chunksSrc [ i * 6 + 4 ] ;
234+ const Mz = chunksSrc [ i * 6 + 5 ] ;
235+
236+ chunks [ i * 4 + 0 ] = ( mx + Mx ) * 0.5 ;
237+ chunks [ i * 4 + 1 ] = ( my + My ) * 0.5 ;
238+ chunks [ i * 4 + 2 ] = ( mz + Mz ) * 0.5 ;
239+ chunks [ i * 4 + 3 ] = Math . sqrt ( ( Mx - mx ) ** 2 + ( My - my ) ** 2 + ( Mz - mz ) ** 2 ) * 0.5 ;
240+
241+ if ( mx < boundMin . x ) boundMin . x = mx ;
242+ if ( my < boundMin . y ) boundMin . y = my ;
243+ if ( mz < boundMin . z ) boundMin . z = mz ;
244+ if ( Mx > boundMax . x ) boundMax . x = Mx ;
245+ if ( My > boundMax . y ) boundMax . y = My ;
246+ if ( Mz > boundMax . z ) boundMax . z = Mz ;
246247 }
247- if ( isNaN ( z ) ) {
248- z = centers [ i * 3 + 2 ] = 0 ;
249- }
250-
251- if ( ! initialized ) {
252- initialized = true ;
253- boundMin . x = boundMax . x = x ;
254- boundMin . y = boundMax . y = y ;
255- boundMin . z = boundMax . z = z ;
256- } else {
257- boundMin . x = Math . min ( boundMin . x , x ) ;
258- boundMax . x = Math . max ( boundMax . x , x ) ;
259- boundMin . y = Math . min ( boundMin . y , y ) ;
260- boundMax . y = Math . max ( boundMax . y , y ) ;
261- boundMin . z = Math . min ( boundMin . z , z ) ;
262- boundMax . z = Math . max ( boundMax . z , z ) ;
248+ } else {
249+ // chunk bounds weren't provided, so calculate them from the centers
250+ const numVertices = centers . length / 3 ;
251+ const numChunks = Math . ceil ( numVertices / 256 ) ;
252+
253+ // allocate storage for one bounding sphere per 256-vertex chunk
254+ chunks = new Float32Array ( numChunks * 4 ) ;
255+
256+ boundMin . x = boundMin . y = boundMin . z = Infinity ;
257+ boundMax . x = boundMax . y = boundMax . z = - Infinity ;
258+
259+ // calculate bounds
260+ let mx , my , mz , Mx , My , Mz ;
261+ for ( let c = 0 ; c < numChunks ; ++ c ) {
262+ mx = my = mz = Infinity ;
263+ Mx = My = Mz = - Infinity ;
264+
265+ const start = c * 256 ;
266+ const end = Math . min ( numVertices , ( c + 1 ) * 256 ) ;
267+ for ( let i = start ; i < end ; ++ i ) {
268+ const x = centers [ i * 3 + 0 ] ;
269+ const y = centers [ i * 3 + 1 ] ;
270+ const z = centers [ i * 3 + 2 ] ;
271+
272+ const validX = Number . isFinite ( x ) ;
273+ const validY = Number . isFinite ( y ) ;
274+ const validZ = Number . isFinite ( z ) ;
275+
276+ if ( ! validX ) centers [ i * 3 + 0 ] = 0 ;
277+ if ( ! validY ) centers [ i * 3 + 1 ] = 0 ;
278+ if ( ! validZ ) centers [ i * 3 + 2 ] = 0 ;
279+ if ( ! validX || ! validY || ! validZ ) {
280+ continue ;
281+ }
282+
283+ if ( x < mx ) mx = x ; else if ( x > Mx ) Mx = x ;
284+ if ( y < my ) my = y ; else if ( y > My ) My = y ;
285+ if ( z < mz ) mz = z ; else if ( z > Mz ) Mz = z ;
286+
287+ if ( x < boundMin . x ) boundMin . x = x ; else if ( x > boundMax . x ) boundMax . x = x ;
288+ if ( y < boundMin . y ) boundMin . y = y ; else if ( y > boundMax . y ) boundMax . y = y ;
289+ if ( z < boundMin . z ) boundMin . z = z ; else if ( z > boundMax . z ) boundMax . z = z ;
290+ }
291+
292+ // calculate chunk center and radius from bound min/max
293+ chunks [ c * 4 + 0 ] = ( mx + Mx ) * 0.5 ;
294+ chunks [ c * 4 + 1 ] = ( my + My ) * 0.5 ;
295+ chunks [ c * 4 + 2 ] = ( mz + Mz ) * 0.5 ;
296+ chunks [ c * 4 + 3 ] = Math . sqrt ( ( Mx - mx ) ** 2 + ( My - my ) ** 2 + ( Mz - mz ) ** 2 ) * 0.5 ;
263297 }
264298 }
265-
266- if ( ! initialized ) {
267- boundMin . x = boundMax . x = boundMin . y = boundMax . y = boundMin . z = boundMax . z = 0 ;
268- }
269- }
270- if ( message . data . chunks ) {
271- chunks = new Float32Array ( message . data . chunks ) ;
272- forceUpdate = true ;
273-
274- // convert chunk min/max to center/radius
275- for ( let i = 0 ; i < chunks . length / 6 ; ++ i ) {
276- const mx = chunks [ i * 6 + 0 ] ;
277- const my = chunks [ i * 6 + 1 ] ;
278- const mz = chunks [ i * 6 + 2 ] ;
279- const Mx = chunks [ i * 6 + 3 ] ;
280- const My = chunks [ i * 6 + 4 ] ;
281- const Mz = chunks [ i * 6 + 5 ] ;
282-
283- chunks [ i * 6 + 0 ] = ( mx + Mx ) * 0.5 ;
284- chunks [ i * 6 + 1 ] = ( my + My ) * 0.5 ;
285- chunks [ i * 6 + 2 ] = ( mz + Mz ) * 0.5 ;
286- chunks [ i * 6 + 3 ] = Math . sqrt ( ( Mx - mx ) ** 2 + ( My - my ) ** 2 + ( Mz - mz ) ** 2 ) * 0.5 ;
287- }
288299 }
289300 if ( message . data . hasOwnProperty ( 'mapping' ) ) {
290301 mapping = message . data . mapping ? new Uint32Array ( message . data . mapping ) : null ;
0 commit comments