Upload
suzanna-burke
View
236
Download
2
Embed Size (px)
Citation preview
OpenGL Shadow
Content
Shadowing using Stencil BufferShadowing using Projective Texture Shadow mapShadow volume
Shadows are important …
It is usually better to have an inaccurate shadow than none at all
Terminology
(area) light source
receiver shadow
occluder
umbra
penumbra
Hard Shadow Soft ShadowOccludee (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)
Mvp
l
ll
ll
M
vl
vlvlp
vl
vlvlp
vl
l
vl
pl
y
yz
xy
yy
yzzyz
yy
yxxyx
yy
y
xx
xx
,
010
00
0000
00
Similarly,
x
v
l
y
p
shadow
v: any pt on model
Planar Projection (general)l
v
p
:n•x+d=
0n
lnnnn
dlnldlnnlnl
dlnlnldlnnl
dlnlnlnldln
M
zyx
zzzyzxz
yzyyyxy
xzxyxxx
)()(
lvlvn
lndlp
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-oneRepetitive blending …
To prevent this from happening, use stencil bufferWhen 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);
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
Stencil Setting
Projective Texture Shadow
Overview
In the display callbackRender occluders to projective
shadow texture (with FBO)Set up texture unit 1 for projective
(shadow) texture; render receiverRender occluder to complete the
scene
Steps
Terrain: triangle stripFBO for render to shadow textureRender projective (shadow) texture
Terrain (trianglestrip)
0 1 2 3 44
0
1
2
3
x
z
[0,0] [0,1] [1,0] [1,1] [2,0] [2,1] …[4,0] [4,1]
[i-1,j] [i,j]
[i-1,j+1]
[i,j+1]
[i,j]
[i-1,j+1]
Set normal at
Render to Shadow Texture
Render occluder (unlit) as black objectsClear 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
Ee: transformed plane equations
Plight: projection matrix for light frustum
[s,t,r,q]T is actually [x,y,z,w]T (scale-biased clip coordinates)
Texgen (eye-linear)
We do not use texture matrix T for now
S: scale-bias matrix from [-1,1] to [0,1]
Depth Map Comparison
Render from eye’s point of view“Convert” the eye coordinates to light space via texgen facility
ObjectLight
EyeLight
Summary
EyeLight
eyew
z
y
x
epp
v
v
v
v
VVP
q
r
t
s
1
21
21
21
21
21
21
1000
00
00
00
After converting to light space
Compare with depth texture:
Use comparison result (0 or 1) in fragment shading (can be bilinearly filtered): use the result directly to modulate the diffuse and specular intensity
smq
t
q
s
q
rls Z
p
p
p
pDtexture
p
pZ
,2_
Zls > Zsm: in shadow
GL_ARB_shadow (ref)Require depth texture extensionEnable shadow comparison
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);
This comparison produces a boolean texture value
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)
Ambient pass Render the scene from
camera with only ambient lighting
Diffuse Pass 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 = 0, otherwise, = 1]
The alpha test will let the lit (unshadowed) fragment pass, covering the original ambient fragments.
Final color is ambient pass + full color
[multitexture]Set shadowmap at the fourth texture unitUse the other three for original textures
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
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)
fov=45 fov=90
Using Shaders…
Texgen is not performedThe 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!
Silhouette: the border of front/back facing polygons w.r.t. light source
Point light [illustration here based on point light]
Z-pass Algorithm
Figure 6: When eye point is within the shadow volume, depth-pass stencil operation fails
Pitfalls of Z-Pass
1
Carmack’s reverse (Z-fail)
Shadow volume must be a closed volume (require front and back caps). Back cap can be at infinity !?
Z-fail Requires Capping
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)
Reusing front cap
Triangular-Fan
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.
Algorithm (Shadow Volume)
Bottlenecks
Silhouette Determination
View Frustum Clipping1
Solution by Mark Kilgard
Solution by Eric Lengyel…Depth-clamping (Kilgard & Everitt): hardware solution
View Frustum Clipping2
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