model batch untz untz untz

This commit is contained in:
a dinosaur 2024-09-06 23:07:53 +10:00
parent 54ed81b15d
commit 34ec6f71eb
3 changed files with 69 additions and 24 deletions

View File

@ -1,5 +1,4 @@
public struct Material: Hashable {
public struct Material {
public var ambient: Color<Float> public var ambient: Color<Float>
public var diffuse: Color<Float> public var diffuse: Color<Float>
public var specular: Color<Float> public var specular: Color<Float>

View File

@ -5,35 +5,67 @@ public struct ModelBatch {
private var _active = false private var _active = false
private var _cam: Camera! private var _cam: Camera!
private var _env: Environment! private var _env: Environment!
private var _prev: ModelInstance!
private var _instances: [Instance]
internal init(_ renderer: Renderer) { internal init(_ renderer: Renderer) {
self._renderer = renderer self._renderer = renderer
self._instances = Array()
} }
//TODO: Sort, Blend //TODO: Sort, Blend
mutating func begin(camera: Camera, environment: Environment) { public mutating func begin(camera: Camera, environment: Environment) {
self._active = true self._active = true
self._cam = camera self._cam = camera
self._env = environment self._env = environment
self._prev = nil
} }
mutating func end() { private mutating func flush() {
assert(self._instances.count > 0)
if self._instances.count == 1 {
let instance = self._instances.first!
self._renderer.draw(
model: instance.world,
color: instance.color,
mesh: self._prev.mesh,
material: self._prev.material,
environment: self._env,
camera: self._cam)
} else {
self._renderer.batch(
instances: self._instances,
mesh: self._prev.mesh,
material: self._prev.material,
environment: self._env,
camera: self._cam)
}
self._instances.removeAll(keepingCapacity: true)
self._prev = nil
}
public mutating func end() {
if !self._instances.isEmpty {
self.flush()
}
self._cam = nil
self._env = nil
self._active = false self._active = false
} }
mutating func draw(_ model: ModelInstance, position: SIMD3<Float>, color: Color<Float> = .white public mutating func draw(_ model: ModelInstance, position: SIMD3<Float>, color: Color<Float> = .white
) { ) {
self.draw(model, world: .translate(position), color: color) self.draw(model, world: .translate(position), color: color)
} }
mutating func draw(_ model: ModelInstance, public mutating func draw(_ model: ModelInstance,
position: SIMD3<Float>, scale: Float, rotation: simd_quatf, position: SIMD3<Float>, scale: Float, rotation: simd_quatf,
color: Color<Float> = .white color: Color<Float> = .white
) { ) {
self.draw(model, position: position, scale: .init(repeating: scale), rotation: rotation, color: color) self.draw(model, position: position, scale: .init(repeating: scale), rotation: rotation, color: color)
} }
mutating func draw(_ model: ModelInstance, public mutating func draw(_ model: ModelInstance,
position: SIMD3<Float>, scale: SIMD3<Float>, rotation: simd_quatf, position: SIMD3<Float>, scale: SIMD3<Float>, rotation: simd_quatf,
color: Color<Float> = .white color: Color<Float> = .white
) { ) {
@ -44,30 +76,33 @@ public struct ModelBatch {
self.draw(model, world: world, color: color) self.draw(model, world: world, color: color)
} }
mutating func draw(_ model: ModelInstance, world: simd_float4x4, color: Color<Float> = .white) { public mutating func draw(_ model: ModelInstance, world: simd_float4x4, color: Color<Float> = .white) {
assert(self._active) assert(self._active)
self._renderer.draw( if self._prev == nil {
model: world, self._prev = model
color: color.linear, } else if model != self._prev {
mesh: model.mesh, self.flush()
material: model.material, self._prev = model
environment: self._env, }
camera: self._cam)
self._instances.append(.init(
world: world,
color: color.linear))
} }
internal struct Instance { internal struct Instance {
let model: simd_float4x4 let world: simd_float4x4
let color: Color<Float> let color: Color<Float>
init(model: simd_float4x4, color: Color<Float> = .white) { init(world: simd_float4x4, color: Color<Float> = .white) {
self.model = model self.world = world
self.color = color self.color = color
} }
} }
} }
//TODO: delet //TODO: delet
public struct ModelInstance { public struct ModelInstance: Hashable {
let mesh: RendererMesh let mesh: RendererMesh
let material: Material let material: Material
} }

View File

@ -452,8 +452,8 @@ public class Renderer {
for i in 0..<numInstances { for i in 0..<numInstances {
let instance = instances[i] let instance = instances[i]
data[i] = VertexShaderInstance( data[i] = VertexShaderInstance(
model: instance.model, model: instance.world,
normalModel: instance.model.inverse.transpose, normalModel: instance.world.inverse.transpose,
color: SIMD4(instance.color)) color: SIMD4(instance.color))
} }
} }
@ -487,10 +487,21 @@ public class Renderer {
} }
} }
public struct RendererMesh { public struct RendererMesh: Hashable {
fileprivate let _vertBuf: MTLBuffer fileprivate let _vertBuf: MTLBuffer, _idxBuf: MTLBuffer
fileprivate let _idxBuf: MTLBuffer
public let numIndices: Int public let numIndices: Int
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs._vertBuf.gpuAddress == rhs._vertBuf.gpuAddress && lhs._vertBuf.length == rhs._vertBuf.length &&
lhs._vertBuf.gpuAddress == rhs._vertBuf.gpuAddress && lhs._vertBuf.length == rhs._vertBuf.length &&
lhs.numIndices == rhs.numIndices
}
public func hash(into hasher: inout Hasher) {
hasher.combine(self._vertBuf.hash)
hasher.combine(self._idxBuf.hash)
hasher.combine(self.numIndices)
}
} }
extension MTLClearColor { extension MTLClearColor {