From 2a11080ebac2aa0db05efa058880f1fec35d7a7b Mon Sep 17 00:00:00 2001 From: a dinosaur Date: Fri, 6 Sep 2024 23:54:23 +1000 Subject: [PATCH] move some shared binds to a setup stage --- Sources/Voxelotl/Game.swift | 15 ++-- Sources/Voxelotl/Renderer/Environment.swift | 1 + Sources/Voxelotl/Renderer/ModelBatch.swift | 20 +----- Sources/Voxelotl/Renderer/Renderer.swift | 79 ++++++++------------- 4 files changed, 41 insertions(+), 74 deletions(-) diff --git a/Sources/Voxelotl/Game.swift b/Sources/Voxelotl/Game.swift index 6871058..ab51996 100644 --- a/Sources/Voxelotl/Game.swift +++ b/Sources/Voxelotl/Game.swift @@ -84,17 +84,18 @@ class Game: GameDelegate { self.world.update() } + public static let material = Material( + ambient: Color(rgba8888: 0x4F4F4F00).linear, + diffuse: Color(rgba8888: 0xDFDFDF00).linear, + specular: Color(rgba8888: 0x2F2F2F00).linear, + gloss: 75) + func draw(_ renderer: Renderer, _ time: GameTime) { let totalTime = Float(time.total.asFloat) let env = Environment( cullFace: .back, lightDirection: .init(0.75, -1, 0.5)) - let material = Material( - ambient: Color(rgba8888: 0x4F4F4F00).linear, - diffuse: Color(rgba8888: 0xDFDFDF00).linear, - specular: Color(rgba8888: 0x2F2F2F00).linear, - gloss: 75) // Update chunk meshes if needed self.world.handleRenderDamagedChunks { id, chunk in @@ -109,7 +110,7 @@ class Game: GameDelegate { continue } let drawPos = SIMD3(id &<< Chunk.shift) - self.modelBatch.draw(.init(mesh: chunk!, material: material), position: drawPos) + self.modelBatch.draw(.init(mesh: chunk!, material: Self.material), position: drawPos) } if let position = player.rayhitPos { @@ -117,7 +118,7 @@ class Game: GameDelegate { .init(angle: totalTime * 3.0, axis: .Y) * .init(angle: totalTime * 1.5, axis: .X) * .init(angle: totalTime * 0.7, axis: .Z) - self.modelBatch.draw(.init(mesh: self.cubeMesh!, material: material), + self.modelBatch.draw(.init(mesh: self.cubeMesh!, material: Self.material), position: position, scale: 0.0725 * 0.5, rotation: rotation, color: .init(r: 0.5, g: 0.5, b: 1)) } diff --git a/Sources/Voxelotl/Renderer/Environment.swift b/Sources/Voxelotl/Renderer/Environment.swift index 6481ba0..7c865d0 100644 --- a/Sources/Voxelotl/Renderer/Environment.swift +++ b/Sources/Voxelotl/Renderer/Environment.swift @@ -1,3 +1,4 @@ +//TODO: Sort, Blend public struct Environment { public var cullFace: Face public var lightDirection: SIMD3 diff --git a/Sources/Voxelotl/Renderer/ModelBatch.swift b/Sources/Voxelotl/Renderer/ModelBatch.swift index c351a51..1f4e399 100644 --- a/Sources/Voxelotl/Renderer/ModelBatch.swift +++ b/Sources/Voxelotl/Renderer/ModelBatch.swift @@ -13,33 +13,17 @@ public struct ModelBatch { self._instances = Array() } - //TODO: Sort, Blend public mutating func begin(camera: Camera, environment: Environment) { self._active = true self._cam = camera self._env = environment self._prev = nil + self._renderer.setupBatch(material: Game.material, environment: environment, camera: camera) } 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._renderer.submitBatch(mesh: self._prev.mesh, instances: self._instances) self._instances.removeAll(keepingCapacity: true) self._prev = nil } diff --git a/Sources/Voxelotl/Renderer/Renderer.swift b/Sources/Voxelotl/Renderer/Renderer.swift index 52a9fe7..9733d32 100644 --- a/Sources/Voxelotl/Renderer/Renderer.swift +++ b/Sources/Voxelotl/Renderer/Renderer.swift @@ -22,7 +22,7 @@ public class Renderer { private let _defaultStorageMode: MTLResourceOptions private var depthTextures: [MTLTexture] - private var _instances: [MTLBuffer?] + //private var _instances: [MTLBuffer?] private var _encoder: MTLRenderCommandEncoder! = nil @@ -99,7 +99,7 @@ public class Renderer { return depthStencilTexture } - self._instances = [MTLBuffer?](repeating: nil, count: numFramesInFlight) + //self._instances = [MTLBuffer?](repeating: nil, count: numFramesInFlight) let stencilDepthDescription = MTLDepthStencilDescriptor() stencilDepthDescription.depthCompareFunction = .less // OpenGL default @@ -377,8 +377,12 @@ public class Renderer { } } - func draw(model: matrix_float4x4, color: Color, mesh: RendererMesh, material: Material, environment: Environment, camera: Camera) { - assert(self._encoder != nil, "draw can't be called outside of a frame being rendered") + func createModelBatch() -> ModelBatch { + return ModelBatch(self) + } + + internal func setupBatch(material: Material, environment: Environment, camera: Camera) { + assert(self._encoder != nil, "startBatch can't be called outside of a frame being rendered") var vertUniforms = VertexShaderUniforms(projView: camera.viewProjection) var fragUniforms = FragmentShaderUniforms( @@ -388,50 +392,24 @@ public class Renderer { diffuseColor: SIMD4(material.diffuse), specularColor: SIMD4(material.specular), specularIntensity: material.gloss) - var instance = VertexShaderInstance( - model: model, - normalModel: model.inverse.transpose, - color: SIMD4(color)) self._encoder.setCullMode(.init(environment.cullFace)) - self._encoder.setVertexBuffer(mesh._vertBuf, offset: 0, index: VertexShaderInputIdx.vertices.rawValue) // Ideal as long as our uniforms total 4 KB or less - self._encoder.setVertexBytes(&instance, - length: MemoryLayout.stride, - index: VertexShaderInputIdx.instance.rawValue) self._encoder.setVertexBytes(&vertUniforms, length: MemoryLayout.stride, index: VertexShaderInputIdx.uniforms.rawValue) self._encoder.setFragmentBytes(&fragUniforms, length: MemoryLayout.stride, index: FragmentShaderInputIdx.uniforms.rawValue) - - self._encoder.drawIndexedPrimitives( - type: .triangle, - indexCount: mesh.numIndices, - indexType: .uint16, - indexBuffer: mesh._idxBuf, - indexBufferOffset: 0) } - func createModelBatch() -> ModelBatch { - return ModelBatch(self) - } - - func batch(instances: [ModelBatch.Instance], mesh: RendererMesh, material: Material, environment: Environment, camera: Camera) { - assert(self._encoder != nil, "batch can't be called outside of a frame being rendered") - - var vertUniforms = VertexShaderUniforms(projView: camera.viewProjection) - var fragUniforms = FragmentShaderUniforms( - cameraPosition: camera.position, - directionalLight: normalize(environment.lightDirection), - ambientColor: SIMD4(material.ambient), - diffuseColor: SIMD4(material.diffuse), - specularColor: SIMD4(material.specular), - specularIntensity: material.gloss) - + internal func submitBatch(mesh: RendererMesh, instances: [ModelBatch.Instance]) { + assert(self._encoder != nil, "submitBatch can't be called outside of a frame being rendered") let numInstances = instances.count + assert(numInstances > 0, "submitBatch called with zero instances") + + /* let instancesBytes = numInstances * MemoryLayout.stride // (Re)create instance buffer if needed @@ -463,27 +441,30 @@ public class Renderer { } #endif - self._encoder.setCullMode(.init(environment.cullFace)) - - self._encoder.setVertexBuffer(mesh._vertBuf, offset: 0, index: VertexShaderInputIdx.vertices.rawValue) self._encoder.setVertexBuffer(instanceBuffer, offset: 0, index: VertexShaderInputIdx.instance.rawValue) + */ + let instanceData = instances.map { instance in + VertexShaderInstance( + model: instance.world, + normalModel: instance.world.inverse.transpose, + color: SIMD4(instance.color)) + } + + self._encoder.setVertexBuffer(mesh._vertBuf, offset: 0, index: VertexShaderInputIdx.vertices.rawValue) // Ideal as long as our uniforms total 4 KB or less - self._encoder.setVertexBytes(&vertUniforms, - length: MemoryLayout.stride, - index: VertexShaderInputIdx.uniforms.rawValue) - self._encoder.setFragmentBytes(&fragUniforms, - length: MemoryLayout.stride, - index: FragmentShaderInputIdx.uniforms.rawValue) + self._encoder.setVertexBytes(instanceData, + length: numInstances * MemoryLayout.stride, + index: VertexShaderInputIdx.instance.rawValue) self._encoder.drawIndexedPrimitives( - type: .triangle, - indexCount: mesh.numIndices, - indexType: .uint16, - indexBuffer: mesh._idxBuf, + type: .triangle, + indexCount: mesh.numIndices, + indexType: .uint16, + indexBuffer: mesh._idxBuf, indexBufferOffset: 0, - instanceCount: numInstances) + instanceCount: numInstances) } }