@@ -97,7 +97,6 @@ const _batchIntersects = [];
97
97
// @TODO : geometry.drawRange support?
98
98
// @TODO : geometry.morphAttributes support?
99
99
// @TODO : Support uniform parameter per geometry
100
- // @TODO : Add an "optimize" function to pack geometry and remove data gaps
101
100
102
101
// copies data from attribute "src" into "target" starting at "targetOffset"
103
102
function copyAttributeData ( src , target , targetOffset = 0 ) {
@@ -132,8 +131,23 @@ function copyAttributeData( src, target, targetOffset = 0 ) {
132
131
// safely copies array contents to a potentially smaller array
133
132
function copyArrayContents ( src , target ) {
134
133
135
- const len = Math . min ( src . length , target . length ) ;
136
- target . set ( new src . constructor ( src . buffer , 0 , len ) ) ;
134
+ if ( src . constructor !== target . constructor ) {
135
+
136
+ // if arrays are of a different type (eg due to index size increasing) then data must be per-element copied
137
+ const len = Math . min ( src . length , target . length ) ;
138
+ for ( let i = 0 ; i < len ; i ++ ) {
139
+
140
+ target [ i ] = src [ i ] ;
141
+
142
+ }
143
+
144
+ } else {
145
+
146
+ // if the arrays use the same data layout we can use a fast block copy
147
+ const len = Math . min ( src . length , target . length ) ;
148
+ target . set ( new src . constructor ( src . buffer , 0 , len ) ) ;
149
+
150
+ }
137
151
138
152
}
139
153
@@ -180,6 +194,10 @@ class BatchedMesh extends Mesh {
180
194
this . _multiDrawInstances = null ;
181
195
this . _visibilityChanged = true ;
182
196
197
+ // used to track where the next point is that geometry should be inserted
198
+ this . _nextIndexStart = 0 ;
199
+ this . _nextVertexStart = 0 ;
200
+
183
201
// Local matrix per geometry by using data texture
184
202
this . _matricesTexture = null ;
185
203
this . _indirectTexture = null ;
@@ -425,16 +443,11 @@ class BatchedMesh extends Mesh {
425
443
indexCount : - 1 ,
426
444
} ;
427
445
428
- let lastRange = null ;
429
446
const reservedRanges = this . _reservedRanges ;
430
447
const drawRanges = this . _drawRanges ;
431
448
const bounds = this . _bounds ;
432
- if ( this . _geometryCount !== 0 ) {
433
-
434
- lastRange = reservedRanges [ reservedRanges . length - 1 ] ;
435
-
436
- }
437
449
450
+ reservedRange . vertexStart = this . _nextVertexStart ;
438
451
if ( vertexCount === - 1 ) {
439
452
440
453
reservedRange . vertexCount = geometry . getAttribute ( 'position' ) . count ;
@@ -445,20 +458,11 @@ class BatchedMesh extends Mesh {
445
458
446
459
}
447
460
448
- if ( lastRange === null ) {
449
-
450
- reservedRange . vertexStart = 0 ;
451
-
452
- } else {
453
-
454
- reservedRange . vertexStart = lastRange . vertexStart + lastRange . vertexCount ;
455
-
456
- }
457
-
458
461
const index = geometry . getIndex ( ) ;
459
462
const hasIndex = index !== null ;
460
463
if ( hasIndex ) {
461
464
465
+ reservedRange . indexStart = this . _nextIndexStart ;
462
466
if ( indexCount === - 1 ) {
463
467
464
468
reservedRange . indexCount = index . count ;
@@ -469,16 +473,6 @@ class BatchedMesh extends Mesh {
469
473
470
474
}
471
475
472
- if ( lastRange === null ) {
473
-
474
- reservedRange . indexStart = 0 ;
475
-
476
- } else {
477
-
478
- reservedRange . indexStart = lastRange . indexStart + lastRange . indexCount ;
479
-
480
- }
481
-
482
476
}
483
477
484
478
if (
@@ -531,6 +525,10 @@ class BatchedMesh extends Mesh {
531
525
// update the geometry
532
526
this . setGeometryAt ( geometryId , geometry ) ;
533
527
528
+ // increment the next geometry position
529
+ this . _nextIndexStart = reservedRange . indexStart + reservedRange . indexCount ;
530
+ this . _nextVertexStart = reservedRange . vertexStart + reservedRange . vertexCount ;
531
+
534
532
return geometryId ;
535
533
536
534
}
@@ -698,41 +696,56 @@ class BatchedMesh extends Mesh {
698
696
let nextVertexStart = 0 ;
699
697
let nextIndexStart = 0 ;
700
698
701
- // iterate over all geometry ranges
699
+ // Iterate over all geometry ranges in order sorted from earliest in the geometry buffer to latest
700
+ // in the geometry buffer. Because draw range objects can be reused there is no guarantee of their order.
702
701
const drawRanges = this . _drawRanges ;
703
702
const reservedRanges = this . _reservedRanges ;
703
+ const indices = drawRanges
704
+ . map ( ( e , i ) => i )
705
+ . sort ( ( a , b ) => {
706
+
707
+ return reservedRanges [ a ] . vertexStart - reservedRanges [ b ] . vertexStart ;
708
+
709
+ } ) ;
710
+
704
711
const geometry = this . geometry ;
705
712
for ( let i = 0 , l = drawRanges . length ; i < l ; i ++ ) {
706
713
707
714
// if a geometry range is inactive then don't copy anything
708
- const drawRange = drawRanges [ i ] ;
709
- const reservedRange = reservedRanges [ i ] ;
715
+ const index = indices [ i ] ;
716
+ const drawRange = drawRanges [ index ] ;
717
+ const reservedRange = reservedRanges [ index ] ;
710
718
if ( drawRange . active === false ) {
711
719
712
720
continue ;
713
721
714
722
}
715
723
716
724
// if a geometry contains an index buffer then shift it, as well
717
- if ( geometry . index !== null && reservedRange . indexStart !== nextIndexStart ) {
725
+ if ( geometry . index !== null ) {
718
726
719
- const { indexStart, indexCount } = reservedRange ;
720
- const index = geometry . index ;
721
- const array = index . array ;
727
+ if ( reservedRange . indexStart !== nextIndexStart ) {
722
728
723
- // shift the index pointers based on how the vertex data will shift
724
- // adjusting the index must happen first so the original vertex start value is available
725
- const elementDelta = nextVertexStart - reservedRange . vertexStart ;
726
- for ( let j = indexStart ; j < indexStart + indexCount ; j ++ ) {
729
+ const { indexStart, indexCount } = reservedRange ;
730
+ const index = geometry . index ;
731
+ const array = index . array ;
727
732
728
- array [ j ] = array [ j ] + elementDelta ;
733
+ // shift the index pointers based on how the vertex data will shift
734
+ // adjusting the index must happen first so the original vertex start value is available
735
+ const elementDelta = nextVertexStart - reservedRange . vertexStart ;
736
+ for ( let j = indexStart ; j < indexStart + indexCount ; j ++ ) {
729
737
730
- }
738
+ array [ j ] = array [ j ] + elementDelta ;
739
+
740
+ }
741
+
742
+ index . array . copyWithin ( nextIndexStart , indexStart , indexStart + indexCount ) ;
743
+ index . addUpdateRange ( nextIndexStart , indexCount ) ;
731
744
732
- index . array . copyWithin ( nextIndexStart , indexStart , indexStart + indexCount ) ;
733
- index . addUpdateRange ( nextIndexStart , indexCount ) ;
745
+ reservedRange . indexStart = nextIndexStart ;
746
+
747
+ }
734
748
735
- reservedRange . indexStart = nextIndexStart ;
736
749
nextIndexStart += reservedRange . indexCount ;
737
750
738
751
}
@@ -752,12 +765,16 @@ class BatchedMesh extends Mesh {
752
765
}
753
766
754
767
reservedRange . vertexStart = nextVertexStart ;
755
- nextVertexStart += reservedRange . vertexCount ;
756
768
757
769
}
758
770
771
+ nextVertexStart += reservedRange . vertexCount ;
759
772
drawRange . start = geometry . index ? reservedRange . indexStart : reservedRange . vertexStart ;
760
773
774
+ // step the next geometry points to the shifted position
775
+ this . _nextIndexStart = geometry . index ? reservedRange . indexStart + reservedRange . indexCount : 0 ;
776
+ this . _nextVertexStart = reservedRange . vertexStart + reservedRange . vertexCount ;
777
+
761
778
}
762
779
763
780
return this ;
@@ -857,9 +874,6 @@ class BatchedMesh extends Mesh {
857
874
858
875
setMatrixAt ( instanceId , matrix ) {
859
876
860
- // @TODO : Map geometryId to index of the arrays because
861
- // optimize() can make geometryId mismatch the index
862
-
863
877
const drawInfo = this . _drawInfo ;
864
878
const matricesTexture = this . _matricesTexture ;
865
879
const matricesArray = this . _matricesTexture . image . data ;
@@ -898,9 +912,6 @@ class BatchedMesh extends Mesh {
898
912
899
913
}
900
914
901
- // @TODO : Map id to index of the arrays because
902
- // optimize() can make id mismatch the index
903
-
904
915
const colorsTexture = this . _colorsTexture ;
905
916
const colorsArray = this . _colorsTexture . image . data ;
906
917
const drawInfo = this . _drawInfo ;
@@ -1055,14 +1066,17 @@ class BatchedMesh extends Mesh {
1055
1066
const matricesTexture = this . _matricesTexture ;
1056
1067
const colorsTexture = this . _colorsTexture ;
1057
1068
1069
+ indirectTexture . dispose ( ) ;
1058
1070
this . _initIndirectTexture ( ) ;
1059
1071
copyArrayContents ( indirectTexture . image . data , this . _indirectTexture . image . data ) ;
1060
1072
1073
+ matricesTexture . dispose ( ) ;
1061
1074
this . _initMatricesTexture ( ) ;
1062
1075
copyArrayContents ( matricesTexture . image . data , this . _matricesTexture . image . data ) ;
1063
1076
1064
1077
if ( colorsTexture ) {
1065
1078
1079
+ colorsTexture . dispose ( ) ;
1066
1080
this . _initColorsTexture ( ) ;
1067
1081
copyArrayContents ( colorsTexture . image . data , this . _colorsTexture . image . data ) ;
1068
1082
@@ -1158,7 +1172,7 @@ class BatchedMesh extends Mesh {
1158
1172
const drawRange = drawRanges [ geometryId ] ;
1159
1173
_mesh . geometry . setDrawRange ( drawRange . start , drawRange . count ) ;
1160
1174
1161
- // ge the intersects
1175
+ // get the intersects
1162
1176
this . getMatrixAt ( i , _mesh . matrixWorld ) . premultiply ( matrixWorld ) ;
1163
1177
this . getBoundingBoxAt ( geometryId , _mesh . geometry . boundingBox ) ;
1164
1178
this . getBoundingSphereAt ( geometryId , _mesh . geometry . boundingSphere ) ;
0 commit comments