Rewrite lighting shader to use Light and Material objects

This commit is contained in:
Eryn Wells 2018-11-21 22:10:03 -07:00
parent 2ef3781935
commit 91c92c9675
3 changed files with 71 additions and 16 deletions

View file

@ -42,6 +42,11 @@ class Renderer: NSObject, MTKViewDelegate {
var uniformBufferIndex = 0
var uniforms: UnsafeMutablePointer<Uniforms>
var lightsBuffer: MTLBuffer
var lights: UnsafeMutablePointer<Light>
var materialBuffer: MTLBuffer
var material: UnsafeMutablePointer<Material>
var projectionMatrix: matrix_float4x4 = matrix_float4x4()
var rotation: Float = 0
@ -103,7 +108,18 @@ class Renderer: NSObject, MTKViewDelegate {
depthStateDesciptor.isDepthWriteEnabled = true
self.depthState = device.makeDepthStencilState(descriptor:depthStateDesciptor)!
let lightsBufferLength = MemoryLayout<Light>.size * 4
self.lightsBuffer = self.device.makeBuffer(length: lightsBufferLength, options: .storageModeShared)!
self.lights = UnsafeMutableRawPointer(lightsBuffer.contents()).bindMemory(to: Light.self, capacity: 4)
let materialBufferLength = MemoryLayout<Material>.size
self.materialBuffer = self.device.makeBuffer(length: materialBufferLength, options: .storageModeShared)!
self.material = UnsafeMutableRawPointer(materialBuffer.contents()).bindMemory(to: Material.self, capacity: 1)
super.init()
populateLights()
populateMaterials()
}
class func buildRenderPipelineWithDevice(device: MTLDevice,
@ -185,6 +201,22 @@ class Renderer: NSObject, MTKViewDelegate {
return progress
}
private func populateLights() {
for i in 0..<4 {
lights[i].enabled = false
}
lights[0].enabled = true
lights[0].position = simd_float4(x: 2, y: 10, z: 5, w: 1)
lights[0].color = simd_float3(0.5, 0.5, 0)
}
private func populateMaterials() {
material[0].diffuseColor = simd_float3(0.8)
material[0].specularColor = simd_float3(1)
material[0].specularExponent = 10
}
private func updateDynamicBufferState() {
/// Update the state of our uniform buffers before rendering
@ -281,6 +313,9 @@ class Renderer: NSObject, MTKViewDelegate {
renderEncoder.setVertexBuffer(terrain.faceNormalsBuffer, offset: 0, index: BufferIndex.faceNormals.rawValue)
renderEncoder.setVertexBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
renderEncoder.setFragmentBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
renderEncoder.setFragmentBuffer(lightsBuffer, offset: 0, index: BufferIndex.lights.rawValue)
renderEncoder.setFragmentBuffer(materialBuffer, offset: 0, index: BufferIndex.materials.rawValue)
for (index, element) in terrain.mesh.vertexDescriptor.layouts.enumerated() {
guard let layout = element as? MDLVertexBufferLayout else {

View file

@ -22,11 +22,13 @@
#include <simd/simd.h>
typedef NS_ENUM(NSInteger, BufferIndex) {
BufferIndexMeshPositions = 0,
BufferIndexNormals = 1,
BufferIndexMeshGenerics = 2,
BufferIndexFaceNormals = 3,
BufferIndexUniforms = 4,
BufferIndexMeshPositions = 0,
BufferIndexNormals = 1,
BufferIndexMeshGenerics = 2,
BufferIndexFaceNormals = 3,
BufferIndexUniforms = 4,
BufferIndexLights = 5,
BufferIndexMaterials = 6,
};
typedef NS_ENUM(NSInteger, NormalBufferIndex) {

View file

@ -24,7 +24,7 @@ typedef struct {
typedef struct {
float4 position [[position]];
float4 eyeCoords;
float3 eyeCoords;
float3 normal;
float2 texCoord;
} ColorInOut;
@ -42,7 +42,7 @@ vertex ColorInOut vertexShader(Vertex in [[stage_in]],
float4 eyeCoords = uniforms.modelViewMatrix * vertexCoords;
out.position = uniforms.projectionMatrix * eyeCoords;
out.eyeCoords = eyeCoords;
out.eyeCoords = eyeCoords.xyz / eyeCoords.w;
// TODO: Use the face normal.
out.normal = normalize(in.normal);
out.texCoord = in.texCoord;
@ -51,23 +51,41 @@ vertex ColorInOut vertexShader(Vertex in [[stage_in]],
}
fragment float4 fragmentShader(ColorInOut in [[stage_in]],
constant Light *lights [[buffer(BufferIndexLights)]],
constant Material *materials [[buffer(BufferIndexMaterials)]],
constant Uniforms &uniforms [[buffer(BufferIndexUniforms)]])
{
// Compute the normal at this position.
float3 normal = normalize(uniforms.normalMatrix * in.normal);
float3 lightDirection = normalize(float3(-8, 8, 1) - in.eyeCoords.xyz);
// Compute the vector pointing to the light from this position.
float3 lightDirection;
constant Light &light = lights[0];
if (light.position.w == 0.0) {
lightDirection = normalize(light.position.xyz);
} else {
lightDirection = normalize(light.position.xyz / light.position.w - in.eyeCoords);
}
// Compute the direction of the viewer from this position.
float3 viewDirection = normalize(-in.eyeCoords.xyz);
float3 reflection = -reflect(lightDirection, normal);
float4 out;
float lightDotNormal = dot(normal, lightDirection);
if (lightDotNormal <= 0.0) {
float lightDirDotNormal = dot(lightDirection, normal);
if (lightDirDotNormal <= 0.0) {
// No color contribution to this pixel.
out = float4();
out = float4(0);
} else {
float3 color = 0.8 * lightDotNormal * float3(0.6);
float reflectDotViewDirection = dot(reflection, viewDirection);
if (reflectDotViewDirection > 0.0) {
color += 0.4 * pow(reflectDotViewDirection, 10) * float3(0, 0, 1);
constant Material &material = materials[0];
// Comput the direction of reflection given the light direction and the normal at this point. Negate it because the vector returned points from the light to this position and we want it from this position toward the light.
float3 reflection = -reflect(lightDirection, normal);
float3 color = lightDirDotNormal * light.color * material.diffuseColor;
float reflectDotViewDir = dot(reflection, viewDirection);
if (reflectDotViewDir > 0.0) {
float factor = pow(reflectDotViewDir, material.specularExponent);
color += factor * material.specularColor * light.color;
}
out = float4(color, 1);
}