diff --git a/Terrain2/Renderer.swift b/Terrain2/Renderer.swift index f54c138..9d437f9 100644 --- a/Terrain2/Renderer.swift +++ b/Terrain2/Renderer.swift @@ -181,8 +181,20 @@ class Renderer: NSObject, MTKViewDelegate { } lights[0].enabled = true - lights[0].position = simd_float4(x: 2, y: 10, z: 2, w: 1) - lights[0].color = simd_float3(0.5, 0.5, 0.3) + lights[0].position = simd_float4(x: -12, y: 5, z: -12, w: 1) + lights[0].color = simd_float3(1, 0.5, 0) + + lights[1].enabled = true + lights[1].position = simd_float4(x: 12, y: 5, z: -12, w: 1) + lights[1].color = simd_float3(1, 0, 1) + + lights[2].enabled = true + lights[2].position = simd_float4(x: -12, y: 5, z: 12, w: 1) + lights[2].color = simd_float3(0, 1, 1) + + lights[3].enabled = true + lights[3].position = simd_float4(x: 12, y: 5, z: 12, w: 1) + lights[3].color = simd_float3(1, 1, 0) } private func populateMaterials() { diff --git a/Terrain2/Shaders/Shaders.metal b/Terrain2/Shaders/Shaders.metal index fdd0724..a938a13 100644 --- a/Terrain2/Shaders/Shaders.metal +++ b/Terrain2/Shaders/Shaders.metal @@ -55,39 +55,41 @@ fragment float4 fragmentShader(ColorInOut in [[stage_in]], constant Material *materials [[buffer(BufferIndexMaterials)]], constant Uniforms &uniforms [[buffer(BufferIndexUniforms)]]) { + float4 out; + // Compute the normal at this position. float3 normal = normalize(uniforms.normalMatrix * in.normal); // 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); - } + for (int i = 0; i < 4; i++) { + constant Light &light = lights[i]; - // Compute the direction of the viewer from this position. - float3 viewDirection = normalize(-in.eyeCoords.xyz); - - float4 out; - float lightDirDotNormal = dot(lightDirection, normal); - if (lightDirDotNormal <= 0.0) { - // No color contribution to this pixel. - out = float4(0); - } else { - 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; + float3 lightDirection; + 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); + + + float lightDirDotNormal = dot(lightDirection, normal); + if (lightDirDotNormal > 0.0) { + 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); } - out = float4(color, 1); } return out; } diff --git a/Terrain2/Shaders/TerrainAlgorithms.metal b/Terrain2/Shaders/TerrainAlgorithms.metal index 1d91d2e..ff2ba52 100644 --- a/Terrain2/Shaders/TerrainAlgorithms.metal +++ b/Terrain2/Shaders/TerrainAlgorithms.metal @@ -74,7 +74,7 @@ kernel void updateGeometryNormals(constant packed_float3 *meshPositions [[buffer /// *----*----* (2, 2) /// /// Adding each vector divided by n would be better, but numerical stability -/// isn't low risk here since these vectors are all normalized. +/// is low risk here since these vectors are all normalized. /// kernel void updateGeometryVertexNormals(constant packed_float3 *meshPositions [[buffer(GeneratorBufferIndexMeshPositions)]], constant packed_float3 *faceNormals [[buffer(GeneratorBufferIndexFaceNormals)]], @@ -87,13 +87,13 @@ kernel void updateGeometryVertexNormals(constant packed_float3 *meshPositions [[ float3 normal = float3(); uint adjacent = 0; - if (tid.y > 0 && tid.x > 0) { + if (tid.x > 0 && tid.y > 0) { uint aIndex = 2 * segmentIndex(uint2(tid.x - 1, tid.y - 1), segs) + 1; normal += faceNormals[aIndex]; adjacent += 1; } - if (tid.y > 0 && tid.x < segs.x) { - uint segment = segmentIndex(uint2(tid.x, tid.y - 1), segs); + if (tid.x > 0 && tid.y < segs.y) { + uint segment = segmentIndex(uint2(tid.x - 1, tid.y), segs); uint bIndex = 2 * segment; uint cIndex = 2 * segment + 1; normal += faceNormals[bIndex] + faceNormals[cIndex]; @@ -104,8 +104,8 @@ kernel void updateGeometryVertexNormals(constant packed_float3 *meshPositions [[ normal += faceNormals[dIndex]; adjacent += 1; } - if (tid.x > 0 && tid.y < segs.y) { - uint segment = segmentIndex(uint2(tid.x - 1, tid.y), segs); + if (tid.x < segs.x && tid.y > 0) { + uint segment = segmentIndex(uint2(tid.x, tid.y - 1), segs); uint eIndex = 2 * segment + 1; uint fIndex = 2 * segment; normal += faceNormals[eIndex] + faceNormals[fIndex]; @@ -114,7 +114,7 @@ kernel void updateGeometryVertexNormals(constant packed_float3 *meshPositions [[ if (adjacent != 0) { normal = normalize(normal / float(adjacent)); - uint idx = segmentIndex(tid, segs); + uint idx = segmentIndex(tid, segs) + 1; vertexNormals[idx] = normal; } }