# Chapter 14: Spotlight Shadow Map

#1

Hi,

I’m really enjoying the book! In chapter 14 (pg. 392/ 393) we create a shadow map using an ortho projection matrix. In the description, the book mentions " If instead you used a spotlight, for example, you would use the perspective projection matrix." I’m trying to accomplish this however I’m having a hard time getting the map to work with perspective projection. Do you or anyone have a working example I could reference? Thanks!

#2

@smehsu we’re happy you’re enjoying the book!

unfortunately, I haven’t seen implementations using the perspective matrix… mostly because when we think of shadows they are most of the time caused by a directional light source such as the sun.

#3

I managed to figure out spotlights. I’m still trying to figure out point lights.

``````let aspect = Float(view.bounds.width) / Float(view.bounds.height)
scene.uniforms.projectionMatrix = float4x4(projectionFov: radians(fromDegrees: 70), near: 0.01, far: 16, aspect: aspect)

let position: float3 = [-sunlight.position.x, -sunlight.position.y, -sunlight.position.z]
let center: float3 = [0, 0, 0]
let lookAt = float4x4(eye: position, center: position - sunlight.coneDirection, up: [0,1,0])

scene.uniforms.viewMatrix = float4x4(translation: [0, 0, 7]) * lookAt
scene.uniforms.shadowMatrix = scene.uniforms.projectionMatrix * scene.uniforms.viewMatrix
``````

``````    matrix_float4x4 mvp = uniforms.projectionMatrix * uniforms.viewMatrix * uniforms.modelMatrix;
float4 position = mvp * vertexIn.position;
float4 worldPosition = uniforms.modelMatrix * vertexIn.position;

float3 directionFromLightToFragment = normalize(light.position - worldPosition.xyz);

if (light.type == Spotlight) {
float3 tConeDirection = light.coneDirection;
float3 coneDirection = normalize(-tConeDirection);
float spotResult = dot(directionFromLightToFragment, coneDirection);
float coneAngle = cos(light.coneAngle);

if (spotResult < coneAngle) {
position = position.xyww;
}
}
``````

``````float2 xy = in.shadowPosition.xy / in.shadowPosition.w;
xy = xy * 0.5 + 0.5;
xy.y = 1 - xy.y;

constexpr sampler s(coord::normalized, filter::linear, address::clamp_to_edge, compare_func:: less);

if (current_sample > shadow_sample ) {
color *= 0.5;
}``````
1 Like
#4

that’s great! let us know about your progress on it.

#5

Pointlight / omni directional shadow maps were significantly more work. Here are the two resources I used:

• It seems the shadow projection matrix needs to have an aspect ratio of 1 instead of using the views width / height.
#6

@smehsu that’s good to hear. thanks for sharing