@@ -12,6 +12,12 @@ import { Frustum } from '../math/Frustum.js';
12
12
import { Vector3 } from '../math/Vector3.js' ;
13
13
import { Color } from '../math/Color.js' ;
14
14
15
+ function ascIdSort ( a , b ) {
16
+
17
+ return a - b ;
18
+
19
+ }
20
+
15
21
function sortOpaque ( a , b ) {
16
22
17
23
return a . z - b . z ;
@@ -123,6 +129,14 @@ function copyAttributeData( src, target, targetOffset = 0 ) {
123
129
124
130
}
125
131
132
+ // safely copies array contents to a potentially smaller array
133
+ function copyArrayContents ( src , target ) {
134
+
135
+ const len = Math . min ( src . length , target . length ) ;
136
+ target . set ( new src . constructor ( src . buffer , 0 , len ) ) ;
137
+
138
+ }
139
+
126
140
class BatchedMesh extends Mesh {
127
141
128
142
get maxInstanceCount ( ) {
@@ -368,7 +382,9 @@ class BatchedMesh extends Mesh {
368
382
// Prioritize using previously freed instance ids
369
383
if ( this . _availableInstanceIds . length > 0 ) {
370
384
371
- drawId = this . _availableInstanceIds . pop ( ) ;
385
+ this . _availableInstanceIds . sort ( ascIdSort ) ;
386
+
387
+ drawId = this . _availableInstanceIds . shift ( ) ;
372
388
this . _drawInfo [ drawId ] = instanceDrawInfo ;
373
389
374
390
} else {
@@ -494,7 +510,9 @@ class BatchedMesh extends Mesh {
494
510
let geometryId ;
495
511
if ( this . _availableGeometryIds . length > 0 ) {
496
512
497
- geometryId = this . _availableGeometryIds . pop ( ) ;
513
+ this . _availableGeometryIds . sort ( ascIdSort ) ;
514
+
515
+ geometryId = this . _availableGeometryIds . shift ( ) ;
498
516
reservedRanges [ geometryId ] = reservedRange ;
499
517
drawRanges [ geometryId ] = drawRange ;
500
518
bounds [ geometryId ] = boundsInfo ;
@@ -1002,6 +1020,109 @@ class BatchedMesh extends Mesh {
1002
1020
1003
1021
}
1004
1022
1023
+ setInstanceCount ( maxInstanceCount ) {
1024
+
1025
+ // shrink the available instances as much as possible
1026
+ const availableInstanceIds = this . _availableInstanceIds ;
1027
+ const drawInfo = this . _drawInfo ;
1028
+ availableInstanceIds . sort ( ascIdSort ) ;
1029
+ while ( availableInstanceIds [ availableInstanceIds . length - 1 ] === drawInfo . length ) {
1030
+
1031
+ drawInfo . pop ( ) ;
1032
+ availableInstanceIds . pop ( ) ;
1033
+
1034
+ }
1035
+
1036
+ // throw an error if it can't be shrunk to the desired size
1037
+ if ( maxInstanceCount < drawInfo . length ) {
1038
+
1039
+ throw new Error ( `BatchedMesh: Instance ids outside the range ${ maxInstanceCount } are being used. Cannot shrink instance count.` ) ;
1040
+
1041
+ }
1042
+
1043
+ // copy the multi draw counts
1044
+ const multiDrawCounts = new Int32Array ( maxInstanceCount ) ;
1045
+ const multiDrawStarts = new Int32Array ( maxInstanceCount ) ;
1046
+ copyArrayContents ( this . _multiDrawCounts , multiDrawCounts ) ;
1047
+ copyArrayContents ( this . _multiDrawStarts , multiDrawStarts ) ;
1048
+
1049
+ this . _multiDrawCounts = multiDrawCounts ;
1050
+ this . _multiDrawStarts = multiDrawStarts ;
1051
+ this . _maxInstanceCount = maxInstanceCount ;
1052
+
1053
+ // update texture data for instance sampling
1054
+ const indirectTexture = this . _indirectTexture ;
1055
+ const matricesTexture = this . _matricesTexture ;
1056
+ const colorsTexture = this . _colorsTexture ;
1057
+
1058
+ this . _initIndirectTexture ( ) ;
1059
+ copyArrayContents ( indirectTexture . image . data , this . _indirectTexture . image . data ) ;
1060
+
1061
+ this . _initMatricesTexture ( ) ;
1062
+ copyArrayContents ( matricesTexture . image . data , this . _matricesTexture . image . data ) ;
1063
+
1064
+ if ( colorsTexture ) {
1065
+
1066
+ this . _initColorsTexture ( ) ;
1067
+ copyArrayContents ( colorsTexture . image . data , this . _colorsTexture . image . data ) ;
1068
+
1069
+ }
1070
+
1071
+ }
1072
+
1073
+ setGeometrySize ( maxVertexCount , maxIndexCount ) {
1074
+
1075
+ // Check if we can shrink to the requested vertex attribute size
1076
+ const validRanges = [ ...this . _reservedRanges ] . filter ( ( range , i ) => this . _drawRanges [ i ] . active ) ;
1077
+ const requiredVertexLength = Math . max ( ...validRanges . map ( range => range . vertexStart + range . vertexCount ) ) ;
1078
+ if ( requiredVertexLength > maxVertexCount ) {
1079
+
1080
+ throw new Error ( `BatchedMesh: Geometry vertex values are being used outside the range ${ maxIndexCount } . Cannot shrink further.` ) ;
1081
+
1082
+ }
1083
+
1084
+ // Check if we can shrink to the requested index attribute size
1085
+ if ( this . geometry . index ) {
1086
+
1087
+ const requiredIndexLength = Math . max ( ...validRanges . map ( range => range . indexStart + range . indexCount ) ) ;
1088
+ if ( requiredIndexLength > maxIndexCount ) {
1089
+
1090
+ throw new Error ( `BatchedMesh: Geometry index values are being used outside the range ${ maxIndexCount } . Cannot shrink further.` ) ;
1091
+
1092
+ }
1093
+
1094
+ }
1095
+
1096
+ //
1097
+
1098
+ // dispose of the previous geometry
1099
+ const oldGeometry = this . geometry ;
1100
+ oldGeometry . dispose ( ) ;
1101
+
1102
+ // recreate the geometry needed based on the previous variant
1103
+ this . _maxVertexCount = maxVertexCount ;
1104
+ this . _maxIndexCount = maxIndexCount ;
1105
+ this . _geometryInitialized = false ;
1106
+
1107
+ this . geometry = new BufferGeometry ( ) ;
1108
+ this . _initializeGeometry ( oldGeometry ) ;
1109
+
1110
+ // copy data from the previous geometry
1111
+ const geometry = this . geometry ;
1112
+ if ( oldGeometry . index ) {
1113
+
1114
+ copyArrayContents ( oldGeometry . index . array , geometry . index . array ) ;
1115
+
1116
+ }
1117
+
1118
+ for ( const key in oldGeometry . attributes ) {
1119
+
1120
+ copyArrayContents ( oldGeometry . attributes [ key ] . array , geometry . attributes [ key ] . array ) ;
1121
+
1122
+ }
1123
+
1124
+ }
1125
+
1005
1126
raycast ( raycaster , intersects ) {
1006
1127
1007
1128
const drawInfo = this . _drawInfo ;
0 commit comments