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
|
let commandQueue: MTLCommandQueue
|
||||||
var dynamicUniformBuffer: MTLBuffer
|
var dynamicUniformBuffer: MTLBuffer
|
||||||
var pipelineState: MTLRenderPipelineState
|
var pipelineState: MTLRenderPipelineState
|
||||||
|
var normalPipelineState: MTLRenderPipelineState
|
||||||
var depthState: MTLDepthStencilState
|
var depthState: MTLDepthStencilState
|
||||||
var colorMap: MTLTexture
|
var colorMap: MTLTexture
|
||||||
|
|
||||||
|
@ -82,6 +83,7 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
library: library,
|
library: library,
|
||||||
metalKitView: metalKitView,
|
metalKitView: metalKitView,
|
||||||
mtlVertexDescriptor: terrain.vertexDescriptor)
|
mtlVertexDescriptor: terrain.vertexDescriptor)
|
||||||
|
normalPipelineState = try Renderer.buildNormalRenderPipeline(withDevice: device, library: library, view: metalKitView)
|
||||||
} catch {
|
} catch {
|
||||||
print("Unable to compile render pipeline state. Error info: \(error)")
|
print("Unable to compile render pipeline state. Error info: \(error)")
|
||||||
return nil
|
return nil
|
||||||
|
@ -112,7 +114,7 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
let fragmentFunction = library.makeFunction(name: "fragmentShader")
|
let fragmentFunction = library.makeFunction(name: "fragmentShader")
|
||||||
|
|
||||||
let pipelineDescriptor = MTLRenderPipelineDescriptor()
|
let pipelineDescriptor = MTLRenderPipelineDescriptor()
|
||||||
pipelineDescriptor.label = "RenderPipeline"
|
pipelineDescriptor.label = "Geometry Render Pipeline"
|
||||||
pipelineDescriptor.sampleCount = metalKitView.sampleCount
|
pipelineDescriptor.sampleCount = metalKitView.sampleCount
|
||||||
pipelineDescriptor.vertexFunction = vertexFunction
|
pipelineDescriptor.vertexFunction = vertexFunction
|
||||||
pipelineDescriptor.fragmentFunction = fragmentFunction
|
pipelineDescriptor.fragmentFunction = fragmentFunction
|
||||||
|
@ -125,6 +127,23 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
return try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
|
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 {
|
class func buildUpdateGeometryNormalsPipeline(withDevice device: MTLDevice, library: MTLLibrary) throws -> MTLComputePipelineState {
|
||||||
guard let computeFunction = library.makeFunction(name: "updateGeometryNormals") else {
|
guard let computeFunction = library.makeFunction(name: "updateGeometryNormals") else {
|
||||||
throw RendererError.badComputeFunction
|
throw RendererError.badComputeFunction
|
||||||
|
@ -242,7 +261,6 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
/// Final pass rendering code here
|
/// Final pass rendering code here
|
||||||
if let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
|
if let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
|
||||||
renderEncoder.label = "Primary Render Encoder"
|
renderEncoder.label = "Primary Render Encoder"
|
||||||
|
|
||||||
renderEncoder.pushDebugGroup("Draw Plane")
|
renderEncoder.pushDebugGroup("Draw Plane")
|
||||||
|
|
||||||
renderEncoder.setCullMode(.none)
|
renderEncoder.setCullMode(.none)
|
||||||
|
@ -281,12 +299,35 @@ class Renderer: NSObject, MTKViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEncoder.popDebugGroup()
|
renderEncoder.popDebugGroup()
|
||||||
|
|
||||||
renderEncoder.endEncoding()
|
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,
|
VertexAttributePosition = 0,
|
||||||
VertexAttributeNormal = 1,
|
VertexAttributeNormal = 1,
|
||||||
VertexAttributeTexcoord = 2,
|
VertexAttributeTexCoord = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, TextureIndex)
|
typedef NS_ENUM(NSInteger, TextureIndex)
|
||||||
|
@ -42,7 +42,7 @@ typedef NS_ENUM(NSInteger, TextureIndex)
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, GeneratorBufferIndex) {
|
typedef NS_ENUM(NSInteger, GeneratorBufferIndex) {
|
||||||
GeneratorBufferIndexVertexes = 0,
|
GeneratorBufferIndexMeshPositions = 0,
|
||||||
GeneratorBufferIndexTexCoords = 1,
|
GeneratorBufferIndexTexCoords = 1,
|
||||||
GeneratorBufferIndexIndexes = 2,
|
GeneratorBufferIndexIndexes = 2,
|
||||||
GeneratorBufferIndexNormals = 3,
|
GeneratorBufferIndexNormals = 3,
|
||||||
|
|
|
@ -20,7 +20,7 @@ typedef struct
|
||||||
{
|
{
|
||||||
float3 position [[attribute(VertexAttributePosition)]];
|
float3 position [[attribute(VertexAttributePosition)]];
|
||||||
float3 normal [[attribute(VertexAttributeNormal)]];
|
float3 normal [[attribute(VertexAttributeNormal)]];
|
||||||
float2 texCoord [[attribute(VertexAttributeTexcoord)]];
|
float2 texCoord [[attribute(VertexAttributeTexCoord)]];
|
||||||
} Vertex;
|
} Vertex;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -65,17 +65,19 @@ fragment float4 fragmentShader(ColorInOut in [[stage_in]],
|
||||||
|
|
||||||
#pragma mark - Normal Shaders
|
#pragma mark - Normal Shaders
|
||||||
|
|
||||||
vertex float4 normalVertexShader(constant float3 *positions [[buffer(BufferIndexMeshPositions)]],
|
vertex float4 normalVertexShader(constant packed_float3 *positions [[buffer(BufferIndexMeshPositions)]],
|
||||||
constant float3 *normals [[buffer(BufferIndexNormals)]],
|
constant packed_float3 *normals [[buffer(BufferIndexNormals)]],
|
||||||
|
constant Uniforms &uniforms [[buffer(BufferIndexUniforms)]],
|
||||||
uint instID [[instance_id]],
|
uint instID [[instance_id]],
|
||||||
uint vertID [[vertex_id]])
|
uint vertID [[vertex_id]])
|
||||||
{
|
{
|
||||||
float3 out = positions[instID];
|
float3 v = positions[instID];
|
||||||
if ( vertID == 1 )
|
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()
|
fragment half4 normalFragmentShader()
|
||||||
|
|
|
@ -23,9 +23,9 @@ class Terrain: NSObject {
|
||||||
desc.attributes[VertexAttribute.normal.rawValue].offset = 0
|
desc.attributes[VertexAttribute.normal.rawValue].offset = 0
|
||||||
desc.attributes[VertexAttribute.normal.rawValue].bufferIndex = BufferIndex.normals.rawValue
|
desc.attributes[VertexAttribute.normal.rawValue].bufferIndex = BufferIndex.normals.rawValue
|
||||||
|
|
||||||
desc.attributes[VertexAttribute.texcoord.rawValue].format = .float2
|
desc.attributes[VertexAttribute.texCoord.rawValue].format = .float2
|
||||||
desc.attributes[VertexAttribute.texcoord.rawValue].offset = 0
|
desc.attributes[VertexAttribute.texCoord.rawValue].offset = 0
|
||||||
desc.attributes[VertexAttribute.texcoord.rawValue].bufferIndex = BufferIndex.meshGenerics.rawValue
|
desc.attributes[VertexAttribute.texCoord.rawValue].bufferIndex = BufferIndex.meshGenerics.rawValue
|
||||||
|
|
||||||
desc.layouts[BufferIndex.meshPositions.rawValue].stride = 12
|
desc.layouts[BufferIndex.meshPositions.rawValue].stride = 12
|
||||||
desc.layouts[BufferIndex.meshPositions.rawValue].stepRate = 1
|
desc.layouts[BufferIndex.meshPositions.rawValue].stepRate = 1
|
||||||
|
@ -63,7 +63,7 @@ class Terrain: NSObject {
|
||||||
}
|
}
|
||||||
attributes[VertexAttribute.position.rawValue].name = MDLVertexAttributePosition
|
attributes[VertexAttribute.position.rawValue].name = MDLVertexAttributePosition
|
||||||
attributes[VertexAttribute.normal.rawValue].name = MDLVertexAttributeNormal
|
attributes[VertexAttribute.normal.rawValue].name = MDLVertexAttributeNormal
|
||||||
attributes[VertexAttribute.texcoord.rawValue].name = MDLVertexAttributeTextureCoordinate
|
attributes[VertexAttribute.texCoord.rawValue].name = MDLVertexAttributeTextureCoordinate
|
||||||
|
|
||||||
plane.vertexDescriptor = mdlVertexDescriptor
|
plane.vertexDescriptor = mdlVertexDescriptor
|
||||||
|
|
||||||
|
@ -82,8 +82,7 @@ class Terrain: NSObject {
|
||||||
|
|
||||||
private let updateHeightsPipeline: MTLComputePipelineState
|
private let updateHeightsPipeline: MTLComputePipelineState
|
||||||
private let updateSurfaceNormalsPipeline: MTLComputePipelineState
|
private let updateSurfaceNormalsPipeline: MTLComputePipelineState
|
||||||
private let updateVertexNormalsPipeline: MTLComputePipelineState
|
|
||||||
|
|
||||||
let dimensions: float2
|
let dimensions: float2
|
||||||
let segments: uint2
|
let segments: uint2
|
||||||
let vertexDescriptor: MTLVertexDescriptor
|
let vertexDescriptor: MTLVertexDescriptor
|
||||||
|
@ -113,7 +112,6 @@ class Terrain: NSObject {
|
||||||
do {
|
do {
|
||||||
updateHeightsPipeline = try Terrain.computePipeline(withFunctionNamed: "updateGeometryHeights", device: device, library: library)
|
updateHeightsPipeline = try Terrain.computePipeline(withFunctionNamed: "updateGeometryHeights", device: device, library: library)
|
||||||
updateSurfaceNormalsPipeline = try Terrain.computePipeline(withFunctionNamed: "updateGeometryNormals", 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 {
|
} catch {
|
||||||
print("Unable to create compute pipelines for terrain geometry updates. Error: \(error)")
|
print("Unable to create compute pipelines for terrain geometry updates. Error: \(error)")
|
||||||
return nil
|
return nil
|
||||||
|
@ -148,10 +146,10 @@ class Terrain: NSObject {
|
||||||
computeEncoder.setComputePipelineState(updateHeightsPipeline)
|
computeEncoder.setComputePipelineState(updateHeightsPipeline)
|
||||||
computeEncoder.setTexture(generator.outTexture, index: GeneratorTextureIndex.in.rawValue)
|
computeEncoder.setTexture(generator.outTexture, index: GeneratorTextureIndex.in.rawValue)
|
||||||
let vertexBuffer = mesh.vertexBuffers[BufferIndex.meshPositions.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]
|
let texCoordBuffer = mesh.vertexBuffers[BufferIndex.meshGenerics.rawValue]
|
||||||
computeEncoder.setBuffer(texCoordBuffer.buffer, offset: texCoordBuffer.offset, index: BufferIndex.texCoords.rawValue)
|
computeEncoder.setBuffer(texCoordBuffer.buffer, offset: texCoordBuffer.offset, index: GeneratorBufferIndex.texCoords.rawValue)
|
||||||
computeEncoder.setBuffer(uniforms, offset: uniformsOffset, index: BufferIndex.uniforms.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.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.popDebugGroup()
|
||||||
computeEncoder.endEncoding()
|
computeEncoder.endEncoding()
|
||||||
|
@ -163,11 +161,11 @@ class Terrain: NSObject {
|
||||||
computeEncoder.pushDebugGroup("Update Geometry: Surface Normals")
|
computeEncoder.pushDebugGroup("Update Geometry: Surface Normals")
|
||||||
computeEncoder.setComputePipelineState(updateSurfaceNormalsPipeline)
|
computeEncoder.setComputePipelineState(updateSurfaceNormalsPipeline)
|
||||||
let indexBuffer = mesh.submeshes[0].indexBuffer
|
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]
|
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.indexes.rawValue)
|
||||||
let normalBuffer = mesh.vertexBuffers[BufferIndex.faceNormals.rawValue]
|
// let normalBuffer = mesh.vertexBuffers[BufferIndex.faceNormals.rawValue]
|
||||||
computeEncoder.setBuffer(normalBuffer.buffer, offset: normalBuffer.offset, index: 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.dispatchThreads(MTLSize(width: mesh.vertexCount, height: 1, depth: 1), threadsPerThreadgroup: MTLSize(width: 64, height: 1, depth: 1))
|
||||||
computeEncoder.popDebugGroup()
|
computeEncoder.popDebugGroup()
|
||||||
computeEncoder.endEncoding()
|
computeEncoder.endEncoding()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue