Render normals at each vertex

This commit is contained in:
Eryn Wells 2018-11-19 13:17:06 -07:00
parent bd696eac1c
commit c3cc0c7fe4
4 changed files with 70 additions and 29 deletions

View file

@ -32,6 +32,7 @@ class Renderer: NSObject, MTKViewDelegate {
let commandQueue: MTLCommandQueue
var dynamicUniformBuffer: MTLBuffer
var pipelineState: MTLRenderPipelineState
var normalPipelineState: MTLRenderPipelineState
var depthState: MTLDepthStencilState
var colorMap: MTLTexture
@ -82,6 +83,7 @@ class Renderer: NSObject, MTKViewDelegate {
library: library,
metalKitView: metalKitView,
mtlVertexDescriptor: terrain.vertexDescriptor)
normalPipelineState = try Renderer.buildNormalRenderPipeline(withDevice: device, library: library, view: metalKitView)
} catch {
print("Unable to compile render pipeline state. Error info: \(error)")
return nil
@ -112,7 +114,7 @@ class Renderer: NSObject, MTKViewDelegate {
let fragmentFunction = library.makeFunction(name: "fragmentShader")
let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.label = "RenderPipeline"
pipelineDescriptor.label = "Geometry Render Pipeline"
pipelineDescriptor.sampleCount = metalKitView.sampleCount
pipelineDescriptor.vertexFunction = vertexFunction
pipelineDescriptor.fragmentFunction = fragmentFunction
@ -125,6 +127,23 @@ class Renderer: NSObject, MTKViewDelegate {
return try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
}
class func buildNormalRenderPipeline(withDevice device: MTLDevice, library: MTLLibrary, view: MTKView) throws -> MTLRenderPipelineState {
let vertexFunction = library.makeFunction(name: "normalVertexShader")
let fragmentFunction = library.makeFunction(name: "normalFragmentShader")
let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.label = "Normal Render Pipeline"
pipelineDescriptor.sampleCount = view.sampleCount
pipelineDescriptor.vertexFunction = vertexFunction
pipelineDescriptor.fragmentFunction = fragmentFunction
pipelineDescriptor.colorAttachments[0].pixelFormat = view.colorPixelFormat
pipelineDescriptor.depthAttachmentPixelFormat = view.depthStencilPixelFormat
pipelineDescriptor.stencilAttachmentPixelFormat = view.depthStencilPixelFormat
return try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
}
class func buildUpdateGeometryNormalsPipeline(withDevice device: MTLDevice, library: MTLLibrary) throws -> MTLComputePipelineState {
guard let computeFunction = library.makeFunction(name: "updateGeometryNormals") else {
throw RendererError.badComputeFunction
@ -242,7 +261,6 @@ class Renderer: NSObject, MTKViewDelegate {
/// Final pass rendering code here
if let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
renderEncoder.label = "Primary Render Encoder"
renderEncoder.pushDebugGroup("Draw Plane")
renderEncoder.setCullMode(.none)
@ -281,12 +299,35 @@ class Renderer: NSObject, MTKViewDelegate {
}
renderEncoder.popDebugGroup()
renderEncoder.endEncoding()
if let drawable = view.currentDrawable {
commandBuffer.present(drawable)
}
}
let normalsRenderPassDescriptor = renderPassDescriptor.copy() as! MTLRenderPassDescriptor
normalsRenderPassDescriptor.colorAttachments[0].loadAction = .load
normalsRenderPassDescriptor.colorAttachments[0].storeAction = .store
if let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: normalsRenderPassDescriptor) {
renderEncoder.label = "Normals Render Encoder"
renderEncoder.pushDebugGroup("Draw Normals")
renderEncoder.setRenderPipelineState(normalPipelineState)
renderEncoder.setDepthStencilState(depthState)
let vertexBuffer = terrain.mesh.vertexBuffers[BufferIndex.meshPositions.rawValue]
renderEncoder.setVertexBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: BufferIndex.meshPositions.rawValue)
let normalBuffer = terrain.mesh.vertexBuffers[BufferIndex.normals.rawValue]
renderEncoder.setVertexBuffer(normalBuffer.buffer, offset: normalBuffer.offset, index: BufferIndex.normals.rawValue)
renderEncoder.setVertexBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
renderEncoder.drawPrimitives(type: .line, vertexStart: 0, vertexCount: 2, instanceCount: terrain.mesh.vertexCount)
renderEncoder.popDebugGroup()
renderEncoder.endEncoding()
}
if let drawable = view.currentDrawable {
commandBuffer.present(drawable)
}
}

View file

@ -33,7 +33,7 @@ typedef NS_ENUM(NSInteger, VertexAttribute)
{
VertexAttributePosition = 0,
VertexAttributeNormal = 1,
VertexAttributeTexcoord = 2,
VertexAttributeTexCoord = 2,
};
typedef NS_ENUM(NSInteger, TextureIndex)
@ -42,7 +42,7 @@ typedef NS_ENUM(NSInteger, TextureIndex)
};
typedef NS_ENUM(NSInteger, GeneratorBufferIndex) {
GeneratorBufferIndexVertexes = 0,
GeneratorBufferIndexMeshPositions = 0,
GeneratorBufferIndexTexCoords = 1,
GeneratorBufferIndexIndexes = 2,
GeneratorBufferIndexNormals = 3,

View file

@ -20,7 +20,7 @@ typedef struct
{
float3 position [[attribute(VertexAttributePosition)]];
float3 normal [[attribute(VertexAttributeNormal)]];
float2 texCoord [[attribute(VertexAttributeTexcoord)]];
float2 texCoord [[attribute(VertexAttributeTexCoord)]];
} Vertex;
typedef struct
@ -65,17 +65,19 @@ fragment float4 fragmentShader(ColorInOut in [[stage_in]],
#pragma mark - Normal Shaders
vertex float4 normalVertexShader(constant float3 *positions [[buffer(BufferIndexMeshPositions)]],
constant float3 *normals [[buffer(BufferIndexNormals)]],
vertex float4 normalVertexShader(constant packed_float3 *positions [[buffer(BufferIndexMeshPositions)]],
constant packed_float3 *normals [[buffer(BufferIndexNormals)]],
constant Uniforms &uniforms [[buffer(BufferIndexUniforms)]],
uint instID [[instance_id]],
uint vertID [[vertex_id]])
{
float3 out = positions[instID];
float3 v = positions[instID];
if ( vertID == 1 )
{
out += normals[instID];
v += normals[instID];
}
return float4(out, 1.0);
float4 out = uniforms.projectionMatrix * uniforms.modelViewMatrix * float4(v, 1.0);
return out;
}
fragment half4 normalFragmentShader()

View file

@ -23,9 +23,9 @@ class Terrain: NSObject {
desc.attributes[VertexAttribute.normal.rawValue].offset = 0
desc.attributes[VertexAttribute.normal.rawValue].bufferIndex = BufferIndex.normals.rawValue
desc.attributes[VertexAttribute.texcoord.rawValue].format = .float2
desc.attributes[VertexAttribute.texcoord.rawValue].offset = 0
desc.attributes[VertexAttribute.texcoord.rawValue].bufferIndex = BufferIndex.meshGenerics.rawValue
desc.attributes[VertexAttribute.texCoord.rawValue].format = .float2
desc.attributes[VertexAttribute.texCoord.rawValue].offset = 0
desc.attributes[VertexAttribute.texCoord.rawValue].bufferIndex = BufferIndex.meshGenerics.rawValue
desc.layouts[BufferIndex.meshPositions.rawValue].stride = 12
desc.layouts[BufferIndex.meshPositions.rawValue].stepRate = 1
@ -63,7 +63,7 @@ class Terrain: NSObject {
}
attributes[VertexAttribute.position.rawValue].name = MDLVertexAttributePosition
attributes[VertexAttribute.normal.rawValue].name = MDLVertexAttributeNormal
attributes[VertexAttribute.texcoord.rawValue].name = MDLVertexAttributeTextureCoordinate
attributes[VertexAttribute.texCoord.rawValue].name = MDLVertexAttributeTextureCoordinate
plane.vertexDescriptor = mdlVertexDescriptor
@ -82,8 +82,7 @@ class Terrain: NSObject {
private let updateHeightsPipeline: MTLComputePipelineState
private let updateSurfaceNormalsPipeline: MTLComputePipelineState
private let updateVertexNormalsPipeline: MTLComputePipelineState
let dimensions: float2
let segments: uint2
let vertexDescriptor: MTLVertexDescriptor
@ -113,7 +112,6 @@ class Terrain: NSObject {
do {
updateHeightsPipeline = try Terrain.computePipeline(withFunctionNamed: "updateGeometryHeights", device: device, library: library)
updateSurfaceNormalsPipeline = try Terrain.computePipeline(withFunctionNamed: "updateGeometryNormals", device: device, library: library)
// updateVertexNormalsPipeline = try Terrain.computePipeline(withFunctionNamed: "updateGeometryVertexNormals", device: device, library: library)
} catch {
print("Unable to create compute pipelines for terrain geometry updates. Error: \(error)")
return nil
@ -148,10 +146,10 @@ class Terrain: NSObject {
computeEncoder.setComputePipelineState(updateHeightsPipeline)
computeEncoder.setTexture(generator.outTexture, index: GeneratorTextureIndex.in.rawValue)
let vertexBuffer = mesh.vertexBuffers[BufferIndex.meshPositions.rawValue]
computeEncoder.setBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: BufferIndex.meshPositions.rawValue)
computeEncoder.setBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: GeneratorBufferIndex.meshPositions.rawValue)
let texCoordBuffer = mesh.vertexBuffers[BufferIndex.meshGenerics.rawValue]
computeEncoder.setBuffer(texCoordBuffer.buffer, offset: texCoordBuffer.offset, index: BufferIndex.texCoords.rawValue)
computeEncoder.setBuffer(uniforms, offset: uniformsOffset, index: BufferIndex.uniforms.rawValue)
computeEncoder.setBuffer(texCoordBuffer.buffer, offset: texCoordBuffer.offset, index: GeneratorBufferIndex.texCoords.rawValue)
computeEncoder.setBuffer(uniforms, offset: uniformsOffset, index: GeneratorBufferIndex.uniforms.rawValue)
computeEncoder.dispatchThreads(MTLSize(width: Int(segments.x + 1), height: Int(segments.y + 1), depth: 1), threadsPerThreadgroup: MTLSize(width: 8, height: 8, depth: 1))
computeEncoder.popDebugGroup()
computeEncoder.endEncoding()
@ -163,11 +161,11 @@ class Terrain: NSObject {
computeEncoder.pushDebugGroup("Update Geometry: Surface Normals")
computeEncoder.setComputePipelineState(updateSurfaceNormalsPipeline)
let indexBuffer = mesh.submeshes[0].indexBuffer
computeEncoder.setBuffer(indexBuffer.buffer, offset: indexBuffer.offset, index: BufferIndex.meshPositions.rawValue)
computeEncoder.setBuffer(indexBuffer.buffer, offset: indexBuffer.offset, index: GeneratorBufferIndex.meshPositions.rawValue)
let vertexBuffer = mesh.vertexBuffers[BufferIndex.meshPositions.rawValue]
computeEncoder.setBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: BufferIndex.meshPositions.rawValue)
let normalBuffer = mesh.vertexBuffers[BufferIndex.faceNormals.rawValue]
computeEncoder.setBuffer(normalBuffer.buffer, offset: normalBuffer.offset, index: BufferIndex.faceNormals.rawValue)
computeEncoder.setBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: GeneratorBufferIndex.indexes.rawValue)
// let normalBuffer = mesh.vertexBuffers[BufferIndex.faceNormals.rawValue]
// computeEncoder.setBuffer(normalBuffer.buffer, offset: normalBuffer.offset, index: BufferIndex.faceNormals.rawValue)
computeEncoder.dispatchThreads(MTLSize(width: mesh.vertexCount, height: 1, depth: 1), threadsPerThreadgroup: MTLSize(width: 64, height: 1, depth: 1))
computeEncoder.popDebugGroup()
computeEncoder.endEncoding()