Skip to content

Commit

Permalink
Batched Rendering (#1023)
Browse files Browse the repository at this point in the history
  • Loading branch information
HunterBarclay authored Jul 16, 2024
2 parents 96185ad + bd073b7 commit e97d4f7
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 34 deletions.
125 changes: 101 additions & 24 deletions fission/src/mirabuf/MirabufInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { mirabuf } from "../proto/mirabuf"
import MirabufParser, { ParseErrorSeverity } from "./MirabufParser.ts"
import World from "@/systems/World.ts"

type MirabufPartInstanceGUID = string

const WIREFRAME = false

export enum MaterialStyle {
Expand Down Expand Up @@ -33,15 +35,21 @@ export const miraMatToString = (mat: mirabuf.ITransform) => {

let nextFillerMaterial = 0
const fillerMaterials = [
new THREE.MeshToonMaterial({
new THREE.MeshStandardMaterial({
color: 0xe32b50,
}),
new THREE.MeshToonMaterial({
new THREE.MeshStandardMaterial({
color: 0x4ccf57,
}),
new THREE.MeshToonMaterial({
new THREE.MeshStandardMaterial({
color: 0xcf4cca,
}),
new THREE.MeshStandardMaterial({
color: 0x585fed,
}),
new THREE.MeshStandardMaterial({
color: 0xade04f,
}),
]

const transformVerts = (mesh: mirabuf.IMesh) => {
Expand Down Expand Up @@ -83,7 +91,8 @@ const transformGeometry = (geometry: THREE.BufferGeometry, mesh: mirabuf.IMesh)
class MirabufInstance {
private _mirabufParser: MirabufParser
private _materials: Map<string, THREE.Material>
private _meshes: Map<string, Array<THREE.Mesh>>
private _meshes: Map<MirabufPartInstanceGUID, Array<[THREE.BatchedMesh, number]>>
private _batches: Array<THREE.BatchedMesh>

public get parser() {
return this._mirabufParser
Expand All @@ -94,6 +103,9 @@ class MirabufInstance {
public get meshes() {
return this._meshes
}
public get batches() {
return this._batches
}

public constructor(parser: MirabufParser, materialStyle?: MaterialStyle) {
if (parser.errors.some(x => x[0] >= ParseErrorSeverity.Unimportable)) {
Expand All @@ -103,6 +115,7 @@ class MirabufInstance {
this._mirabufParser = parser
this._materials = new Map()
this._meshes = new Map()
this._batches = new Array<THREE.BatchedMesh>()

this.LoadMaterials(materialStyle ?? MaterialStyle.Regular)
this.CreateMeshes()
Expand Down Expand Up @@ -145,15 +158,23 @@ class MirabufInstance {
const assembly = this._mirabufParser.assembly
const instances = assembly.data!.parts!.partInstances!

for (const instance of Object.values(instances) /* .filter(x => x.info!.name!.startsWith('EyeBall')) */) {
interface BatchCounts {
maxInstances: number
maxVertices: number
maxIndices: number
}

const batchMap = new Map<THREE.Material, Map<string, [mirabuf.IBody, Array<mirabuf.IPartInstance>]>>()
const countMap = new Map<THREE.Material, BatchCounts>()

// Filter all instances by first material, then body
for (const instance of Object.values(instances)) {
const definition = assembly.data!.parts!.partDefinitions![instance.partDefinitionReference!]!
const bodies = definition.bodies
const meshes = new Array<THREE.Mesh>()
if (bodies) {
for (const body of bodies) {
if (!body) continue
const mesh = body.triangleMesh
const geometry = new THREE.BufferGeometry()
if (
mesh &&
mesh.mesh &&
Expand All @@ -162,29 +183,86 @@ class MirabufInstance {
mesh.mesh.uv &&
mesh.mesh.indices
) {
transformGeometry(geometry, mesh.mesh!)

const appearanceOverride = body.appearanceOverride
const material: THREE.Material = WIREFRAME
? new THREE.MeshStandardMaterial({ wireframe: true, color: 0x000000 })
: appearanceOverride && this._materials.has(appearanceOverride)
? this._materials.get(appearanceOverride)!
: fillerMaterials[nextFillerMaterial++ % fillerMaterials.length]

const threeMesh = new THREE.Mesh(geometry, material)
threeMesh.receiveShadow = true
threeMesh.castShadow = true
let materialBodyMap = batchMap.get(material)
if (!materialBodyMap) {
materialBodyMap = new Map<string, [mirabuf.IBody, Array<mirabuf.IPartInstance>]>()
batchMap.set(material, materialBodyMap)
}

meshes.push(threeMesh)
const partBodyGuid = this.GetPartBodyGuid(definition, body)
let bodyInstances = materialBodyMap.get(partBodyGuid)
if (!bodyInstances) {
bodyInstances = [body, new Array<mirabuf.IPartInstance>()]
materialBodyMap.set(partBodyGuid, bodyInstances)
}
bodyInstances[1].push(instance)

const mat = this._mirabufParser.globalTransforms.get(instance.info!.GUID!)!
threeMesh.position.setFromMatrixPosition(mat)
threeMesh.rotation.setFromRotationMatrix(mat)
if (countMap.has(material)) {
const count = countMap.get(material)!
count.maxInstances += 1
count.maxVertices += mesh.mesh.verts.length / 3
count.maxIndices += mesh.mesh.indices.length
} else {
const count: BatchCounts = {
maxInstances: 1,
maxVertices: mesh.mesh.verts.length / 3,
maxIndices: mesh.mesh.indices.length,
}
countMap.set(material, count)
}
}
}
}
this._meshes.set(instance.info!.GUID!, meshes)
}

console.debug(batchMap)

// Construct batched meshes
batchMap.forEach((materialBodyMap, material) => {
const count = countMap.get(material)!
const batchedMesh = new THREE.BatchedMesh(count.maxInstances, count.maxVertices, count.maxIndices)
this._batches.push(batchedMesh)

console.debug(`${count.maxInstances}, ${count.maxVertices}, ${count.maxIndices}`)

batchedMesh.material = material
batchedMesh.castShadow = true
batchedMesh.receiveShadow = true

materialBodyMap.forEach(instances => {
const body = instances[0]
instances[1].forEach(instance => {
const mat = this._mirabufParser.globalTransforms.get(instance.info!.GUID!)!

const geometry = new THREE.BufferGeometry()
transformGeometry(geometry, body.triangleMesh!.mesh!)
const geoId = batchedMesh.addGeometry(geometry)

batchedMesh.setMatrixAt(geoId, mat)

console.debug(geoId)

let bodies = this._meshes.get(instance.info!.GUID!)
if (!bodies) {
bodies = new Array<[THREE.BatchedMesh, number]>()
this._meshes.set(instance.info!.GUID!, bodies)
}

bodies.push([batchedMesh, geoId])
})
})
})
}

private GetPartBodyGuid(partDef: mirabuf.IPartDefinition, body: mirabuf.IPartDefinition) {
return `${partDef.info!.GUID!}_BODY_${body.info!.GUID!}`
}

/**
Expand All @@ -193,19 +271,18 @@ class MirabufInstance {
* @param scene
*/
public AddToScene(scene: THREE.Scene) {
this._meshes.forEach(x => x.forEach(y => scene.add(y)))
this._batches.forEach(x => scene.add(x))
}

/**
* Disposes of all ThreeJs scenes and materials.
*/
public Dispose(scene: THREE.Scene) {
this._meshes.forEach(x =>
x.forEach(y => {
y.geometry.dispose()
scene.remove(y)
})
)
this._batches.forEach(x => {
x.dispose()
scene.remove(x)
})
this._batches = []
this._meshes.clear()

this._materials.forEach(x => x.dispose())
Expand Down
12 changes: 7 additions & 5 deletions fission/src/mirabuf/MirabufSceneObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,8 @@ class MirabufSceneObject extends SceneObject {
.get(part)!
.clone()
.premultiply(transform)
this._mirabufInstance.meshes.get(part)!.forEach(mesh => {
// iterating through each mesh and updating their position and rotation
mesh.position.setFromMatrixPosition(partTransform)
mesh.rotation.setFromRotationMatrix(partTransform)
})
const meshes = this._mirabufInstance.meshes.get(part) ?? []
meshes.forEach(([batch, id]) => batch.setMatrixAt(id, partTransform))
})

/**
Expand Down Expand Up @@ -203,6 +200,11 @@ class MirabufSceneObject extends SceneObject {
comMesh.rotation.setFromRotationMatrix(comTransform)
}
})

this._mirabufInstance.batches.forEach(x => {
x.computeBoundingBox()
x.computeBoundingSphere()
})
}

public Dispose(): void {
Expand Down
8 changes: 3 additions & 5 deletions fission/src/ui/components/TransformGizmos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,9 @@ class TransformGizmos {
.get(part)!
.clone()
.premultiply(this.mesh.matrix)
obj.mirabufInstance.meshes.get(part)!.forEach(mesh => {
// iterating through each mesh and updating their position and rotation
mesh.position.setFromMatrixPosition(partTransform)
mesh.rotation.setFromRotationMatrix(partTransform)
})

const meshes = obj.mirabufInstance.meshes.get(part) ?? []
meshes.forEach(([batch, id]) => batch.setMatrixAt(id, partTransform))
})
}
}
Expand Down

0 comments on commit e97d4f7

Please sign in to comment.