Shadow Volumes on Programmable Graphics Hardware


Published on

Talk at Eurographics 2003. Compute Shadow Volumes on the GPU (pre-geometry shader approach).

Published in: Technology, Art & Photos
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Shadow Volumes on Programmable Graphics Hardware

  1. 1. Shadow Volumes on Programmable Graphics Hardware Stefan Brabec Hans-Peter Seidel MPI Informatik
  2. 2. Overview <ul><li>Shadow Volumes </li></ul><ul><li>Silhouette Generation in Hardware </li></ul><ul><ul><li>Motivation </li></ul></ul><ul><ul><li>Our method </li></ul></ul><ul><ul><li>Results </li></ul></ul><ul><li>Conclusion & Future Work </li></ul>
  3. 3. Shadow Volumes <ul><li>[Crow77] Shadow algorithms for computer graphics </li></ul><ul><ul><li>Compute regions of shadow in 3D </li></ul></ul><ul><ul><ul><li>Object-space algorithm </li></ul></ul></ul><ul><ul><ul><li>Per-pixel correct shadow information </li></ul></ul></ul><ul><ul><ul><li>Cast shadows onto arbitrary receiver geometry </li></ul></ul></ul>
  4. 4. Shadow Volumes <ul><li>Extend occluder polygons to form semi-infinite volumes </li></ul><ul><ul><li>Light source is center-of-projection </li></ul></ul><ul><ul><li>Everything behind occluder is in shadow </li></ul></ul>occluder light shadow region lit
  5. 5. Shadow Volume Generation <ul><li>Trivial way </li></ul><ul><ul><li>One volume for each polygon </li></ul></ul><ul><li>Better </li></ul><ul><ul><li>Silhouette-based approach </li></ul></ul><ul><ul><ul><li>Need to check each edge with each light ! </li></ul></ul></ul>
  6. 6. Shadow Volume Generation <ul><li>An edge is a silhouette edge if it is an edge shared by a front-facing and back-facing triangle/polygon </li></ul>Light Light FF BF FF FF Silhouette Edge (v0,v1) ! No Silhouette Edge ! n 1 n 2 n 1 n 2
  7. 7. Shadow Volume Rendering <ul><li>Stencil-based shadow volumes [Heidmann ‘91] Real shadows real time </li></ul><ul><ul><li>count in-out events using the stencil buffer </li></ul></ul>
  8. 8. Shadow Volume Rendering <ul><li>Number of problems </li></ul><ul><ul><li>near/far clipping plane </li></ul></ul><ul><ul><li>fill rate </li></ul></ul><ul><ul><li>non-closed volumes </li></ul></ul><ul><li>See work from Everitt/Kilgard ! </li></ul>silhouette detection Focus of this talk:
  9. 9. Motivation <ul><li>From some OpenGL discussion forum: </li></ul>
  10. 10. Motivation <ul><li>Silhouette detection is not trivial for complex vertex shaders </li></ul>
  11. 11. Our method <ul><li>Use graphics hardware to compute silhouettes </li></ul><ul><li>State-of-the-art hardware allows computation in object space </li></ul><ul><ul><li>Floating point calculations </li></ul></ul><ul><ul><li>Floating point textures </li></ul></ul><ul><ul><li>Powerful, programmable vertex and fragment processing units </li></ul></ul>
  12. 12. Input Data <ul><li>Supported meshes </li></ul><ul><ul><li>Closed objects (no open edges) </li></ul></ul><ul><ul><li>Two triangles meet at one edge </li></ul></ul>Example: This is not a closed mesh, but since we are only focusing on one edge of this mesh its ok.
  13. 13. Coordinate Transformation <ul><li>First step </li></ul><ul><ul><li>Need to transform all geometry to a global coordinate system </li></ul></ul><ul><ul><li>Also need all light sources in this system </li></ul></ul><ul><li>Common choices </li></ul><ul><ul><li>World space </li></ul></ul><ul><ul><ul><li>View-independent </li></ul></ul></ul><ul><ul><li>Eye Space </li></ul></ul><ul><ul><ul><li>View-dependent ok for fully dynamic scenes with moving viewer </li></ul></ul></ul><ul><ul><li>Object Space </li></ul></ul><ul><ul><ul><li>Need to transform light sources to this space (done by most CPU approaches) </li></ul></ul></ul>
  14. 14. Transform to world/eye space <ul><li>Unique identifier per vertex </li></ul><ul><li>Transform each vertex to world/eye space </li></ul><ul><ul><li>render mesh as points </li></ul></ul><ul><li>Store position at index slot </li></ul>P 0 P 1 P 2 P 3 P 4 position texture P 0 P 1 P 2 P 3 P 4 P N
  15. 15. Transform to world/eye space <ul><li>Vertex program for transform / index store </li></ul><ul><ul><li>Simple for standard modelview transformation </li></ul></ul><ul><ul><li>More complex programs modified by simple source-to-source code transformation </li></ul></ul><ul><ul><ul><li>Eliminate code relevant for additional attributes (color, texcoords, etc.) </li></ul></ul></ul><ul><ul><ul><li>Replace output position register by attribute register result.position -> result.texcoord[0] </li></ul></ul></ul><ul><ul><ul><li>Add code to move vertex index to output position MOV result.position, vertex.texcoord[..]; </li></ul></ul></ul>!!ARBvp1.0 ATTRIB iVertexPos = vertex.position; ATTRIB iVertexIdx = vertex.texcoord[0]; PARAM mv[4] = { state.matrix.modelview }; OUTPUT oPos = result.position; OUTPUT oDumpPos = result.texcoord[0]; # Transform the vertex to eye coordinates . DP4 oDumpPos.x, mv[0], iVertexPos; DP4 oDumpPos.y, mv[1], iVertexPos; DP4 oDumpPos.z, mv[2], iVertexPos; DP4 oDumpPos.w, mv[3], iVertexPos; # Vertex position is its index (x,y,0,1) MOV oPos, iVertexIdx; END
  16. 16. Transform to world/eye space <ul><li>Storing the result </li></ul><ul><ul><li>Need full floating point precission </li></ul></ul><ul><ul><ul><li>RGBA float textures (RGBA = x,y,z,w) </li></ul></ul></ul><ul><ul><li>One global texture to store all positions </li></ul></ul><ul><ul><ul><li>Index numbering is pre-processing step </li></ul></ul></ul><ul><ul><ul><li>Multiple instances of the same object need separate index slots (use index offset) </li></ul></ul></ul><ul><ul><ul><li>Use per-object culling (in light view) to reduce number of vertices </li></ul></ul></ul><ul><ul><ul><li>Mapping indices to 2D (idx % width, idx / width) overcomes texture size limitation </li></ul></ul></ul><ul><ul><ul><ul><li>1D: 2048 vertices </li></ul></ul></ul></ul><ul><ul><ul><ul><li>2D: over 4M vertices ! (max 2D texture size 2048x2048) </li></ul></ul></ul></ul>
  17. 17. Process edges <ul><li>Mesh connectivity is known </li></ul><ul><ul><li>Computed in pre-processing step </li></ul></ul><ul><ul><li>Each edge has unique identifier (index) </li></ul></ul><ul><li>Two vertices for the edge </li></ul><ul><li>Two vertices for adjacent triangles </li></ul>
  18. 18. Process edges <ul><li>Render point for each edge </li></ul><ul><ul><li>Edge index defines output position </li></ul></ul><ul><ul><li>Assign four vertex indices as attributes </li></ul></ul>E 0_idx P 0_idx P 1_idx P 3_idx P 4_idx glBegin(GL_POINTS) ; glAttrib(P0_idx, P3_idx, P1_idx, P4_idx); glVertex1f(E0_idx); glEnd();
  19. 19. Process Edges <ul><li>Vertex shader </li></ul><ul><ul><li>Not needed during this stage (pass-through all attributes) </li></ul></ul><ul><li>Fragment shader </li></ul><ul><ul><li>Used to compute silhouette flag </li></ul></ul><ul><ul><li>Position of light sources as global parameters </li></ul></ul><ul><ul><li>Use position texture of previous pass </li></ul></ul>
  20. 20. Process edges <ul><li>Fragment shader </li></ul>E 0_idx P 0_idx P 1_idx P 3_idx P 4_idx input data 4 texture lookups for world space positions P 0 P 1 P 3 P 4 registers P 3 P 0 P 1 P 4 N 1 = (P 3 –P 0 )x(P 1 –P 0 ) N 2 = (P 4 –P 0 )x(P 3 –P 0 ) front & back facing ? position texture P 0 P 1 P 2 P 3 P 4 Light Store silhouette flag (yes/no) at edge index E 0 E 1 E 2 E 3 E 4 E M edge texture
  21. 21. Silhouette Detection <ul><li>What we’ve got so far </li></ul><ul><ul><li>One texture holding all world/eye space position (w*h = #vertices) </li></ul></ul><ul><ul><li>One texture holding all silhouette flags for the edges (w*h = #edges) </li></ul></ul><ul><ul><ul><li>There’s also an additional flag (bit) for the vertex ordering (please see paper for details) </li></ul></ul></ul><ul><li>Next step </li></ul><ul><ul><li>Use this information to extrude & render shadow volumes </li></ul></ul>
  22. 22. Rendering Shadow Volumes <ul><li>Basic algorithm </li></ul>for all lights { for all edges { if (is silhouette edge for light i) { get edge’s vertices render extruded quad } } }
  23. 23. Rendering shadow volumes <ul><li>Vertex shader & tex lookup </li></ul><ul><ul><li>Best solution, but not (yet) supported </li></ul></ul><ul><li>Read back textures </li></ul><ul><ul><li>Trivial solution, but not very fast </li></ul></ul>position texture P 0 P 1 P 2 P 3 P 4 P N E 0 E 1 E 2 E 3 E 4 E M edge texture glBegin(GL_QUADS) ; glVertex(P0_idx, E0_idx, 0); glVertex(P1_idx, E0_idx, 0); glVertex(P1_idx, E0_idx, 1); glVertex(P0_idx, E0_idx, 1); P = Lookup (p_idx) mask = Lookup (e_idx) if (mask & silhouette) { if (extrude) // 0 or 1 flag out = P – Light_pos else out = P } else { out = (0,0,0,1) // outside view }
  24. 24. Rendering shadow volumes <ul><li>Better: keep all data on the card ! </li></ul><ul><li>Instead of storing edge flags, store all quad information </li></ul>E 0 = silhouette quad texture E` 0 = silhouette & extrude P 0 L P 3 P 0- L P 3- L Q 0 Q 1 Q 2 Q 3 Q 0 = (P 0x ,P 0y ,P 0z , E 0 ) Q 1 = (P 3x ,P 3y ,P 3z , E 0 ) Q 2 = (P 3x ,P 3y ,P 3z , E` 0 ) Q 3 = (P 0x ,P 0y ,P 0z , E` 0 )
  25. 25. Rendering Shadow Volumes <ul><li>Quad texture </li></ul><ul><ul><li>Instead of rendering one point per edge, render 4 points (line, 2x2 point) </li></ul></ul><ul><ul><li>XYZ-components used for world space position (edge vertices) </li></ul></ul><ul><ul><li>W-component for silhouette/extrude flag </li></ul></ul><ul><ul><ul><li>Can be used as bitmask (number of lights) </li></ul></ul></ul>Light0: Silhouette Light0: Extrude Light1: Silhouette Light1: Extrude
  26. 26. Rendering Shadow Volumes <ul><li>Quad texture used as vertex array </li></ul>Vertex Array: glBegin(GL_QUADS) ; glArrayElement(0); glArrayElement(1); glArrayElement(2); glArrayElement(3); P_xyz = IN_xyz; E = IN_w; if(E & silhouette) { if(E & extrude) out = P-L; else out = P; } else { out = somewhere outside view } Q 0 Q 1 Q 2 Q 3
  27. 27. Rendering Shadow Volumes <ul><li>Problem: </li></ul><ul><ul><li>Information stored as texture image </li></ul></ul><ul><ul><li>Need information in vertex path </li></ul></ul><ul><li>Solution: </li></ul><ul><ul><li>New OpenGL extension ARB_superbuffers allows more generic memory objects </li></ul></ul>
  28. 28. ARB_superbuffers <ul><li>General purpose memory objects </li></ul><ul><li>Use the same memory object in different parts of the pipeline </li></ul><ul><ul><li>as a texture </li></ul></ul><ul><ul><li>as a vertex array </li></ul></ul><ul><ul><li>as a render target </li></ul></ul>glVertexArrayMem ( GL_VERTEX_ARRAY, 4, mem, 0); memory block glAttachMem ( GL_DRAW_FRAMEBUFFER, GL_AUX0, mem); glAttachMem ( GL_TEXTURE_2D, GL_IMAGES, mem); glAllocMem2D (fmt, w, h, …)
  29. 29. ARB_superbuffers <ul><li>In our application </li></ul><ul><ul><li>Create memory object for quad texture (width*height = 4 * #edges) </li></ul></ul><ul><ul><li>During edge processing, use memory object as render target </li></ul></ul><ul><ul><li>During shadow volume rendering, use memory object as vertex array </li></ul></ul><ul><li>Very fast, since objects are used by reference (no data is copied) </li></ul>
  30. 30. Summary <ul><li>Silhouette Algorithm </li></ul><ul><ul><li>Pre-process meshes </li></ul></ul><ul><ul><ul><li>Number all vertices (#V) </li></ul></ul></ul><ul><ul><ul><li>Number all edges (#E) </li></ul></ul></ul><ul><ul><ul><li>Several instances of the same object need edge/vertex offsets </li></ul></ul></ul><ul><ul><li>Compute position texture </li></ul></ul><ul><ul><ul><li>Render one point per vertex </li></ul></ul></ul><ul><ul><ul><li>4-component float texture for #V vertices </li></ul></ul></ul><ul><ul><li>Compute quad texture </li></ul></ul><ul><ul><ul><li>4 pixels for each edge </li></ul></ul></ul><ul><ul><ul><li>check front/back facing condition for a number of lights (fragment shader) </li></ul></ul></ul><ul><ul><ul><li>4-component float texture for #E * 4 entries </li></ul></ul></ul>
  31. 31. Summary <ul><li>Silhouette Algorithm (cont.) </li></ul><ul><ul><li>Assign quad texture as vertex array </li></ul></ul><ul><ul><ul><li>ARB_superbuffer </li></ul></ul></ul><ul><ul><li>Render shadow volumes (for each light) </li></ul></ul><ul><ul><ul><li>Send down #E quads (#E * 4 array indices) </li></ul></ul></ul><ul><ul><ul><li>Vertex shader checks silhouette/extrude case If silhouette flag is false, move quad’s vertices way outside of view frustum (early clip) Otherwise, pass through vertices if extrude flag is false, or extrude vertices to infinity </li></ul></ul></ul>
  32. 32. Summary <ul><li>Execution of different stages </li></ul><ul><ul><li>Position texture needs to be computed when objects change </li></ul></ul><ul><ul><li>Quad texture needs to be re-computed when light position or objects change </li></ul></ul><ul><li>Selective update </li></ul><ul><ul><li>E.g. only recompute position for those objects that changed, no need to redo the complete texture </li></ul></ul>
  33. 33. Results
  34. 34. Conclusions <ul><li>Silhouette detection in hardware </li></ul><ul><ul><li>No frame-to-frame work for CPU </li></ul></ul><ul><ul><ul><li>All dynamic data remains on the graphics card ! </li></ul></ul></ul><ul><ul><li>Works with custom vertex shaders </li></ul></ul><ul><ul><ul><li>Deformation is no longer a problem </li></ul></ul></ul><ul><ul><li>Processes a number of light sources in parallel (flag bitmask) </li></ul></ul><ul><ul><li>Full hardware shadow volumes implementation </li></ul></ul><ul><ul><ul><li>More CPU resources for non-graphics work </li></ul></ul></ul><ul><ul><ul><li>No graphics / CPU sync requiered </li></ul></ul></ul>
  35. 35. Future Work <ul><li>Shadow volume fill-rate problem </li></ul><ul><ul><li>Optimizations during edge processing </li></ul></ul><ul><ul><ul><li>Intersect with large occluder polygons (walls, floor, etc.) </li></ul></ul></ul><ul><li>Reduce geometry work </li></ul><ul><ul><li>Work with connected primitives (quad strips) </li></ul></ul><ul><li>More general input geometry </li></ul><ul><ul><li>Meshes with open edges ? </li></ul></ul><ul><li>Other applications </li></ul><ul><ul><li>non-photorealistic rendering </li></ul></ul>
  36. 36. Thank you !