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