From 4209a925c47309bbc49b245434ed2c058a08081e Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Sun, 1 Sep 2024 19:27:39 -0400 Subject: [PATCH 1/2] RIP to Float16, it's sad that Intel doesn't support you. --- Sources/Voxelotl/Chunk.swift | 2 +- Sources/Voxelotl/Game.swift | 4 +-- Sources/Voxelotl/Renderer/Material.swift | 6 ++--- Sources/Voxelotl/Renderer/Mesh.swift | 2 +- Sources/Voxelotl/Renderer/Renderer.swift | 32 ++++++++++++------------ Sources/Voxelotl/WorldGenerator.swift | 6 ++--- Sources/Voxelotl/shader.metal | 10 ++++---- Sources/Voxelotl/shadertypes.h | 13 +++------- 8 files changed, 35 insertions(+), 40 deletions(-) diff --git a/Sources/Voxelotl/Chunk.swift b/Sources/Voxelotl/Chunk.swift index d0a1bea..87e7793 100644 --- a/Sources/Voxelotl/Chunk.swift +++ b/Sources/Voxelotl/Chunk.swift @@ -123,7 +123,7 @@ public struct Chunk: Hashable { public enum BlockType: Hashable { case air - case solid(_ color: Color) + case solid(_ color: Color) } public struct Block: Hashable { diff --git a/Sources/Voxelotl/Game.swift b/Sources/Voxelotl/Game.swift index 049c038..fbad833 100644 --- a/Sources/Voxelotl/Game.swift +++ b/Sources/Voxelotl/Game.swift @@ -4,13 +4,13 @@ struct Instance { let position: SIMD3 let scale: SIMD3 let rotation: simd_quatf - let color: Color + let color: Color init( position: SIMD3 = .zero, scale: SIMD3 = .one, rotation: simd_quatf = .identity, - color: Color = .white + color: Color = .white ) { self.position = position self.scale = scale diff --git a/Sources/Voxelotl/Renderer/Material.swift b/Sources/Voxelotl/Renderer/Material.swift index 2f1c849..858dfba 100644 --- a/Sources/Voxelotl/Renderer/Material.swift +++ b/Sources/Voxelotl/Renderer/Material.swift @@ -1,7 +1,7 @@ public struct Material { - public var ambient: Color - public var diffuse: Color - public var specular: Color + public var ambient: Color + public var diffuse: Color + public var specular: Color public var gloss: Float } diff --git a/Sources/Voxelotl/Renderer/Mesh.swift b/Sources/Voxelotl/Renderer/Mesh.swift index 4e00b21..0964d28 100644 --- a/Sources/Voxelotl/Renderer/Mesh.swift +++ b/Sources/Voxelotl/Renderer/Mesh.swift @@ -18,6 +18,6 @@ public struct VertexPositionNormalTexcoord: Vertex { public struct VertexPositionNormalColorTexcoord: Vertex { var position: SIMD3 var normal: SIMD3 - var color: SIMD4 + var color: SIMD4 var texCoord: SIMD2 } diff --git a/Sources/Voxelotl/Renderer/Renderer.swift b/Sources/Voxelotl/Renderer/Renderer.swift index 2ff85c1..a00f40d 100644 --- a/Sources/Voxelotl/Renderer/Renderer.swift +++ b/Sources/Voxelotl/Renderer/Renderer.swift @@ -141,7 +141,7 @@ public class Renderer { if mesh.vertices.isEmpty || mesh.indices.isEmpty { return nil } let vertices = mesh.vertices.map { - ShaderVertex(position: $0.position, normal: $0.normal, color: $0.color.reinterpretUShort, texCoord: $0.texCoord) + ShaderVertex(position: $0.position, normal: $0.normal, color: $0.color, texCoord: $0.texCoord) } guard let vtxBuffer = self.device.makeBuffer( bytes: vertices, @@ -165,9 +165,9 @@ public class Renderer { func createMesh(_ mesh: Mesh) -> RendererMesh? { if mesh.vertices.isEmpty || mesh.indices.isEmpty { return nil } - let color = Color.white.reinterpretUShort + let color = Color.white let vertices = mesh.vertices.map { - ShaderVertex(position: $0.position, normal: $0.normal, color: color, texCoord: $0.texCoord) + ShaderVertex(position: $0.position, normal: $0.normal, color: color.values, texCoord: $0.texCoord) } guard let vtxBuffer = self.device.makeBuffer( bytes: vertices, @@ -341,21 +341,21 @@ public class Renderer { } } - func draw(model: matrix_float4x4, color: Color, mesh: RendererMesh, material: Material, environment: Environment, camera: Camera) { + 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") var vertUniforms = VertexShaderUniforms(projView: camera.viewProjection) var fragUniforms = FragmentShaderUniforms( cameraPosition: camera.position, directionalLight: normalize(environment.lightDirection), - ambientColor: material.ambient.reinterpretUShort, - diffuseColor: material.diffuse.reinterpretUShort, - specularColor: material.specular.reinterpretUShort, + ambientColor: material.ambient.values, + diffuseColor: material.diffuse.values, + specularColor: material.specular.values, specularIntensity: material.gloss) var instance = VertexShaderInstance( model: model, normalModel: model.inverse.transpose, - color: color.reinterpretUShort) + color: color.values) self._encoder.setCullMode(.init(environment.cullFace)) @@ -386,9 +386,9 @@ public class Renderer { var fragUniforms = FragmentShaderUniforms( cameraPosition: camera.position, directionalLight: normalize(environment.lightDirection), - ambientColor: material.ambient.reinterpretUShort, - diffuseColor: material.diffuse.reinterpretUShort, - specularColor: material.specular.reinterpretUShort, + ambientColor: material.ambient.values, + diffuseColor: material.diffuse.values, + specularColor: material.specular.values, specularIntensity: material.gloss) let numInstances = instances.count @@ -417,7 +417,7 @@ public class Renderer { .scale(instance.scale) data[i] = VertexShaderInstance( model: model, normalModel: model.inverse.transpose, - color: instance.color.reinterpretUShort) + color: instance.color.values) } } instanceBuffer.didModifyRange(0.. { +fileprivate extension Color where T == Float { + var reinterpretUInt: SIMD4 { .init(self.r.bitPattern, self.g.bitPattern, self.b.bitPattern, self.a.bitPattern) } } -fileprivate extension SIMD4 where Scalar == Float16 { - var reinterpretUShort: SIMD4 { +fileprivate extension SIMD4 where Scalar == Float { + var reinterpretUShort: SIMD4 { .init(self.x.bitPattern, self.y.bitPattern, self.z.bitPattern, self.w.bitPattern) } } diff --git a/Sources/Voxelotl/WorldGenerator.swift b/Sources/Voxelotl/WorldGenerator.swift index ea1c056..fe3b108 100644 --- a/Sources/Voxelotl/WorldGenerator.swift +++ b/Sources/Voxelotl/WorldGenerator.swift @@ -26,9 +26,9 @@ struct WorldGenerator { + self.noise.get(fpos * 0.30) * 0.23 return if value < threshold { .solid(.init( - hue: Float16(180 + self.noise2.get(fpos * 0.05) * 180), - saturation: Float16(0.5 + self.noise2.get(SIMD4(fpos * 0.05, 4)) * 0.5), - value: Float16(0.5 + self.noise2.get(SIMD4(fpos * 0.05, 9)) * 0.5).lerp(0.5, 1)).linear) + hue: Float(180 + self.noise2.get(fpos * 0.05) * 180), + saturation: Float(0.5 + self.noise2.get(SIMD4(fpos * 0.05, 4)) * 0.5), + value: Float(0.5 + self.noise2.get(SIMD4(fpos * 0.05, 9)) * 0.5).lerp(0.5, 1)).linear) } else { .air } diff --git a/Sources/Voxelotl/shader.metal b/Sources/Voxelotl/shader.metal index 0efb259..63bc5c3 100644 --- a/Sources/Voxelotl/shader.metal +++ b/Sources/Voxelotl/shader.metal @@ -7,7 +7,7 @@ struct FragmentInput { float3 world; float3 normal; float2 texCoord; - half4 color; + float4 color; }; vertex FragmentInput vertexMain( @@ -29,7 +29,7 @@ vertex FragmentInput vertexMain( return out; } -fragment half4 fragmentMain( +fragment float4 fragmentMain( FragmentInput in [[stage_in]], metal::texture2d texture [[texture(0)]], constant FragmentShaderUniforms& u [[buffer(FragmentShaderInputIdxUniforms)]] @@ -45,17 +45,17 @@ fragment half4 fragmentMain( // Compute diffuse component float lambert = metal::dot(normal, lightVec); float diffuseAmount = metal::max(0.0, lambert); - half4 diffuse = u.diffuseColor * diffuseAmount; + float4 diffuse = u.diffuseColor * diffuseAmount; // Compute specular component (blinn-phong) float specularAngle = metal::max(0.0, metal::dot(halfDir, normal)); float specularTerm = metal::pow(specularAngle, u.specularIntensity); // smoothstep hack to ensure highlight tapers gracefully at grazing angles float specularAmount = specularTerm * metal::smoothstep(0, 2, lambert * u.specularIntensity); - half4 specular = u.specularColor * specularAmount; + float4 specular = u.specularColor * specularAmount; // Sample texture & vertex color to get albedo - half4 albedo = texture.sample(sampler, in.texCoord); + float4 albedo = float4(texture.sample(sampler, in.texCoord)); albedo *= in.color; return albedo * (u.ambientColor + diffuse) + specular; diff --git a/Sources/Voxelotl/shadertypes.h b/Sources/Voxelotl/shadertypes.h index ab16d91..63330e6 100644 --- a/Sources/Voxelotl/shadertypes.h +++ b/Sources/Voxelotl/shadertypes.h @@ -10,12 +10,7 @@ #include -// HACK: allow passing SIMD4 to shader while `simd_half4` is beta -#ifdef __METAL_VERSION__ -typedef half4 color_half4; -#else -typedef simd_ushort4 color_half4; -#endif +typedef simd_float4 color_float4; typedef NS_ENUM(NSInteger, VertexShaderInputIdx) { VertexShaderInputIdxVertices = 0, @@ -26,14 +21,14 @@ typedef NS_ENUM(NSInteger, VertexShaderInputIdx) { typedef struct { vector_float3 position; vector_float3 normal; - color_half4 color; + color_float4 color; vector_float2 texCoord; } ShaderVertex; typedef struct { matrix_float4x4 model; matrix_float4x4 normalModel; - color_half4 color; + color_float4 color; } VertexShaderInstance; typedef struct { @@ -46,7 +41,7 @@ typedef NS_ENUM(NSInteger, FragmentShaderInputIdx) { typedef struct { vector_float3 cameraPosition, directionalLight; - color_half4 ambientColor, diffuseColor, specularColor; + color_float4 ambientColor, diffuseColor, specularColor; float specularIntensity; } FragmentShaderUniforms; From 42244456c93ab11c569fe8b62d3f59a025ccc983 Mon Sep 17 00:00:00 2001 From: a dinosaur Date: Mon, 2 Sep 2024 19:06:16 +1000 Subject: [PATCH 2/2] restore halfs in shader --- Sources/Voxelotl/Renderer/Renderer.swift | 29 ++++++++---------------- Sources/Voxelotl/shader.metal | 16 ++++++------- Sources/Voxelotl/shadertypes.h | 8 +++---- 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/Sources/Voxelotl/Renderer/Renderer.swift b/Sources/Voxelotl/Renderer/Renderer.swift index a00f40d..04869a7 100644 --- a/Sources/Voxelotl/Renderer/Renderer.swift +++ b/Sources/Voxelotl/Renderer/Renderer.swift @@ -167,7 +167,7 @@ public class Renderer { let color = Color.white let vertices = mesh.vertices.map { - ShaderVertex(position: $0.position, normal: $0.normal, color: color.values, texCoord: $0.texCoord) + ShaderVertex(position: $0.position, normal: $0.normal, color: SIMD4(color), texCoord: $0.texCoord) } guard let vtxBuffer = self.device.makeBuffer( bytes: vertices, @@ -348,14 +348,14 @@ public class Renderer { var fragUniforms = FragmentShaderUniforms( cameraPosition: camera.position, directionalLight: normalize(environment.lightDirection), - ambientColor: material.ambient.values, - diffuseColor: material.diffuse.values, - specularColor: material.specular.values, + ambientColor: SIMD4(material.ambient), + diffuseColor: SIMD4(material.diffuse), + specularColor: SIMD4(material.specular), specularIntensity: material.gloss) var instance = VertexShaderInstance( model: model, normalModel: model.inverse.transpose, - color: color.values) + color: SIMD4(color)) self._encoder.setCullMode(.init(environment.cullFace)) @@ -386,9 +386,9 @@ public class Renderer { var fragUniforms = FragmentShaderUniforms( cameraPosition: camera.position, directionalLight: normalize(environment.lightDirection), - ambientColor: material.ambient.values, - diffuseColor: material.diffuse.values, - specularColor: material.specular.values, + ambientColor: SIMD4(material.ambient), + diffuseColor: SIMD4(material.diffuse), + specularColor: SIMD4(material.specular), specularIntensity: material.gloss) let numInstances = instances.count @@ -417,7 +417,7 @@ public class Renderer { .scale(instance.scale) data[i] = VertexShaderInstance( model: model, normalModel: model.inverse.transpose, - color: instance.color.values) + color: SIMD4(instance.color)) } } instanceBuffer.didModifyRange(0.. { - .init(self.r.bitPattern, self.g.bitPattern, self.b.bitPattern, self.a.bitPattern) - } -} -fileprivate extension SIMD4 where Scalar == Float { - var reinterpretUShort: SIMD4 { - .init(self.x.bitPattern, self.y.bitPattern, self.z.bitPattern, self.w.bitPattern) - } -} - enum RendererError: Error { case initFailure(_ message: String) case loadFailure(_ message: String) diff --git a/Sources/Voxelotl/shader.metal b/Sources/Voxelotl/shader.metal index 63bc5c3..4614d17 100644 --- a/Sources/Voxelotl/shader.metal +++ b/Sources/Voxelotl/shader.metal @@ -7,7 +7,7 @@ struct FragmentInput { float3 world; float3 normal; float2 texCoord; - float4 color; + half4 color; }; vertex FragmentInput vertexMain( @@ -23,13 +23,13 @@ vertex FragmentInput vertexMain( FragmentInput out; out.position = u.projView * world; out.world = world.xyz; - out.color = vtx[vertexID].color * i[instanceID].color; + out.color = half4(vtx[vertexID].color) * half4(i[instanceID].color); out.normal = (i[instanceID].normalModel * float4(vtx[vertexID].normal, 0)).xyz; out.texCoord = vtx[vertexID].texCoord; return out; } -fragment float4 fragmentMain( +fragment half4 fragmentMain( FragmentInput in [[stage_in]], metal::texture2d texture [[texture(0)]], constant FragmentShaderUniforms& u [[buffer(FragmentShaderInputIdxUniforms)]] @@ -45,18 +45,18 @@ fragment float4 fragmentMain( // Compute diffuse component float lambert = metal::dot(normal, lightVec); float diffuseAmount = metal::max(0.0, lambert); - float4 diffuse = u.diffuseColor * diffuseAmount; + half4 diffuse = half4(u.diffuseColor) * diffuseAmount; // Compute specular component (blinn-phong) float specularAngle = metal::max(0.0, metal::dot(halfDir, normal)); float specularTerm = metal::pow(specularAngle, u.specularIntensity); // smoothstep hack to ensure highlight tapers gracefully at grazing angles float specularAmount = specularTerm * metal::smoothstep(0, 2, lambert * u.specularIntensity); - float4 specular = u.specularColor * specularAmount; + half4 specular = half4(u.specularColor) * specularAmount; // Sample texture & vertex color to get albedo - float4 albedo = float4(texture.sample(sampler, in.texCoord)); - albedo *= in.color; + half4 albedo = texture.sample(sampler, in.texCoord); + albedo *= half4(in.color); - return albedo * (u.ambientColor + diffuse) + specular; + return albedo * (half4(u.ambientColor) + diffuse) + specular; } diff --git a/Sources/Voxelotl/shadertypes.h b/Sources/Voxelotl/shadertypes.h index 63330e6..0a9ef3d 100644 --- a/Sources/Voxelotl/shadertypes.h +++ b/Sources/Voxelotl/shadertypes.h @@ -10,8 +10,6 @@ #include -typedef simd_float4 color_float4; - typedef NS_ENUM(NSInteger, VertexShaderInputIdx) { VertexShaderInputIdxVertices = 0, VertexShaderInputIdxInstance = 1, @@ -21,14 +19,14 @@ typedef NS_ENUM(NSInteger, VertexShaderInputIdx) { typedef struct { vector_float3 position; vector_float3 normal; - color_float4 color; + vector_float4 color; vector_float2 texCoord; } ShaderVertex; typedef struct { matrix_float4x4 model; matrix_float4x4 normalModel; - color_float4 color; + vector_float4 color; } VertexShaderInstance; typedef struct { @@ -41,7 +39,7 @@ typedef NS_ENUM(NSInteger, FragmentShaderInputIdx) { typedef struct { vector_float3 cameraPosition, directionalLight; - color_float4 ambientColor, diffuseColor, specularColor; + vector_float4 ambientColor, diffuseColor, specularColor; float specularIntensity; } FragmentShaderUniforms;