diff --git a/Sources/Voxelotl/Renderer.swift b/Sources/Voxelotl/Renderer.swift index 48aaa35..b7845a9 100644 --- a/Sources/Voxelotl/Renderer.swift +++ b/Sources/Voxelotl/Renderer.swift @@ -286,24 +286,26 @@ class Renderer { let projection = matrix_float4x4.perspective( verticalFov: Float(60.0).radians, aspect: aspectRatio, - near: 0.003, - far: 100) + near: 0.03, + far: 25) #else let projection = matrix_float4x4.orthographic( left: -aspectRatio, right: aspectRatio, bottom: -1, top: 1, - near: 0, far: -4) + near: -0.03, far: -25) #endif let view = camera.view - let model: matrix_float4x4 = - .translate(.init(0, -1, 0)) * .scale(.init(10, 0.1, 10)) - //.translate(.init(0, sin(time * 0.5) * 0.75, -2)) * - //.scale(0.5) * - //.rotate(y: time) + + let instances: [ShaderInstance] = [ + ShaderInstance(model: .translate(.init(0, sin(time * 0.5) * 0.5, -2)) * .rotate(y: time) * .scale(0.25), color: .init(0.5, 0.5, 1, 1)), + ShaderInstance(model: .translate(.init(0, -1, 0)) * .scale(.init(10, 0.1, 10)), color: .init(1, 1, 1, 1)), + ShaderInstance(model: .translate(.init(-2.5, 0, -3)), color: .init(1, 0.5, 0.75, 1)), + ShaderInstance(model: .translate(.init(-2.5, -0.5, -5)), color: .init(0.75, 1, 1, 1)) + ] time += 0.025 - var uniforms = ShaderUniforms(model: model, projView: projection * view) + var uniforms = ShaderUniforms(projView: projection * view) guard let rt = layer.nextDrawable() else { throw RendererError.drawFailure("Failed to get next drawable render target") @@ -318,7 +320,7 @@ class Renderer { throw RendererError.drawFailure("Failed to make render encoder from command buffer") } - encoder.setCullMode(.none) + encoder.setCullMode(.back) encoder.setFrontFacing(.counterClockwise) // OpenGL default encoder.setViewport(viewport) encoder.setRenderPipelineState(pso) @@ -328,16 +330,22 @@ class Renderer { encoder.setVertexBuffer(vtxBuffer, offset: 0, index: ShaderInputIdx.vertices.rawValue) + // Ideal as long as our uniforms total 4 KB or less + encoder.setVertexBytes(instances, + length: instances.count * MemoryLayout.stride, + index: ShaderInputIdx.instance.rawValue) encoder.setVertexBytes(&uniforms, length: MemoryLayout.stride, index: ShaderInputIdx.uniforms.rawValue) + encoder.drawIndexedPrimitives( type: .triangle, indexCount: cubeIndices.count, indexType: .uint16, indexBuffer: idxBuffer, - indexBufferOffset: 0) + indexBufferOffset: 0, + instanceCount: instances.count) encoder.endEncoding() commandBuf.present(rt) diff --git a/Sources/Voxelotl/shader.metal b/Sources/Voxelotl/shader.metal index 88b6bf3..14ff1a8 100644 --- a/Sources/Voxelotl/shader.metal +++ b/Sources/Voxelotl/shader.metal @@ -1,25 +1,28 @@ #include "shadertypes.h" - #include -using namespace metal; struct FragmentInput { float4 position [[position]]; float4 normal; float2 texCoord; + half4 color; }; vertex FragmentInput vertexMain( uint vertexID [[vertex_id]], + uint instanceID [[instance_id]], device const ShaderVertex* vtx [[buffer(ShaderInputIdxVertices)]], + device const ShaderInstance* i [[buffer(ShaderInputIdxInstance)]], constant ShaderUniforms& u [[buffer(ShaderInputIdxUniforms)]] ) { auto position = vtx[vertexID].position; - position = u.projView * u.model * position; + auto world = i[instanceID].model * position; + auto ndc = u.projView * world; FragmentInput out; - out.position = position; + out.position = ndc; + out.color = half4(i[instanceID].color); out.normal = vtx[vertexID].normal; out.texCoord = vtx[vertexID].texCoord; return out; @@ -27,10 +30,9 @@ vertex FragmentInput vertexMain( fragment half4 fragmentMain( FragmentInput in [[stage_in]], - texture2d tex [[texture(0)]] + metal::texture2d texture [[texture(0)]] ) { - constexpr sampler s(address::repeat, filter::nearest); - half4 albedo = tex.sample(s, in.texCoord); - - return half4(albedo.rgb, 1.0); + constexpr metal::sampler sampler(metal::address::repeat, metal::filter::nearest); + half4 albedo = texture.sample(sampler, in.texCoord); + return albedo * in.color; } diff --git a/Sources/Voxelotl/shadertypes.h b/Sources/Voxelotl/shadertypes.h index 6f3e3a6..054b7fc 100644 --- a/Sources/Voxelotl/shadertypes.h +++ b/Sources/Voxelotl/shadertypes.h @@ -12,7 +12,8 @@ typedef NS_ENUM(NSInteger, ShaderInputIdx) { ShaderInputIdxVertices = 0, - ShaderInputIdxUniforms = 1 + ShaderInputIdxInstance = 1, + ShaderInputIdxUniforms = 2 }; typedef struct { @@ -23,6 +24,10 @@ typedef struct { typedef struct { matrix_float4x4 model; + vector_float4 color; +} ShaderInstance; + +typedef struct { matrix_float4x4 projView; } ShaderUniforms;