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")
|
printErr("Renderer init error: unexpected error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.del.create(renderer!)
|
||||||
|
|
||||||
lastCounter = SDL_GetPerformanceCounter()
|
lastCounter = SDL_GetPerformanceCounter()
|
||||||
return .running
|
return .running
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,11 @@ add_executable(Voxelotl MACOSX_BUNDLE
|
|||||||
# Resource classes
|
# Resource classes
|
||||||
NSImageLoader.swift
|
NSImageLoader.swift
|
||||||
|
|
||||||
|
# Renderer classes
|
||||||
|
Renderer/Material.swift
|
||||||
|
Renderer/Environment.swift
|
||||||
|
Renderer/Renderer.swift
|
||||||
|
|
||||||
# Input wrappers
|
# Input wrappers
|
||||||
Input/Keyboard.swift
|
Input/Keyboard.swift
|
||||||
Input/GameController.swift
|
Input/GameController.swift
|
||||||
@ -34,7 +39,6 @@ add_executable(Voxelotl MACOSX_BUNDLE
|
|||||||
# Core utility classes
|
# Core utility classes
|
||||||
Color.swift
|
Color.swift
|
||||||
Camera.swift
|
Camera.swift
|
||||||
Renderer.swift
|
|
||||||
FPSCalculator.swift
|
FPSCalculator.swift
|
||||||
GameDelegate.swift
|
GameDelegate.swift
|
||||||
Application.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\\Random" REGULAR_EXPRESSION "Random/")
|
||||||
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
|
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
|
||||||
source_group("Source Files\\Input" REGULAR_EXPRESSION "Input/")
|
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 projection: matrix_float4x4 = .identity
|
||||||
var chunk = Chunk(position: .zero)
|
var chunk = Chunk(position: .zero)
|
||||||
|
|
||||||
init() {
|
func create(_ renderer: Renderer) {
|
||||||
self.resetPlayer()
|
self.resetPlayer()
|
||||||
self.generateWorld()
|
self.generateWorld()
|
||||||
|
|
||||||
|
renderer.clearColor = Color<Double>.black.mix(.white, 0.1).linear
|
||||||
}
|
}
|
||||||
|
|
||||||
private func resetPlayer() {
|
private func resetPlayer() {
|
||||||
@ -103,6 +105,15 @@ class Game: GameDelegate {
|
|||||||
func draw(_ renderer: Renderer, _ time: GameTime) {
|
func draw(_ renderer: Renderer, _ time: GameTime) {
|
||||||
let totalTime = Float(time.total.asFloat)
|
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
|
var instances = chunk.compactMap { block, position in
|
||||||
if case let .solid(color) = block.type {
|
if case let .solid(color) = block.type {
|
||||||
Instance(
|
Instance(
|
||||||
@ -121,7 +132,7 @@ class Game: GameDelegate {
|
|||||||
.init(angle: totalTime * 0.7, axis: .init(0, 0, 1)),
|
.init(angle: totalTime * 0.7, axis: .init(0, 0, 1)),
|
||||||
color: .init(r: 0.5, g: 0.5, b: 1).linear))
|
color: .init(r: 0.5, g: 0.5, b: 1).linear))
|
||||||
if !instances.isEmpty {
|
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 {
|
public protocol GameDelegate {
|
||||||
|
func create(_ renderer: Renderer)
|
||||||
func fixedUpdate(_ time: GameTime)
|
func fixedUpdate(_ time: GameTime)
|
||||||
func update(_ time: GameTime)
|
func update(_ time: GameTime)
|
||||||
func draw(_ renderer: Renderer, _ time: GameTime)
|
func draw(_ renderer: Renderer, _ time: GameTime)
|
||||||
|
@ -203,7 +203,7 @@ struct Player {
|
|||||||
chunk: chunk,
|
chunk: chunk,
|
||||||
origin: self.eyePosition,
|
origin: self.eyePosition,
|
||||||
direction: .forward * simd_matrix3x3(self.eyeRotation),
|
direction: .forward * simd_matrix3x3(self.eyeRotation),
|
||||||
maxDistance: 3.666
|
maxDistance: 3.8
|
||||||
) {
|
) {
|
||||||
self.rayhitPos = hit.position
|
self.rayhitPos = hit.position
|
||||||
if destroy {
|
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
|
import ShaderTypes
|
||||||
|
|
||||||
fileprivate let cubeVertices: [ShaderVertex] = [
|
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(.back, 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(.back, 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(.back, 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(.back, 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(.right, 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(.right, 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(.right, 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(.right, 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(.forward, 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(.forward, 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(.forward, 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(.forward, 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(.left, 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(.left, 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(.left, 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(.left, 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(.down, 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(.down, 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(.down, 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(.down, 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(.up, 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(.up, 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(.up, 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(.up, 0), texCoord: .init(1, 1)),
|
||||||
]
|
]
|
||||||
|
|
||||||
fileprivate let cubeIndices: [UInt16] = [
|
fileprivate let cubeIndices: [UInt16] = [
|
||||||
@ -43,12 +43,12 @@ fileprivate let cubeIndices: [UInt16] = [
|
|||||||
fileprivate let numFramesInFlight: Int = 3
|
fileprivate let numFramesInFlight: Int = 3
|
||||||
fileprivate let colorFormat: MTLPixelFormat = .bgra8Unorm_srgb
|
fileprivate let colorFormat: MTLPixelFormat = .bgra8Unorm_srgb
|
||||||
fileprivate let depthFormat: MTLPixelFormat = .depth32Float
|
fileprivate let depthFormat: MTLPixelFormat = .depth32Float
|
||||||
fileprivate let clearColor: Color<Double> = .black.mix(.white, 0.1).linear
|
|
||||||
|
|
||||||
public class Renderer {
|
public class Renderer {
|
||||||
private var device: MTLDevice
|
private var device: MTLDevice
|
||||||
private var layer: CAMetalLayer
|
private var layer: CAMetalLayer
|
||||||
private var backBufferSize: Size<Int>
|
private var backBufferSize: Size<Int>
|
||||||
|
private var _clearColor: Color<Double>
|
||||||
private var _aspectRatio: Float
|
private var _aspectRatio: Float
|
||||||
private var queue: MTLCommandQueue
|
private var queue: MTLCommandQueue
|
||||||
private var lib: MTLLibrary
|
private var lib: MTLLibrary
|
||||||
@ -70,6 +70,10 @@ public class Renderer {
|
|||||||
|
|
||||||
var frame: Rect<Int> { .init(origin: .zero, size: self.backBufferSize) }
|
var frame: Rect<Int> { .init(origin: .zero, size: self.backBufferSize) }
|
||||||
var aspectRatio: Float { self._aspectRatio }
|
var aspectRatio: Float { self._aspectRatio }
|
||||||
|
var clearColor: Color<Double> {
|
||||||
|
get { self._clearColor }
|
||||||
|
set { self._clearColor = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
fileprivate static func createMetalDevice() -> MTLDevice? {
|
fileprivate static func createMetalDevice() -> MTLDevice? {
|
||||||
MTLCopyAllDevices().reduce(nil, { best, dev in
|
MTLCopyAllDevices().reduce(nil, { best, dev in
|
||||||
@ -100,10 +104,10 @@ public class Renderer {
|
|||||||
|
|
||||||
self.backBufferSize = size
|
self.backBufferSize = size
|
||||||
self._aspectRatio = Float(self.backBufferSize.w) / Float(self.backBufferSize.w)
|
self._aspectRatio = Float(self.backBufferSize.w) / Float(self.backBufferSize.w)
|
||||||
|
self._clearColor = .black
|
||||||
|
|
||||||
passDescription.colorAttachments[0].loadAction = .clear
|
passDescription.colorAttachments[0].loadAction = .clear
|
||||||
passDescription.colorAttachments[0].storeAction = .store
|
passDescription.colorAttachments[0].storeAction = .store
|
||||||
passDescription.colorAttachments[0].clearColor = MTLClearColor(clearColor)
|
|
||||||
passDescription.depthAttachment.loadAction = .clear
|
passDescription.depthAttachment.loadAction = .clear
|
||||||
passDescription.depthAttachment.storeAction = .dontCare
|
passDescription.depthAttachment.storeAction = .dontCare
|
||||||
passDescription.depthAttachment.clearDepth = 1.0
|
passDescription.depthAttachment.clearDepth = 1.0
|
||||||
@ -302,6 +306,7 @@ public class Renderer {
|
|||||||
throw RendererError.drawFailure("Failed to get next drawable render target")
|
throw RendererError.drawFailure("Failed to get next drawable render target")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
passDescription.colorAttachments[0].clearColor = MTLClearColor(self._clearColor)
|
||||||
passDescription.colorAttachments[0].texture = rt.texture
|
passDescription.colorAttachments[0].texture = rt.texture
|
||||||
passDescription.depthAttachment.texture = self.depthTextures[self.currentFrame]
|
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")
|
throw RendererError.drawFailure("Failed to make render encoder from command buffer")
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder.setCullMode(.back)
|
|
||||||
encoder.setFrontFacing(.counterClockwise) // OpenGL default
|
encoder.setFrontFacing(.counterClockwise) // OpenGL default
|
||||||
encoder.setViewport(Self.makeViewport(rect: self.frame))
|
encoder.setViewport(Self.makeViewport(rect: self.frame))
|
||||||
encoder.setRenderPipelineState(pso)
|
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")
|
assert(self._encoder != nil, "batch can't be called outside of a frame being rendered")
|
||||||
|
|
||||||
var vertUniforms = VertexShaderUniforms(projView: camera.viewProjection)
|
var vertUniforms = VertexShaderUniforms(projView: camera.viewProjection)
|
||||||
var fragUniforms = FragmentShaderUniforms(
|
var fragUniforms = FragmentShaderUniforms(
|
||||||
cameraPosition: camera.position,
|
cameraPosition: camera.position,
|
||||||
directionalLight: normalize(.init(0.75, -1, 0.5)),
|
directionalLight: normalize(environment.lightDirection),
|
||||||
ambientColor: SIMD4(Color(rgba8888: 0x1F1F1F00).linear),
|
ambientColor: SIMD4(Color<Float>(material.ambient)),
|
||||||
diffuseColor: SIMD4(Color(rgba8888: 0xEFEFEF00).linear),
|
diffuseColor: SIMD4(Color<Float>(material.diffuse)),
|
||||||
specularColor: SIMD4(Color(rgba8888: 0x7F7F7F00).linear),
|
specularColor: SIMD4(Color<Float>(material.specular)),
|
||||||
specularIntensity: 50)
|
specularIntensity: material.gloss)
|
||||||
|
|
||||||
let numInstances = instances.count
|
let numInstances = instances.count
|
||||||
let instancesBytes = numInstances * MemoryLayout<VertexShaderInstance>.stride
|
let instancesBytes = numInstances * MemoryLayout<VertexShaderInstance>.stride
|
||||||
@ -385,6 +389,8 @@ public class Renderer {
|
|||||||
}
|
}
|
||||||
instanceBuffer.didModifyRange(0..<instancesBytes)
|
instanceBuffer.didModifyRange(0..<instancesBytes)
|
||||||
|
|
||||||
|
self._encoder.setCullMode(.init(environment.cullFace))
|
||||||
|
|
||||||
self._encoder.setVertexBuffer(instanceBuffer,
|
self._encoder.setVertexBuffer(instanceBuffer,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
index: VertexShaderInputIdx.instance.rawValue)
|
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 {
|
enum RendererError: Error {
|
||||||
case initFailure(_ message: String)
|
case initFailure(_ message: String)
|
||||||
case loadFailure(_ message: String)
|
case loadFailure(_ message: String)
|
Loading…
Reference in New Issue
Block a user