mirror of
https://github.com/GayPizzaSpecifications/voxelotl-engine.git
synced 2025-08-02 21:00:57 +00:00
un-hardcode various render properties (environment, material)
This commit is contained in:
parent
7a417e0701
commit
428b142bf2
@ -57,6 +57,8 @@ public class Application {
|
||||
printErr("Renderer init error: unexpected error")
|
||||
}
|
||||
|
||||
self.del.create(renderer!)
|
||||
|
||||
lastCounter = SDL_GetPerformanceCounter()
|
||||
return .running
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ add_executable(Voxelotl MACOSX_BUNDLE
|
||||
# Resource classes
|
||||
NSImageLoader.swift
|
||||
|
||||
# Renderer classes
|
||||
Renderer/Material.swift
|
||||
Renderer/Environment.swift
|
||||
Renderer/Renderer.swift
|
||||
|
||||
# Input wrappers
|
||||
Input/Keyboard.swift
|
||||
Input/GameController.swift
|
||||
@ -34,7 +39,6 @@ add_executable(Voxelotl MACOSX_BUNDLE
|
||||
# Core utility classes
|
||||
Color.swift
|
||||
Camera.swift
|
||||
Renderer.swift
|
||||
FPSCalculator.swift
|
||||
GameDelegate.swift
|
||||
Application.swift
|
||||
@ -85,3 +89,4 @@ source_group("Source Files" REGULAR_EXPRESSION "\\.(swift|metal)$")
|
||||
source_group("Source Files\\Random" REGULAR_EXPRESSION "Random/")
|
||||
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
|
||||
source_group("Source Files\\Input" REGULAR_EXPRESSION "Input/")
|
||||
source_group("Source Files\\Renderer" REGULAR_EXPRESSION "Renderer/")
|
||||
|
@ -26,9 +26,11 @@ class Game: GameDelegate {
|
||||
var projection: matrix_float4x4 = .identity
|
||||
var chunk = Chunk(position: .zero)
|
||||
|
||||
init() {
|
||||
func create(_ renderer: Renderer) {
|
||||
self.resetPlayer()
|
||||
self.generateWorld()
|
||||
|
||||
renderer.clearColor = Color<Double>.black.mix(.white, 0.1).linear
|
||||
}
|
||||
|
||||
private func resetPlayer() {
|
||||
@ -103,6 +105,15 @@ class Game: GameDelegate {
|
||||
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)
|
||||
|
||||
var instances = chunk.compactMap { block, position in
|
||||
if case let .solid(color) = block.type {
|
||||
Instance(
|
||||
@ -121,7 +132,7 @@ class Game: GameDelegate {
|
||||
.init(angle: totalTime * 0.7, axis: .init(0, 0, 1)),
|
||||
color: .init(r: 0.5, g: 0.5, b: 1).linear))
|
||||
if !instances.isEmpty {
|
||||
renderer.batch(instances: instances, camera: self.camera)
|
||||
renderer.batch(instances: instances, material: material, environment: env, camera: self.camera)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
public protocol GameDelegate {
|
||||
func create(_ renderer: Renderer)
|
||||
func fixedUpdate(_ time: GameTime)
|
||||
func update(_ time: GameTime)
|
||||
func draw(_ renderer: Renderer, _ time: GameTime)
|
||||
|
@ -203,7 +203,7 @@ struct Player {
|
||||
chunk: chunk,
|
||||
origin: self.eyePosition,
|
||||
direction: .forward * simd_matrix3x3(self.eyeRotation),
|
||||
maxDistance: 3.666
|
||||
maxDistance: 3.8
|
||||
) {
|
||||
self.rayhitPos = hit.position
|
||||
if destroy {
|
||||
|
6
Sources/Voxelotl/Renderer/Environment.swift
Normal file
6
Sources/Voxelotl/Renderer/Environment.swift
Normal file
@ -0,0 +1,6 @@
|
||||
public struct Environment {
|
||||
public var cullFace: Face
|
||||
public var lightDirection: SIMD3<Float>
|
||||
|
||||
public enum Face { case none, front, back }
|
||||
}
|
7
Sources/Voxelotl/Renderer/Material.swift
Normal file
7
Sources/Voxelotl/Renderer/Material.swift
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
public struct Material {
|
||||
public var ambient: Color<Float16>
|
||||
public var diffuse: Color<Float16>
|
||||
public var specular: Color<Float16>
|
||||
public var gloss: Float
|
||||
}
|
@ -5,30 +5,30 @@ import simd
|
||||
import ShaderTypes
|
||||
|
||||
fileprivate let cubeVertices: [ShaderVertex] = [
|
||||
.init(position: .init(-1, -1, 1, 1), normal: .init( 0, 0, 1, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init( 1, -1, 1, 1), normal: .init( 0, 0, 1, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init(-1, 1, 1, 1), normal: .init( 0, 0, 1, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init( 1, 1, 1, 1), normal: .init( 0, 0, 1, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init( 1, -1, 1, 1), normal: .init( 1, 0, 0, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init( 1, -1, -1, 1), normal: .init( 1, 0, 0, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init( 1, 1, 1, 1), normal: .init( 1, 0, 0, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init( 1, 1, -1, 1), normal: .init( 1, 0, 0, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init( 1, -1, -1, 1), normal: .init( 0, 0, -1, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init(-1, -1, -1, 1), normal: .init( 0, 0, -1, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init( 1, 1, -1, 1), normal: .init( 0, 0, -1, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init(-1, 1, -1, 1), normal: .init( 0, 0, -1, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init(-1, -1, -1, 1), normal: .init(-1, 0, 0, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init(-1, -1, 1, 1), normal: .init(-1, 0, 0, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init(-1, 1, -1, 1), normal: .init(-1, 0, 0, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init(-1, 1, 1, 1), normal: .init(-1, 0, 0, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init(-1, -1, -1, 1), normal: .init( 0, -1, 0, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init( 1, -1, -1, 1), normal: .init( 0, -1, 0, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init(-1, -1, 1, 1), normal: .init( 0, -1, 0, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init( 1, -1, 1, 1), normal: .init( 0, -1, 0, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init(-1, 1, 1, 1), normal: .init( 0, 1, 0, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init( 1, 1, 1, 1), normal: .init( 0, 1, 0, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init(-1, 1, -1, 1), normal: .init( 0, 1, 0, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init( 1, 1, -1, 1), normal: .init( 0, 1, 0, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init(-1, -1, 1, 1), normal: .init(.back, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init( 1, -1, 1, 1), normal: .init(.back, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init(-1, 1, 1, 1), normal: .init(.back, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init( 1, 1, 1, 1), normal: .init(.back, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init( 1, -1, 1, 1), normal: .init(.right, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init( 1, -1, -1, 1), normal: .init(.right, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init( 1, 1, 1, 1), normal: .init(.right, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init( 1, 1, -1, 1), normal: .init(.right, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init( 1, -1, -1, 1), normal: .init(.forward, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init(-1, -1, -1, 1), normal: .init(.forward, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init( 1, 1, -1, 1), normal: .init(.forward, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init(-1, 1, -1, 1), normal: .init(.forward, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init(-1, -1, -1, 1), normal: .init(.left, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init(-1, -1, 1, 1), normal: .init(.left, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init(-1, 1, -1, 1), normal: .init(.left, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init(-1, 1, 1, 1), normal: .init(.left, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init(-1, -1, -1, 1), normal: .init(.down, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init( 1, -1, -1, 1), normal: .init(.down, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init(-1, -1, 1, 1), normal: .init(.down, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init( 1, -1, 1, 1), normal: .init(.down, 0), texCoord: .init(1, 1)),
|
||||
.init(position: .init(-1, 1, 1, 1), normal: .init(.up, 0), texCoord: .init(0, 0)),
|
||||
.init(position: .init( 1, 1, 1, 1), normal: .init(.up, 0), texCoord: .init(1, 0)),
|
||||
.init(position: .init(-1, 1, -1, 1), normal: .init(.up, 0), texCoord: .init(0, 1)),
|
||||
.init(position: .init( 1, 1, -1, 1), normal: .init(.up, 0), texCoord: .init(1, 1)),
|
||||
]
|
||||
|
||||
fileprivate let cubeIndices: [UInt16] = [
|
||||
@ -43,12 +43,12 @@ fileprivate let cubeIndices: [UInt16] = [
|
||||
fileprivate let numFramesInFlight: Int = 3
|
||||
fileprivate let colorFormat: MTLPixelFormat = .bgra8Unorm_srgb
|
||||
fileprivate let depthFormat: MTLPixelFormat = .depth32Float
|
||||
fileprivate let clearColor: Color<Double> = .black.mix(.white, 0.1).linear
|
||||
|
||||
public class Renderer {
|
||||
private var device: MTLDevice
|
||||
private var layer: CAMetalLayer
|
||||
private var backBufferSize: Size<Int>
|
||||
private var _clearColor: Color<Double>
|
||||
private var _aspectRatio: Float
|
||||
private var queue: MTLCommandQueue
|
||||
private var lib: MTLLibrary
|
||||
@ -70,6 +70,10 @@ public class Renderer {
|
||||
|
||||
var frame: Rect<Int> { .init(origin: .zero, size: self.backBufferSize) }
|
||||
var aspectRatio: Float { self._aspectRatio }
|
||||
var clearColor: Color<Double> {
|
||||
get { self._clearColor }
|
||||
set { self._clearColor = newValue }
|
||||
}
|
||||
|
||||
fileprivate static func createMetalDevice() -> MTLDevice? {
|
||||
MTLCopyAllDevices().reduce(nil, { best, dev in
|
||||
@ -100,10 +104,10 @@ public class Renderer {
|
||||
|
||||
self.backBufferSize = size
|
||||
self._aspectRatio = Float(self.backBufferSize.w) / Float(self.backBufferSize.w)
|
||||
self._clearColor = .black
|
||||
|
||||
passDescription.colorAttachments[0].loadAction = .clear
|
||||
passDescription.colorAttachments[0].storeAction = .store
|
||||
passDescription.colorAttachments[0].clearColor = MTLClearColor(clearColor)
|
||||
passDescription.depthAttachment.loadAction = .clear
|
||||
passDescription.depthAttachment.storeAction = .dontCare
|
||||
passDescription.depthAttachment.clearDepth = 1.0
|
||||
@ -302,6 +306,7 @@ public class Renderer {
|
||||
throw RendererError.drawFailure("Failed to get next drawable render target")
|
||||
}
|
||||
|
||||
passDescription.colorAttachments[0].clearColor = MTLClearColor(self._clearColor)
|
||||
passDescription.colorAttachments[0].texture = rt.texture
|
||||
passDescription.depthAttachment.texture = self.depthTextures[self.currentFrame]
|
||||
|
||||
@ -319,7 +324,6 @@ public class Renderer {
|
||||
throw RendererError.drawFailure("Failed to make render encoder from command buffer")
|
||||
}
|
||||
|
||||
encoder.setCullMode(.back)
|
||||
encoder.setFrontFacing(.counterClockwise) // OpenGL default
|
||||
encoder.setViewport(Self.makeViewport(rect: self.frame))
|
||||
encoder.setRenderPipelineState(pso)
|
||||
@ -342,17 +346,17 @@ public class Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
func batch(instances: [Instance], camera: Camera) {
|
||||
func batch(instances: [Instance], 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(.init(0.75, -1, 0.5)),
|
||||
ambientColor: SIMD4(Color(rgba8888: 0x1F1F1F00).linear),
|
||||
diffuseColor: SIMD4(Color(rgba8888: 0xEFEFEF00).linear),
|
||||
specularColor: SIMD4(Color(rgba8888: 0x7F7F7F00).linear),
|
||||
specularIntensity: 50)
|
||||
directionalLight: normalize(environment.lightDirection),
|
||||
ambientColor: SIMD4(Color<Float>(material.ambient)),
|
||||
diffuseColor: SIMD4(Color<Float>(material.diffuse)),
|
||||
specularColor: SIMD4(Color<Float>(material.specular)),
|
||||
specularIntensity: material.gloss)
|
||||
|
||||
let numInstances = instances.count
|
||||
let instancesBytes = numInstances * MemoryLayout<VertexShaderInstance>.stride
|
||||
@ -385,6 +389,8 @@ public class Renderer {
|
||||
}
|
||||
instanceBuffer.didModifyRange(0..<instancesBytes)
|
||||
|
||||
self._encoder.setCullMode(.init(environment.cullFace))
|
||||
|
||||
self._encoder.setVertexBuffer(instanceBuffer,
|
||||
offset: 0,
|
||||
index: VertexShaderInputIdx.instance.rawValue)
|
||||
@ -412,6 +418,16 @@ extension MTLClearColor {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension MTLCullMode {
|
||||
init(_ face: Environment.Face) {
|
||||
self = switch face {
|
||||
case .none: .none
|
||||
case .front: .front
|
||||
case .back: .back
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum RendererError: Error {
|
||||
case initFailure(_ message: String)
|
||||
case loadFailure(_ message: String)
|
Loading…
Reference in New Issue
Block a user