Skip to content

Commit 90319aa

Browse files
Hotfix: Chrome Rendering Issue [AARD-2058] (#1262)
Co-authored-by: Alexey Dmitriev <157652245+AlexD717@users.noreply.github.com>
2 parents dd961a3 + a4e70f5 commit 90319aa

File tree

2 files changed

+86
-4
lines changed

2 files changed

+86
-4
lines changed

fission/src/mirabuf/MirabufInstance.ts

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ import { ParseErrorSeverity } from "./MirabufParser.ts"
88
type MirabufPartInstanceGUID = string
99

1010
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(/Chrome\/(\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()
1130

1231
export enum MaterialStyle {
1332
REGULAR = 0,
@@ -93,8 +112,8 @@ const transformGeometry = (geometry: THREE.BufferGeometry, mesh: mirabuf.IMesh)
93112
class MirabufInstance {
94113
private _mirabufParser: MirabufParser
95114
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>
98117

99118
public get parser() {
100119
return this._mirabufParser
@@ -160,6 +179,63 @@ class MirabufInstance {
160179
* Creates ThreeJS meshes from the parsed mirabuf file.
161180
*/
162181
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() {
163239
const assembly = this._mirabufParser.assembly
164240
const instances = assembly.data!.parts!.partInstances!
165241

@@ -171,6 +247,7 @@ class MirabufInstance {
171247

172248
const batchMap = new Map<THREE.Material, Map<string, [mirabuf.IBody, Array<mirabuf.IPartInstance>]>>()
173249
const countMap = new Map<THREE.Material, BatchCounts>()
250+
174251
// Filter all instances by first material, then body
175252
Object.values(instances).forEach(instance => {
176253
const definition = assembly.data!.parts!.partDefinitions![instance.partDefinitionReference!]
@@ -180,7 +257,6 @@ class MirabufInstance {
180257
if (!mesh?.verts || !mesh.normals || !mesh.uv || !mesh.indices) return
181258

182259
const appearanceOverride = body.appearanceOverride
183-
184260
const material = WIREFRAME
185261
? new THREE.MeshStandardMaterial({ wireframe: true, color: 0x000000 })
186262
: appearanceOverride && this._materials.has(appearanceOverride)

fission/src/mirabuf/MirabufSceneObject.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,13 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
471471
.clone()
472472
.premultiply(transform)
473473
const meshes = this._mirabufInstance.meshes.get(part) ?? []
474-
meshes.forEach(([batch, id]) => batch.setMatrixAt(id, partTransform))
474+
meshes.forEach(([mesh, index]) => {
475+
mesh.setMatrixAt(index, partTransform)
476+
// Only update instanceMatrix for InstancedMesh
477+
if ("instanceMatrix" in mesh) {
478+
mesh.instanceMatrix.needsUpdate = true
479+
}
480+
})
475481
})
476482
}
477483

0 commit comments

Comments
 (0)