From e62dd1b0f2d2d21b85b19f9086c63802e4d2e343 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sun, 11 Nov 2018 21:04:03 -0500 Subject: [PATCH] Work in the normal calculations --- Terrain2/Renderer.swift | 37 ++++++++++++++++++++---- Terrain2/ShaderTypes.h | 3 +- Terrain2/Shaders/TerrainAlgorithms.metal | 15 ++++++---- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/Terrain2/Renderer.swift b/Terrain2/Renderer.swift index c98db1a..c9a35fe 100644 --- a/Terrain2/Renderer.swift +++ b/Terrain2/Renderer.swift @@ -32,7 +32,8 @@ class Renderer: NSObject, MTKViewDelegate { var depthState: MTLDepthStencilState var colorMap: MTLTexture - var updateGeometryHeightsPipeline: MTLComputePipelineState + let updateGeometryHeightsPipeline: MTLComputePipelineState + let updateGeometryNormalsPipeline: MTLComputePipelineState let inFlightSemaphore = DispatchSemaphore(value: maxBuffersInFlight) let regenerationSemaphore = DispatchSemaphore(value: 1) @@ -101,7 +102,8 @@ class Renderer: NSObject, MTKViewDelegate { } do { - updateGeometryHeightsPipeline = try Renderer.buildUpdateGeometryPipeline(withDevice: device, library: library) + updateGeometryHeightsPipeline = try Renderer.buildUpdateGeometryHeightsPipeline(withDevice: device, library: library) + updateGeometryNormalsPipeline = try Renderer.buildUpdateGeometryNormalsPipeline(withDevice: device, library: library) } catch { print("Unable to create update geometry pipeline. Error: \(error)") return nil @@ -134,13 +136,20 @@ class Renderer: NSObject, MTKViewDelegate { return try device.makeRenderPipelineState(descriptor: pipelineDescriptor) } - class func buildUpdateGeometryPipeline(withDevice device: MTLDevice, library: MTLLibrary) throws -> MTLComputePipelineState { + class func buildUpdateGeometryHeightsPipeline(withDevice device: MTLDevice, library: MTLLibrary) throws -> MTLComputePipelineState { guard let computeFunction = library.makeFunction(name: "updateGeometryHeights") else { throw RendererError.badComputeFunction } return try device.makeComputePipelineState(function: computeFunction) } + class func buildUpdateGeometryNormalsPipeline(withDevice device: MTLDevice, library: MTLLibrary) throws -> MTLComputePipelineState { + guard let computeFunction = library.makeFunction(name: "updateGeometryNormals") else { + throw RendererError.badComputeFunction + } + return try device.makeComputePipelineState(function: computeFunction) + } + class func loadTexture(device: MTLDevice, textureName: String) throws -> MTLTexture { /// Load texture data with optimal parameters for sampling @@ -238,8 +247,9 @@ class Renderer: NSObject, MTKViewDelegate { didScheduleAlgorithmIteration = true } - if didScheduleAlgorithmIteration || needsGeometryUpdate, let computeEncoder = commandBuffer.makeComputeCommandEncoder() { - print("Scheduling update geometry iteration") + if didScheduleAlgorithmIteration || needsGeometryUpdate { + if let computeEncoder = commandBuffer.makeComputeCommandEncoder() { + print("Scheduling update geometry heights") computeEncoder.label = "Geometry Heights Encoder" computeEncoder.pushDebugGroup("Update Geometry: Heights") computeEncoder.setComputePipelineState(updateGeometryHeightsPipeline) @@ -252,6 +262,23 @@ class Renderer: NSObject, MTKViewDelegate { computeEncoder.dispatchThreads(MTLSize(width: Int(terrain.segments.x + 1), height: Int(terrain.segments.y + 1), depth: 1), threadsPerThreadgroup: MTLSize(width: 8, height: 8, depth: 1)) computeEncoder.popDebugGroup() computeEncoder.endEncoding() + } + + if let computeEncoder = commandBuffer.makeComputeCommandEncoder() { + print("Scheduling update geometry normals") + computeEncoder.label = "Geometry Normals Encoder" + computeEncoder.pushDebugGroup("Update Geometry: Normals") + computeEncoder.setComputePipelineState(updateGeometryNormalsPipeline) + let indexBuffer = terrain.mesh.submeshes[0].indexBuffer + computeEncoder.setBuffer(indexBuffer.buffer, offset: indexBuffer.offset, index: GeneratorBufferIndex.indexes.rawValue) + let vertexBuffer = terrain.mesh.vertexBuffers[BufferIndex.meshPositions.rawValue] + computeEncoder.setBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: GeneratorBufferIndex.vertexes.rawValue) + let normalBuffer = terrain.mesh.vertexBuffers[BufferIndex.normals.rawValue] + computeEncoder.setBuffer(normalBuffer.buffer, offset: normalBuffer.offset, index: GeneratorBufferIndex.normals.rawValue) + computeEncoder.dispatchThreads(MTLSize(width: terrain.mesh.vertexCount, height: 1, depth: 1), threadsPerThreadgroup: MTLSize(width: 64, height: 1, depth: 1)) + computeEncoder.popDebugGroup() + computeEncoder.endEncoding() + } } /// Delay getting the currentRenderPassDescriptor until we absolutely need it to avoid diff --git a/Terrain2/ShaderTypes.h b/Terrain2/ShaderTypes.h index ee15675..fee7472 100644 --- a/Terrain2/ShaderTypes.h +++ b/Terrain2/ShaderTypes.h @@ -45,7 +45,8 @@ typedef NS_ENUM(NSInteger, GeneratorBufferIndex) { GeneratorBufferIndexVertexes = 0, GeneratorBufferIndexTexCoords = 1, GeneratorBufferIndexIndexes = 2, - GeneratorBufferIndexUniforms = 3, + GeneratorBufferIndexNormals = 3, + GeneratorBufferIndexUniforms = 4, }; typedef NS_ENUM(NSInteger, GeneratorTextureIndex) { diff --git a/Terrain2/Shaders/TerrainAlgorithms.metal b/Terrain2/Shaders/TerrainAlgorithms.metal index 3a147ce..813a4f6 100644 --- a/Terrain2/Shaders/TerrainAlgorithms.metal +++ b/Terrain2/Shaders/TerrainAlgorithms.metal @@ -61,13 +61,16 @@ kernel void updateGeometryHeights(texture2d texture [[texture(GeneratorTe vertexes[vIdx].y = height.r; } -kernel void updateGeometryNormals(texture2d texture [[texture(GeneratorTextureIndexIn)]], - constant float3 *vertexes [[buffer(GeneratorBufferIndexVertexes)]], - constant float2 *texCoords [[buffer(GeneratorBufferIndexTexCoords)]], - constant uint *indexes [[buffer(GeneratorBufferIndexIndexes)]], - constant Uniforms &uniforms [[buffer(GeneratorBufferIndexUniforms)]], - uint2 tid [[thread_position_in_grid]]) +kernel void updateGeometryNormals(constant float3 *vertexes [[buffer(GeneratorBufferIndexVertexes)]], + constant packed_uint3 *indexes [[buffer(GeneratorBufferIndexIndexes)]], + device packed_float3 *normals [[buffer(GeneratorBufferIndexNormals)]], + uint tid [[thread_position_in_grid]]) { + const uint3 triIdx = indexes[tid]; + float3 side1(vertexes[triIdx.y] - vertexes[triIdx.x]); + float3 side2(vertexes[triIdx.y] - vertexes[triIdx.z]); + float3 normal(normalize(cross(side1, side2))); + normals[tid] = normal; } #pragma mark - ZeroGenerator