Skip to content

Commit

Permalink
Merge pull request #279 from P0rc3lain/spot-light-angles
Browse files Browse the repository at this point in the history
Interpolate outer and inner spot light angles
  • Loading branch information
mateuszstompor authored Sep 3, 2023
2 parents 26ce5b4 + e5138b3 commit 079f607
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 9 deletions.
2 changes: 2 additions & 0 deletions Engine/Core/Extensions/Porcelain/SpotLight+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ extension SpotLight {
projectionMatrix: light.projectionMatrix,
projectionMatrixInverse: light.projectionMatrixInverse,
coneAngle: light.coneAngle,
innerConeAngle: light.innerConeAngle,
outerConeAngle: light.outerConeAngle,
idx: Int32(index),
castsShadows: light.castsShadows ? 1 : 0)
}
Expand Down
6 changes: 6 additions & 0 deletions Engine/Core/Scene/Light/PNISpotLight.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public struct PNISpotLight: PNSpotLight {
public let intensity: Float
public var influenceRadius: Float
public let coneAngle: PNRadians
public let innerConeAngle: PNRadians
public let outerConeAngle: PNRadians
public let castsShadows: Bool
public let projectionMatrix: simd_float4x4
public let projectionMatrixInverse: simd_float4x4
Expand All @@ -17,12 +19,16 @@ public struct PNISpotLight: PNSpotLight {
intensity: Float,
influenceRadius: Float,
coneAngle: PNRadians,
innerConeAngle: PNRadians,
outerConeAngle: PNRadians,
castsShadows: Bool) {
assertValid(color: color)
self.color = color
self.intensity = intensity
self.influenceRadius = influenceRadius
self.coneAngle = coneAngle
self.innerConeAngle = innerConeAngle
self.outerConeAngle = outerConeAngle
self.castsShadows = castsShadows
self.projectionMatrix = PNISpotLight.projectionMatrix(coneAngle: coneAngle,
influenceRadius: influenceRadius)
Expand Down
2 changes: 2 additions & 0 deletions Engine/Core/Scene/Light/PNSpotLight.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public protocol PNSpotLight {
var intensity: Float { get }
var influenceRadius: Float { get }
var coneAngle: PNRadians { get }
var innerConeAngle: PNRadians { get }
var outerConeAngle: PNRadians { get }
var castsShadows: Bool { get }
var projectionMatrix: simd_float4x4 { get }
var projectionMatrixInverse: simd_float4x4 { get }
Expand Down
2 changes: 2 additions & 0 deletions Engine/MetalBinding/PNShared/Light/SpotLight.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ struct SpotLight {
simd_float4x4 projectionMatrix;
simd_float4x4 projectionMatrixInverse;
float coneAngle;
float innerConeAngle;
float outerConeAngle;
int idx;
uint8_t castsShadows;
};
26 changes: 17 additions & 9 deletions Engine/Shaders/DeferredRendering/Spot.metal
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,21 @@ fragment float4 fragmentSpotLight(RasterizerData in [[stage_in]],
float attenuationFactor = falloffAttenuation(length_squared(fragmentToLight),
light.influenceRadius);
float3 l = normalize(fragmentToLight);
float theta = acos(dot(forwardDirection, l));
if (theta > light.coneAngle/2 || attenuationFactor == 0) {
auto theta = dot(forwardDirection, l);
auto thetaAngle = acos(theta);
if (thetaAngle > light.coneAngle / 2 || attenuationFactor == 0) {
discard_fragment();
}

auto gamma = cos(light.outerConeAngle/2);
auto phi = cos(light.innerConeAngle/2);
float epsilon = phi - gamma;
float intensity = clamp((theta - gamma) / epsilon, 0.0f, 1.0f);

if (light.castsShadows) {
float4 lightSpacesFragmentPosition = modelUniforms[id].modelMatrixInverse * modelUniforms[camera.index].modelMatrix * float4(input.fragmentPosition, 1);
constant auto & invModelMatrix = modelUniforms[id].modelMatrixInverse;
constant auto & invCameraMatrix = modelUniforms[camera.index].modelMatrix;
float4 lightSpacesFragmentPosition = invModelMatrix * invCameraMatrix * float4(input.fragmentPosition, 1);
float4 lightProjectedPosition = light.projectionMatrix * lightSpacesFragmentPosition;
lightProjectedPosition /= lightProjectedPosition.w;
lightProjectedPosition.xy = lightProjectedPosition.xy * 0.5 + 0.5;
Expand All @@ -70,14 +79,13 @@ fragment float4 fragmentSpotLight(RasterizerData in [[stage_in]],
float4 reconstructedPosition = light.projectionMatrixInverse * float4(lightProjectedPosition.xy, existingDepth, 1.0);
reconstructedPosition /= reconstructedPosition.w;
float bias = max(0.05 * (1.0 - dot(input.n, l)), 0.005);

if (lightSpacesFragmentPosition.z < reconstructedPosition.z - bias) {
discard_fragment();
}
}
return float4(attenuationFactor * lighting(l,
eye,
input,
light.color,
light.intensity), 1);
return float4(attenuationFactor * intensity * lighting(l,
eye,
input,
light.color,
light.intensity), 1);
}

0 comments on commit 079f607

Please sign in to comment.