Transcript Shadowing

OpenGL Shadow
Content
Shadowing using Stencil Buffer
Shadowing using Projective Texture
Shadow map
Shadow volume
Shadows are important …
It is usually better to have an inaccurate shadow than none at all
Terminology
(area) light source
occluder
penumbra
umbra
shadow
Hard Shadow
Occludee
(receiver)
Soft Shadow
receiver
Soft Shadows (Ref)
–Point light generates hard shadows only
–Soft shadows are NOT generated by low pass filters
–Soft shadows are generally preferable, if possible.
Planar Projection Shadow (xz plane)
l
y
ly
lx  px

l x  vx l y  v y
v: any pt on
model
px 
v
x
shadow
p
l y vx  lx v y
ly  vy
l y
0
M 
0

 0
Similarly, p z 
 lx
0
0
0
 lz
ly
1
0
0
0 
, p  Mv
0

l y 
l y vz  l z v y
ly  vy
Planar Projection (general)
l
v
n
pl
d  nl
(v  l )
n  (v  l )
 lx ny
 l x nz
n  l  d  l y ny
 l y nz
 lz ny
n  l  d  l z nz
 ny
 nz
p
n  l  d  l x nx
 l n
y x

M

 l z nx

 nx

 lx d 
 l y d 
 lz d 

n  l 
Planar Projection Shadow
Problems [& Solutions]





Z-fighting [polygon offset, stencil]
Shadow fall outside of the receiver [stencil]
Semi-transparent shadows [blending + stencil,
ensuring each pixel is drawn at most once]
Planar receiver only
Need to render each frame (But for static objects,
the shadows are view-independent) [render the
shadow into texture]
Remark
Shadow polygons are
blended with the floor,
one-by-one
Repetitive blending …
To prevent this from
happening, use stencil
buffer
When a polygon is
drawn, increment the
stencil count (therefore,
the area is not drawn
again)
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
Stencil Setting
Projective Texture Shadow
Overview
In the display callback
Render occluders to projective shadow
texture (with FBO)
Set up texture unit 1 for projective
(shadow) texture; render receiver
Render occluder to complete the scene
Steps
Terrain: triangle strip
FBO for render to shadow texture
Render projective (shadow) texture
Terrain (trianglestrip)
[i-1,j]
[i,j]
[0,0] [0,1] [1,0] [1,1] [2,0] [2,1] …[4,0] [4,1]
0
[i-1,j+1]
1
Set normal at
2
x
[i,j]
3
4
0
1
2
z
3
4
[i-1,j+1] [i,j+1]
Render to Shadow Texture
Render occluder (unlit) as black objects
Clear color set to (1,1,1)
Projective Shadow Texture
Set texture environment to modulate


Shadowed part: dark (modulated by GREY)
Unshadowed part: unchanged (modulated
by WHITE)
Use the same projective parameters
(fovy, …) as in render to texture
Tricks
This is normal!
If you see something like
this, the artifact comes
from projective texture
clamping: the shadow
touches the texture border.
It can be alleviated by
increasing the fov or
raising the light position
Shadow Map Primer
Image-based technique by Lance
Williams (1978)
Amenable to h/w implementation
Coordinate Transformation
World
Space
Note the
convention
on X and X-1
Texgen (eye-linear)
Ee: transformed plane
equations
We do not use
texture matrix T for
now
Plight: projection matrix for light frustum
S: scale-bias matrix from [-1,1] to [0,1]
[s,t,r,q]T is actually [x,y,z,w]T
(scale-biased clip coordinates)
Depth Map Comparison
Render from eye’s point of view
“Convert” the eye coordinates to light
space via texgen facility
ObjectLight
EyeLight
Summary
EyeLight
s
t 
 
r 
 
q 
 12 0 0 12 
 vx 
0 1 0 1 
v 
1  y 
2
2

P
V
V
0 0 12 12  p p e  vz 


 
0 0 0 1 
vw  eye
After converting to light space
Compare with depth texture:
 ps pt 
pr
Z ls 
 texture _ 2 D ,   Z sm
p p 
pq
 q q
Zls > Zsm:
in shadow
Use comparison result (0 or 1) in
fragment shading (can be bilinearly
filtered): use the result directly to
modulate the diffuse and specular
intensity
GL_ARB_shadow (ref)
Require depth texture extension
Enable shadow comparison

This comparison produces
a boolean texture value
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_COMPARE_MODE_ARB,
GL_COMPARE_R_TO_TEXTURE);
Not in shadow if r<=texture

glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
Shadow comparison should generate an INTENSITY
result (or ALPHA result)

glTexParameteri(GL_TEXTURE_2D,
GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY)
Set alpha test to discard false comparisons


glAlphaFunc(GL_GEQUAL, 0.99f);
glEnable(GL_ALPHA_TEST);
From GL_ARB_SHADOW
Implementation
Generate shadow map




render the scene from light
position
Lighting, texturing, color buffer
writes OFF
Copy depth buffer content to a
depth texture
Note: shadow map is view
independent (only need to be
updated if scene or light moved)
[multitexture]
Set shadowmap at the fourth texture unit
Use the other three for original textures
Diffuse Pass



Ambient pass

Render the scene from camera
with only ambient lighting


Set up necessary manipulations
for coordinate transformation
(eye coordinate to light
coordinate)
Set up shadow map parameters
(compare_mode, compare_func,
deptht texture_mode)
Render the scene with lights on;
the shadow map will generate a
boolean texture result based on
shadow test. The test will set
the alpha values of the
fragment. [in shadow a = 0,
otherwise, a = 1]
The alpha test will let the lit
(unshadowed) fragment pass,
covering the original ambient
fragments.
Final color is ambient pass +
full colora
FAQ
Fov for light need to be
the same as te fov of
camera?
No. The shadow
comparison is solely
based on depth texture
and the converted clip
coordinates in light
coordinate system. The
projection matrices
(where fov plays a part)
are of no importance.
Aspect ratio of shadow
map need to be the
same as the aspect
ratio of the window?
No. (similar reason as in
the left.) The projection
matrices (where aspect
ratio plays a part) are of
no importance.
Trouble Shooting
fov=45
fov=90
The artifact on the base is because the shadow map coverage contains
only part of the base. It can be remedied by increasing the fov of the
light frustum (but sacrificing the depth texture resolution)
Using Shaders…
Texgen is not performed
The inverse of viewing matrix need to be
computed directly (see projective texture)
Only two passes are required


First pass: generate shadow map
Second pass: render the shadowed and lit part
(one pass less than fixed functionality)
Remove unwanted artifact (more precise
control by rendering shadowed part only
within light frustum)
Bias(1)
Bias(2)
Bias(3)
Alias(1)
Alias(2)
Issues
Bias factor

Depth in shadow map often slightly lower
than that of the viewer
Aliasing due to point-sampling



Percentage closer filtering: instead of
single point sample, take four closest.
Bilinearly interpolate the results (in/out
shadow) to calculate the lighting
Provide pseudo-soft shadows
Shadow Map
Advantage:


Simple
Shadow map is view independent
Disadvantage:



Shadow distance from light position may appear
blocky
Storage
Light source in the view volume?
Shadow Volume
Geometry-based
technique first
proposed by Frank
Crow in 1977
Need stencil
buffer!
Point light
[illustration here based on point light]
Silhouette:
the border of front/back
facing polygons w.r.t.
light source
Z-pass Algorithm
Pitfalls of Z-Pass
Figure 6: When eye point is within the shadow volume,
depth-pass stencil operation fails
Carmack’s reverse (Z-fail)
1
Z-fail Requires Capping
Shadow volume must be a closed volume
(require front and back caps). Back cap can
be at infinity !?
Only need to close the back gap for point light
(directional light is closed by definition: all
rays intersect to a single point at infinity)
We can build the front cap by using the front facing triangles
with respect to the light source. The geometries used in the
front cap can then be extruded, with their ordering reversed,
to create the back cap.
Reusing front cap
Triangular-Fan
Algorithm (Shadow Volume)
Bottlenecks
Silhouette Determination
View Frustum Clipping1
Solution by Mark Kilgard
View Frustum Clipping2
Solution by Eric Lengyel…
Depth-clamping (Kilgard & Everitt): hardware solution
Better, unless viewer enters shadow vol.
Depends on type of games:
z-pass sufficient for Diablo (暗黑
破壞神)
Shadow Volume by Shaders
Unless CPU is totally occupied, may not
be beneficial (silhouette computation;
too many vertices processed by shaders)
Advantages
• Support omnidirectional lights
• Exact shadow boundaries
Disadvantages
• Fill-rate intensive
• Expensive to compute shadow volumes
• Hard shadow boundaries, not soft shadows
• Difficult to implement robustly
Area Light