Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batched Rendering #1023

Merged
merged 7 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
16 changes: 11 additions & 5 deletions fission/src/mirabuf/MirabufSceneObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ 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)
})
// this._mirabufInstance.meshes.get(part)!.forEach(mesh => {
// mesh.position.setFromMatrixPosition(partTransform)
// mesh.rotation.setFromRotationMatrix(partTransform)
// })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saving this?

const meshes = this._mirabufInstance.meshes.get(part) ?? []
meshes.forEach(([batch, id]) => batch.setMatrixAt(id, partTransform))
})

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

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

public Dispose(): void {
Expand Down
13 changes: 8 additions & 5 deletions fission/src/ui/components/TransformGizmos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,14 @@ 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)
})
// 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)
// })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saving this?


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