3D Lighting
The ForwardPbrPipeline supports four light types with Cook-Torrance PBR shading. Lights are added per-frame via Draw3D.* commands inside your view function.
What and Why
- Ambient light — Base illumination for the entire scene. One per frame.
- Directional light — Parallel rays (sun, moon). Supports shadow casting.
- Point light — Radial light with position, radius, and falloff. Supports shadow casting.
- Spot light — Cone-shaped light with inner/outer cutoff angles.
All lights are struct types with builder functions. The pipeline uploads them as shader uniforms each frame.
Quick start
let view (ctx: GameContext) (model: Model) (buffer: RenderBuffer3D) =
buffer
|> Draw3D.beginCamera camera
// Ambient
|> Draw3D.setAmbientLight (AmbientLight3D.create (Color(30, 30, 30, 255)))
// Directional (sun)
|> Draw3D.addDirectionalLight (
DirectionalLight3D.create (Vector3(0.3f, -0.7f, -0.5f))
|> DirectionalLight3D.withIntensity 0.8f
)
// Point light (torch)
|> Draw3D.addPointLight (
PointLight3D.create (torchPos, 10f)
|> PointLight3D.withColor Color.Orange
|> PointLight3D.withIntensity 1.5f
|> PointLight3D.withCastsShadows true
)
// Spot light (flashlight)
|> Draw3D.addSpotLight (
SpotLight3D.create (camPos, camDir, 20f)
|> SpotLight3D.withIntensity 2.0f
)
|> Draw3D.drawModel model.PlayerModel model.PlayerTransform
|> Draw3D.endCamera
|> Draw3D.drop
Light types
AmbientLight3D
Uniform base illumination applied to all surfaces.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Base color |
|
|
|
Brightness multiplier |
AmbientLight3D.create (Color(30, 30, 30, 255))
|> AmbientLight3D.withIntensity 0.5f
DirectionalLight3D
Parallel light rays. Use for sun or moon.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Direction rays travel (should be normalized) |
|
|
|
Light color |
|
|
|
Brightness multiplier |
|
|
|
Whether to cast shadows |
DirectionalLight3D.create (Vector3(0.3f, -0.7f, -0.5f))
|> DirectionalLight3D.withColor Color.White
|> DirectionalLight3D.withIntensity 0.8f
|> DirectionalLight3D.withCastsShadows true
PointLight3D
Radial light that emits in all directions from a position.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
World-space position |
|
|
|
Light color |
|
|
|
Brightness multiplier |
|
|
— |
Maximum distance of influence |
|
|
|
Decay exponent (1 = linear, 2 = quadratic) |
|
|
|
Whether to cast shadows |
|
|
|
Per-light bias override (uses pipeline default when |
PointLight3D.create (Vector3(10f, 5f, 0f), 15f)
|> PointLight3D.withColor Color.Orange
|> PointLight3D.withIntensity 1.5f
|> PointLight3D.withFalloff 2.0f
|> PointLight3D.withCastsShadows true
|> PointLight3D.withShadowBias 0.005f
_TIP_: Set
CastsShadows = truesparingly. Each shadow-casting point light renders a cubemap shadow pass. Two or three is a good target for performance.
SpotLight3D
Cone-shaped light with inner and outer cutoff angles.
Field |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
World-space position |
|
|
— |
Direction the cone points (should be normalized) |
|
|
|
Light color |
|
|
|
Brightness multiplier |
|
|
— |
Maximum distance of influence |
|
|
|
Cosine of inner cone half-angle (full brightness) |
|
|
|
Cosine of outer cone half-angle (fade to zero) |
|
|
|
Whether to cast shadows |
|
|
|
Per-light bias override |
SpotLight3D.create (camPos, camDir, 25f)
|> SpotLight3D.withIntensity 2.0f
|> SpotLight3D.withCutoff 0.9f 0.95f // tight beam
|> SpotLight3D.withCastsShadows true
Light limits
The ForwardPbrPipeline defaults to:
Type |
Default max |
|---|---|
Point lights |
8 |
Spot lights |
4 |
Override at pipeline creation:
let pipeline = ForwardPbrPipeline(
maxPointLights = 16,
maxSpotLights = 8
)
Exceeding the limit silently drops extra lights.
Shadow configuration
Global bias
Shadow bias values control the tradeoff between shadow acne (too low) and peter-panning (too high). Set via ShadowBiasConfig:
let pipeline = ForwardPbrPipeline(
shadowBiasConfig = {
DirectionalBias = 0.002f
PointBias = 0.01f
SpotBias = 0.001f
SlopeScaleBias = 0.001f
}
)
Per-light bias
Point and spot lights can override the global bias:
PointLight3D.create (pos, radius)
|> PointLight3D.withCastsShadows true
|> PointLight3D.withShadowBias 0.005f // per-light override
Atlas configuration
The shadow atlas controls resolution and caster capacity:
let pipeline = ForwardPbrPipeline(
shadowAtlasConfig = {
ShadowAtlasConfig.defaults with
Resolution = 4096 // higher = sharper shadows
MaxCasters = 9 // must be perfect square (4, 9, 16, 25, 36)
DirectionalLightSize = ValueSome 30.f // ortho projection half-size
}
)
Field |
Default |
Description |
|---|---|---|
|
2048 |
Atlas texture resolution (square) |
|
16 |
Maximum shadow casters (must be perfect square) |
|
|
Where directional shadows are centered |
|
auto |
Ortho projection half-size for directional shadows |
|
2.0 |
Snap shadow origin to grid to reduce flickering |
See also
- Overview — Architecture and pipeline setup
- Buffer & Commands — All
Draw3D.*functions - Materials — PBR material system
Mibo.Raylib