Render normals at each vertex
This commit is contained in:
parent
bd696eac1c
commit
c3cc0c7fe4
4 changed files with 70 additions and 29 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue