Lighting
Light = ambient + diffuse (Lambert: max(N·L, 0)) + specular (Phong: max(R·V, 0)^shininess, where R = reflect(-L, N)).
19.1 The Phong reflection model
Light = ambient + diffuse (Lambert: max(N·L, 0)) + specular (Phong: max(R·V, 0)^shininess, where R = reflect(-L, N)). Blinn–Phong uses the half vector H = normalize(L + V) and max(N·H, 0)^shininess — cheaper, better at grazing angles, and the basis for microfacet models.
19.2 Blinn–Phong pixel shader with multiple lights
Check: LightData is 64 bytes (4 registers), so the cbuffer array stride is exactly 64 — matching a C++ array of the same struct.
#define MAX_LIGHTS 16
#define LIGHT_DIRECTIONAL 0
#define LIGHT_POINT 1
#define LIGHT_SPOT 2
struct LightData
{
float3 position; uint type;
float3 direction; float range;
float3 color; float intensity;
float spotInner; float spotOuter; float2 pad; // cosines of cone angles
};
cbuffer Lights : register(b3)
{
LightData gLights[MAX_LIGHTS];
uint gLightCount;
float3 gAmbient;
};
Texture2D gAlbedoTex : register(t0);
SamplerState gAniso : register(s0);
float3 BlinnPhong(LightData L, float3 P, float3 N, float3 V, float3 albedo, float shininess)
{
float3 toLight; float atten = 1.0;
if (L.type == LIGHT_DIRECTIONAL)
{
toLight = -L.direction;
}
else
{
float3 d = L.position - P;
float dist = length(d);
toLight = d / dist;
float falloff = saturate(1.0 - pow(dist / L.range, 4)); // windowed inverse-square
atten = falloff * falloff / (dist * dist + 1.0);
if (L.type == LIGHT_SPOT)
{
float cd = dot(-toLight, L.direction);
atten *= smoothstep(L.spotOuter, L.spotInner, cd);
}
}
float3 H = normal
…19.3 Shading frequency
Per-vertex (Gouraud): lighting in the VS, interpolated — cheap, misses highlights.
Per-pixel: lighting in the PS — standard.
Per-sample: input SV_SampleIndex or sample interpolation — MSAA quality, expensive.
19.4 Stylized lighting
For wrap lighting use saturate((dot(N, L) + w) / (1 + w)); for a hemispheric ambient use lerp(groundColor, skyColor, N.y * 0.5 + 0.5).
float3 Toon(float3 N, float3 L, float3 V, float3 baseColor)
{
float ndl = dot(N, L);
float band = ndl > 0.6 ? 1.0 : ndl > 0.2 ? 0.6 : 0.3; // quantized diffuse
float rim = pow(1.0 - saturate(dot(N, V)), 4.0); // rim light
float spec = step(0.95, dot(N, normalize(L + V))); // hard specular
return baseColor * band + rim * 0.3 + spec;
}