@@ -8,6 +8,25 @@ import { ParseErrorSeverity } from "./MirabufParser.ts"
8
8
type MirabufPartInstanceGUID = string
9
9
10
10
const WIREFRAME = false
11
+ const CHROME_VERSION_FOR_INSTANCED_MESH = 139
12
+
13
+ const detectInstancedMeshSupport = ( ) : boolean => {
14
+ const userAgent = navigator . userAgent
15
+ const chromeMatch = userAgent . match ( / C h r o m e \/ ( \d + ) / )
16
+
17
+ if ( chromeMatch ) {
18
+ const chromeVersion = parseInt ( chromeMatch [ 1 ] , 10 )
19
+ console . log (
20
+ `Detected Chrome ${ chromeVersion } , using ${ chromeVersion >= CHROME_VERSION_FOR_INSTANCED_MESH ? "InstancedMesh" : "BatchedMesh" } `
21
+ )
22
+ return chromeVersion >= CHROME_VERSION_FOR_INSTANCED_MESH
23
+ }
24
+
25
+ console . log ( `Non-Chrome browser detected (${ userAgent } ), using BatchedMesh` )
26
+ return false
27
+ }
28
+
29
+ const USE_INSTANCED_MESH = detectInstancedMeshSupport ( )
11
30
12
31
export enum MaterialStyle {
13
32
REGULAR = 0 ,
@@ -93,8 +112,8 @@ const transformGeometry = (geometry: THREE.BufferGeometry, mesh: mirabuf.IMesh)
93
112
class MirabufInstance {
94
113
private _mirabufParser : MirabufParser
95
114
private _materials : Map < string , THREE . Material >
96
- private _meshes : Map < MirabufPartInstanceGUID , Array < [ THREE . BatchedMesh , number ] > >
97
- private _batches : Array < THREE . BatchedMesh >
115
+ private _meshes : Map < MirabufPartInstanceGUID , Array < [ THREE . InstancedMesh | THREE . BatchedMesh , number ] > >
116
+ private _batches : Array < THREE . InstancedMesh | THREE . BatchedMesh >
98
117
99
118
public get parser ( ) {
100
119
return this . _mirabufParser
@@ -160,6 +179,63 @@ class MirabufInstance {
160
179
* Creates ThreeJS meshes from the parsed mirabuf file.
161
180
*/
162
181
private createMeshes ( ) {
182
+ if ( USE_INSTANCED_MESH ) {
183
+ this . createInstancedMeshes ( )
184
+ } else {
185
+ this . createBatchedMeshes ( )
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Creates InstancedMesh objects, as newer version of Chrome break with BatchedMesh
191
+ */
192
+ private createInstancedMeshes ( ) {
193
+ const assembly = this . _mirabufParser . assembly
194
+ const instances = assembly . data ! . parts ! . partInstances !
195
+
196
+ Object . values ( instances ) . forEach ( instance => {
197
+ const definition = assembly . data ! . parts ! . partDefinitions ! [ instance . partDefinitionReference ! ]
198
+ const bodies = definition ?. bodies ?? [ ]
199
+
200
+ bodies . forEach ( body => {
201
+ const mesh = body ?. triangleMesh ?. mesh
202
+ if ( ! mesh ?. verts || ! mesh . normals || ! mesh . uv || ! mesh . indices ) return
203
+
204
+ const appearanceOverride = body . appearanceOverride
205
+ const material = WIREFRAME
206
+ ? new THREE . MeshStandardMaterial ( { wireframe : true , color : 0x000000 } )
207
+ : appearanceOverride && this . _materials . has ( appearanceOverride )
208
+ ? this . _materials . get ( appearanceOverride ) !
209
+ : fillerMaterials [ nextFillerMaterial ++ % fillerMaterials . length ]
210
+
211
+ const geometry = new THREE . BufferGeometry ( )
212
+ transformGeometry ( geometry , mesh )
213
+
214
+ // Create InstancedMesh with count of 1 for this body
215
+ const instancedMesh = new THREE . InstancedMesh ( geometry , material , 1 )
216
+ instancedMesh . castShadow = true
217
+ instancedMesh . receiveShadow = true
218
+
219
+ const mat = this . _mirabufParser . globalTransforms . get ( instance . info ! . GUID ! ) !
220
+ instancedMesh . setMatrixAt ( 0 , mat )
221
+ instancedMesh . instanceMatrix . needsUpdate = true
222
+
223
+ this . _batches . push ( instancedMesh )
224
+
225
+ let bodies = this . _meshes . get ( instance . info ! . GUID ! )
226
+ if ( ! bodies ) {
227
+ bodies = [ ]
228
+ this . _meshes . set ( instance . info ! . GUID ! , bodies )
229
+ }
230
+ bodies . push ( [ instancedMesh , 0 ] )
231
+ } )
232
+ } )
233
+ }
234
+
235
+ /**
236
+ * Creates BatchedMesh, more efficient, but broken in newer versions of Chrome
237
+ */
238
+ private createBatchedMeshes ( ) {
163
239
const assembly = this . _mirabufParser . assembly
164
240
const instances = assembly . data ! . parts ! . partInstances !
165
241
@@ -171,6 +247,7 @@ class MirabufInstance {
171
247
172
248
const batchMap = new Map < THREE . Material , Map < string , [ mirabuf . IBody , Array < mirabuf . IPartInstance > ] > > ( )
173
249
const countMap = new Map < THREE . Material , BatchCounts > ( )
250
+
174
251
// Filter all instances by first material, then body
175
252
Object . values ( instances ) . forEach ( instance => {
176
253
const definition = assembly . data ! . parts ! . partDefinitions ! [ instance . partDefinitionReference ! ]
@@ -180,7 +257,6 @@ class MirabufInstance {
180
257
if ( ! mesh ?. verts || ! mesh . normals || ! mesh . uv || ! mesh . indices ) return
181
258
182
259
const appearanceOverride = body . appearanceOverride
183
-
184
260
const material = WIREFRAME
185
261
? new THREE . MeshStandardMaterial ( { wireframe : true , color : 0x000000 } )
186
262
: appearanceOverride && this . _materials . has ( appearanceOverride )
0 commit comments