Get face normals rendering
This commit is contained in:
parent
f28e6e08df
commit
296af144ce
5 changed files with 90 additions and 41 deletions
|
@ -320,21 +320,34 @@ class Renderer: NSObject, MTKViewDelegate {
|
|||
|
||||
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.pushDebugGroup("Draw Vertex Normals")
|
||||
|
||||
renderEncoder.setVertexBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
|
||||
let vertexBuffer = terrain.mesh.vertexBuffers[BufferIndex.meshPositions.rawValue]
|
||||
let normalBuffer = terrain.mesh.vertexBuffers[BufferIndex.normals.rawValue]
|
||||
|
||||
renderEncoder.setVertexBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: NormalBufferIndex.points.rawValue)
|
||||
renderEncoder.setVertexBuffer(normalBuffer.buffer, offset: normalBuffer.offset, index: NormalBufferIndex.normals.rawValue)
|
||||
renderEncoder.setVertexBuffer(dynamicUniformBuffer, offset: uniformBufferOffset, index: NormalBufferIndex.uniforms.rawValue)
|
||||
|
||||
renderEncoder.drawPrimitives(type: .line, vertexStart: 0, vertexCount: 2, instanceCount: terrain.mesh.vertexCount)
|
||||
|
||||
renderEncoder.popDebugGroup()
|
||||
|
||||
renderEncoder.pushDebugGroup("Draw Face Normals")
|
||||
|
||||
let faceMidpointsBuffer = terrain.faceMidpointsBuffer
|
||||
let faceNormalsBuffer = terrain.faceNormalsBuffer
|
||||
|
||||
renderEncoder.setVertexBuffer(faceMidpointsBuffer, offset: 0, index: NormalBufferIndex.points.rawValue)
|
||||
renderEncoder.setVertexBuffer(faceNormalsBuffer, offset: 0, index: NormalBufferIndex.normals.rawValue)
|
||||
renderEncoder.setVertexBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: NormalBufferIndex.uniforms.rawValue)
|
||||
renderEncoder.drawPrimitives(type: .line, vertexStart: 0, vertexCount: 2, instanceCount: 2 * Int(terrain.segments.x * terrain.segments.y))
|
||||
renderEncoder.popDebugGroup()
|
||||
|
||||
renderEncoder.endEncoding()
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
|
||||
#include <simd/simd.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, BufferIndex)
|
||||
{
|
||||
typedef NS_ENUM(NSInteger, BufferIndex) {
|
||||
BufferIndexMeshPositions = 0,
|
||||
BufferIndexNormals = 1,
|
||||
BufferIndexMeshGenerics = 2,
|
||||
|
@ -30,6 +29,12 @@ typedef NS_ENUM(NSInteger, BufferIndex)
|
|||
BufferIndexUniforms = 4,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, NormalBufferIndex) {
|
||||
NormalBufferIndexPoints = 0,
|
||||
NormalBufferIndexNormals = 1,
|
||||
NormalBufferIndexUniforms = 2,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, VertexAttribute)
|
||||
{
|
||||
VertexAttributePosition = 0,
|
||||
|
@ -48,7 +53,8 @@ typedef NS_ENUM(NSInteger, GeneratorBufferIndex) {
|
|||
GeneratorBufferIndexIndexes = 2,
|
||||
GeneratorBufferIndexNormals = 3,
|
||||
GeneratorBufferIndexFaceNormals = 4,
|
||||
GeneratorBufferIndexUniforms = 5,
|
||||
GeneratorBufferIndexFaceMidpoints = 5,
|
||||
GeneratorBufferIndexUniforms = 6,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, GeneratorTextureIndex) {
|
||||
|
|
|
@ -27,19 +27,30 @@ typedef struct
|
|||
{
|
||||
float4 position [[position]];
|
||||
float3 normal;
|
||||
float4 color;
|
||||
float2 texCoord;
|
||||
} ColorInOut;
|
||||
|
||||
#pragma mark - Geometry Shaders
|
||||
|
||||
vertex ColorInOut vertexShader(Vertex in [[stage_in]],
|
||||
constant packed_float3 *faceNormals [[buffer(BufferIndexFaceNormals)]],
|
||||
constant Uniforms &uniforms [[buffer(BufferIndexUniforms)]])
|
||||
constant float3 *faceNormals [[buffer(BufferIndexFaceNormals)]],
|
||||
constant Uniforms &uniforms [[buffer(BufferIndexUniforms)]],
|
||||
uint vid [[vertex_id]])
|
||||
{
|
||||
ColorInOut out;
|
||||
|
||||
out.position = uniforms.projectionMatrix * uniforms.modelViewMatrix * float4(in.position, 1.0);
|
||||
out.normal = uniforms.normalMatrix * in.normal;
|
||||
float4 vertexCoords = float4(in.position, 1.0);
|
||||
float4 eyeCoords = uniforms.modelViewMatrix * vertexCoords;
|
||||
out.position = uniforms.projectionMatrix * eyeCoords;
|
||||
|
||||
float3 normal = normalize(uniforms.normalMatrix * in.normal);
|
||||
out.normal = normal;
|
||||
|
||||
float3 lightDirection = -eyeCoords.xyz;
|
||||
float lightDotNormal = dot(normal, lightDirection);
|
||||
out.color = float4(abs(lightDotNormal) * float3(0.3), 1.0);
|
||||
|
||||
out.texCoord = in.texCoord;
|
||||
|
||||
return out;
|
||||
|
@ -49,20 +60,14 @@ fragment float4 fragmentShader(ColorInOut in [[stage_in]],
|
|||
constant Uniforms & uniforms [[ buffer(BufferIndexUniforms) ]],
|
||||
texture2d<half> colorMap [[ texture(TextureIndexColor) ]])
|
||||
{
|
||||
constexpr sampler colorSampler(mip_filter::linear,
|
||||
mag_filter::linear,
|
||||
min_filter::linear);
|
||||
|
||||
half4 colorSample = colorMap.sample(colorSampler, in.texCoord.xy);
|
||||
|
||||
return float4(1.0);
|
||||
return in.color;
|
||||
}
|
||||
|
||||
#pragma mark - Normal Shaders
|
||||
|
||||
vertex float4 normalVertexShader(constant packed_float3 *positions [[buffer(BufferIndexMeshPositions)]],
|
||||
constant packed_float3 *normals [[buffer(BufferIndexNormals)]],
|
||||
constant Uniforms &uniforms [[buffer(BufferIndexUniforms)]],
|
||||
vertex float4 normalVertexShader(constant packed_float3 *positions [[buffer(NormalBufferIndexPoints)]],
|
||||
constant packed_float3 *normals [[buffer(NormalBufferIndexNormals)]],
|
||||
constant Uniforms &uniforms [[buffer(NormalBufferIndexUniforms)]],
|
||||
uint instID [[instance_id]],
|
||||
uint vertID [[vertex_id]])
|
||||
{
|
||||
|
@ -71,7 +76,7 @@ vertex float4 normalVertexShader(constant packed_float3 *positions [[buffer(Buff
|
|||
{
|
||||
v += 0.25 * normals[instID];
|
||||
}
|
||||
float4 out = uniforms.projectionMatrix * uniforms.modelViewMatrix * float4(v, 1.0);
|
||||
float4 out = uniforms.projectionMatrix * uniforms.modelViewMatrix * float4(v, 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,16 +61,23 @@ kernel void updateGeometryHeights(texture2d<float> texture [[texture(GeneratorTe
|
|||
vertexes[vIdx].y = height.r;
|
||||
}
|
||||
|
||||
kernel void updateGeometryNormals(constant float3 *vertexes [[buffer(GeneratorBufferIndexMeshPositions)]],
|
||||
constant packed_uint3 *indexes [[buffer(GeneratorBufferIndexIndexes)]],
|
||||
device packed_float3 *normals [[buffer(GeneratorBufferIndexFaceNormals)]],
|
||||
kernel void updateGeometryNormals(constant packed_float3 *meshPositions [[buffer(GeneratorBufferIndexMeshPositions)]],
|
||||
constant packed_ushort3 *indexes [[buffer(GeneratorBufferIndexIndexes)]],
|
||||
device packed_float3 *faceNormals [[buffer(GeneratorBufferIndexFaceNormals)]],
|
||||
device packed_float3 *faceMidpoints [[buffer(GeneratorBufferIndexFaceMidpoints)]],
|
||||
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;
|
||||
const ushort3 triangleIndex = indexes[tid];
|
||||
|
||||
const float3 v1 = meshPositions[triangleIndex.x];
|
||||
const float3 v2 = meshPositions[triangleIndex.y];
|
||||
const float3 v3 = meshPositions[triangleIndex.z];
|
||||
|
||||
float3 side1 = v1 - v2;
|
||||
float3 side2 = v1 - v3;
|
||||
float3 normal = normalize(cross(side1, side2));
|
||||
faceNormals[tid] = normal;
|
||||
faceMidpoints[tid] = 0.3333333333 * (v1 + v2 + v3);
|
||||
}
|
||||
|
||||
kernel void updateGeometryVertexNormals()
|
||||
|
|
|
@ -88,6 +88,7 @@ class Terrain: NSObject {
|
|||
let vertexDescriptor: MTLVertexDescriptor
|
||||
let mesh: MTKMesh
|
||||
let faceNormalsBuffer: MTLBuffer
|
||||
let faceMidpointsBuffer: MTLBuffer
|
||||
|
||||
var generator: TerrainGenerator
|
||||
|
||||
|
@ -118,15 +119,23 @@ class Terrain: NSObject {
|
|||
return nil
|
||||
}
|
||||
|
||||
// A normal is a float 3. Two triangles per segment, x * t segments.
|
||||
let faceNormalsLength = MemoryLayout<float3>.stride * 2 * Int(segments.x * segments.y)
|
||||
guard let faceNormalsBuf = device.makeBuffer(length: faceNormalsLength, options: .storageModePrivate) else {
|
||||
// A normal is a float3. Two triangles per segment, x * t segments.
|
||||
let faceDataLength = 12 * 2 * Int(segments.x * segments.y)
|
||||
guard let faceNormalsBuf = device.makeBuffer(length: faceDataLength, options: .storageModeShared) else {
|
||||
print("Couldn't create buffer for face normals")
|
||||
return nil
|
||||
}
|
||||
faceNormalsBuffer = faceNormalsBuf
|
||||
|
||||
guard let faceMidpointsBuf = device.makeBuffer(length: faceDataLength, options: .storageModeShared) else {
|
||||
print("Couldn't create buffer for face normals")
|
||||
return nil
|
||||
}
|
||||
faceMidpointsBuffer = faceMidpointsBuf
|
||||
|
||||
super.init()
|
||||
|
||||
populateInitialFaceNormals()
|
||||
}
|
||||
|
||||
func generate(completion: @escaping () -> Void) -> Progress {
|
||||
|
@ -134,7 +143,7 @@ class Terrain: NSObject {
|
|||
generatorQueue.async {
|
||||
progress.becomeCurrent(withPendingUnitCount: 1)
|
||||
|
||||
let _ = self.generator.render(progress: progress)
|
||||
let heights = self.generator.render(progress: progress)
|
||||
progress.completedUnitCount += 1
|
||||
|
||||
// TODO: Store heights
|
||||
|
@ -149,7 +158,7 @@ class Terrain: NSObject {
|
|||
|
||||
func scheduleGeometryUpdates(inCommandBuffer commandBuffer: MTLCommandBuffer, uniforms: MTLBuffer, uniformsOffset: Int) {
|
||||
if let computeEncoder = commandBuffer.makeComputeCommandEncoder() {
|
||||
print("Scheduling update geometry heights")
|
||||
//print("Scheduling update geometry heights")
|
||||
computeEncoder.label = "Geometry Heights Encoder"
|
||||
computeEncoder.pushDebugGroup("Update Geometry: Heights")
|
||||
computeEncoder.setComputePipelineState(updateHeightsPipeline)
|
||||
|
@ -165,18 +174,27 @@ class Terrain: NSObject {
|
|||
}
|
||||
|
||||
if let computeEncoder = commandBuffer.makeComputeCommandEncoder() {
|
||||
print("Scheduling update geometry normals")
|
||||
//print("Scheduling update geometry normals")
|
||||
computeEncoder.label = "Surface Normals Encoder"
|
||||
computeEncoder.pushDebugGroup("Update Geometry: Surface Normals")
|
||||
computeEncoder.setComputePipelineState(updateSurfaceNormalsPipeline)
|
||||
let indexBuffer = mesh.submeshes[0].indexBuffer
|
||||
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: GeneratorBufferIndex.indexes.rawValue)
|
||||
computeEncoder.setBuffer(indexBuffer.buffer, offset: indexBuffer.offset, index: GeneratorBufferIndex.indexes.rawValue)
|
||||
let positionsBuffer = mesh.vertexBuffers[BufferIndex.meshPositions.rawValue]
|
||||
computeEncoder.setBuffer(positionsBuffer.buffer, offset: positionsBuffer.offset, index: GeneratorBufferIndex.meshPositions.rawValue)
|
||||
computeEncoder.setBuffer(faceNormalsBuffer, offset: 0, index: GeneratorBufferIndex.faceNormals.rawValue)
|
||||
computeEncoder.setBuffer(faceMidpointsBuffer, offset: 0, index: GeneratorBufferIndex.faceMidpoints.rawValue)
|
||||
computeEncoder.dispatchThreads(MTLSize(width: 2 * Int(segments.x * segments.y), height: 1, depth: 1), threadsPerThreadgroup: MTLSize(width: 64, height: 1, depth: 1))
|
||||
computeEncoder.popDebugGroup()
|
||||
computeEncoder.endEncoding()
|
||||
}
|
||||
}
|
||||
|
||||
private func populateInitialFaceNormals() {
|
||||
let normalsCount = 2 * Int(segments.x * segments.y)
|
||||
let faceNormals = UnsafeMutableRawPointer(faceNormalsBuffer.contents()).bindMemory(to: float3.self, capacity: normalsCount)
|
||||
for i in 0..<normalsCount {
|
||||
faceNormals[i] = float3(0, 1, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue