Shadows volumes: what's wrong ??!
it would be great if u post the implementation of that algorithm... i'm still trying to make my one work :P
Here's my implementation for shadow volumes. The code is not as clean as it should be but it works (or so it seems).
Please feel free to send feedback about it !
Header :
Implementation :
The interesting parts are the constructor and the draw method. The begin, end_shadow and end methods describe the "shadow volume flow and can be used as follow :
- draw the scene with ambient light
- for each light source
- ShadowVolume::begin()
- draw shadow volumes
- ShadowVolume::end_shadow()
- draw the scene with diffuse and specular lights
- ShadowVolume::end()
Note that the z-pass part is not finished yet.
Please feel free to send feedback about it !
Header :
class ShadowVolume { struct triangle_t { unsigned int vertex[3]; int edge[3]; }; struct edge_t { unsigned int vertex[2]; char value; bool operator <(const edge_t& e) const; edge_t& operator =(const edge_t& e); }; unsigned int m_nb_triangles; triangle_t* m_triangles; unsigned int m_nb_edges; edge_t* m_edges; static bool create_edge(edge_t& e, const unsigned int v1, const unsigned int v2); static void quick_sort(const edge_t* edges, unsigned int* indices, const unsigned int l, const unsigned int r); static void insertion_sort(const edge_t* edges, unsigned int* indices, const unsigned int l, const unsigned int r); static void sort_edges(const edge_t* edges, unsigned int* indices, const unsigned int l, const unsigned int r); public: ShadowVolume(const Triangle* tris, const unsigned int nb_tris); ~ShadowVolume(); void draw(Vector3* vertices) const; enum method_t { z_pass, z_fail }; static void begin(const method_t method = z_pass); static void end_shadow(); static void end(); };
Implementation :
The interesting parts are the constructor and the draw method. The begin, end_shadow and end methods describe the "shadow volume flow and can be used as follow :
- draw the scene with ambient light
- for each light source
- ShadowVolume::begin()
- draw shadow volumes
- ShadowVolume::end_shadow()
- draw the scene with diffuse and specular lights
- ShadowVolume::end()
Note that the z-pass part is not finished yet.
bool ShadowVolume::edge_t:: operator <(const edge_t& e) const { return ( (vertex[0] < e.vertex[0]) || (vertex[0] == e.vertex[0] && vertex[1] < e.vertex[1])); } ShadowVolume::edge_t& ShadowVolume::edge_t:: operator =(const edge_t& e) { vertex[0] = e.vertex[0]; vertex[1] = e.vertex[1]; value = 0; return *this; } bool ShadowVolume:: create_edge(edge_t& e, const unsigned int v1, const unsigned int v2) { if (v1 < v2) { e.vertex[0] = v1; e.vertex[1] = v2; return true; } else { e.vertex[0] = v2; e.vertex[1] = v1; return false; } } #define swap(i, j) { unsigned int tmp = indices; indices = indices[j]; indices[j] = tmp; } void ShadowVolume:: quick_sort(const edge_t* edges, unsigned int* indices, const unsigned int l, const unsigned int r) { unsigned short M = 4; unsigned short i, j; edge_t v; if (r-l > M) { i = (r+l)>>1; if (edges[indices] < edges[indices[l]]) swap(l, i); if (edges[indices[r]] < edges[indices[l]]) swap(l, r); if (edges[indices[r]] < edges[indices]) swap(i, r); j = r-1; swap(i, j); i = l; v = edges[indices[j]]; for (;;) { while (edges[indices[++i]] < v); while (v < edges[indices[--j]]); if (j < i) break; swap(i, j); } swap(i, r-1); quick_sort(edges, indices, l, j); quick_sort(edges, indices, i+1, r); } } void ShadowVolume:: insertion_sort(const edge_t* edges, unsigned int* indices, const unsigned int l, const unsigned int r) { unsigned int i, j; unsigned int v; for (i = l+1; i <= r; ++i) { v = indices; j = i; while (j > l && edges[v] < edges[indices[j-1]]) { indices[j] = indices[j-1]; --j; } indices[j] = v; } } void ShadowVolume:: sort_edges(const edge_t* edges, unsigned int* indices, const unsigned int l, const unsigned int r) { quick_sort(edges, indices, l, r); insertion_sort(edges, indices, l, r); } #undef swap ShadowVolume:: ShadowVolume(const Triangle* tris, const unsigned int nb_tris) : m_nb_triangles(nb_tris), m_triangles(new triangle_t[nb_tris]) { unsigned int i, j; { // Copy triangle array... for (i = 0; i < nb_tris; ++i) { m_triangles.vertex[0] = tris.a; m_triangles.vertex[1] = tris.b; m_triangles.vertex[2] = tris.c; } } { // Create edge array... edge_t* edges = new edge_t[nb_tris*3]; for (i = 0; i < nb_tris; ++i) { triangle_t& t = m_triangles; if (create_edge(edges[i*3], t.vertex[0], t.vertex[1])) { t.edge[0] = i*3; } else { t.edge[0] = -i*3-1; } if (create_edge(edges[i*3+1], t.vertex[1], t.vertex[2])) { t.edge[1] = i*3+1; } else { t.edge[1] = -i*3-2; } if (create_edge(edges[i*3+2], t.vertex[2], t.vertex[0])) { t.edge[2] = i*3+2; } else { t.edge[2] = -i*3-3; } } // Sort edge array unsigned int* indices = new unsigned int[nb_tris*3]; for (i = 0; i < nb_tris*3; ++i) { indices = i; } sort_edges(edges, indices, 0, nb_tris*3-1); // Count unique edges m_nb_edges = 1; for (i = 1; i < nb_tris*3; ++i) { if (edges[indices[i-1]] < edges[indices]) { m_nb_edges++; } } m_edges = new edge_t[m_nb_edges]; unsigned int* new_indices = new unsigned int[nb_tris*3]; j = 0; m_edges[0] = edges[indices[0]]; new_indices[indices[0]] = 0; for (i = 1; i < nb_tris*3; ++i) { if (edges[indices[i-1]] < edges[indices]) { m_edges[++j] = edges[indices]; } new_indices[indices] = j; } delete [] edges; delete [] indices; for (i = 0; i < nb_tris; ++i) { triangle_t& t = m_triangles; for (j = 0; j < 3; ++j) { if (t.edge[j] >= 0) { t.edge[j] = new_indices[t.edge[j]]; } else { t.edge[j] = -1-new_indices[-1-t.edge[j]]; } } } delete [] new_indices; } } ShadowVolume:: ~ShadowVolume() { delete [] m_edges; delete [] m_triangles; } namespace { unsigned char status = 0; ShadowVolume::method_t current_method; } void ShadowVolume:: draw(Vector3* v) const { const float shadow_length = 400; Vector3 light_pos; unsigned int i; int j; assert(status == 1); { float tmp[4]; Matrix4x4 m(GL_MODELVIEW_MATRIX); glGetLightfv(GL_LIGHT0, GL_POSITION, tmp); light_pos.x = tmp[0]*tmp[3]; light_pos.y = tmp[1]*tmp[3]; light_pos.z = tmp[2]*tmp[3]; light_pos = (m.inverse())*light_pos; } if (current_method == z_fail) { glBegin(GL_TRIANGLES); for (i = 0; i < m_nb_triangles; ++i) { triangle_t& tri = m_triangles; Vector3 n = (v[tri.vertex[1]]-v[tri.vertex[0]])^(v[tri.vertex[2]]-v[tri.vertex[0]]); if (n*(light_pos-v[tri.vertex[0]]) < 0) { Vector3 p1 = v[tri.vertex[0]]+shadow_length*((v[tri.vertex[0]]-light_pos).norm()); Vector3 p2 = v[tri.vertex[1]]+shadow_length*((v[tri.vertex[1]]-light_pos).norm()); Vector3 p3 = v[tri.vertex[2]]+shadow_length*((v[tri.vertex[2]]-light_pos).norm()); glVertex3f(v[tri.vertex[0]].x, v[tri.vertex[0]].y, v[tri.vertex[0]].z); glVertex3f(v[tri.vertex[1]].x, v[tri.vertex[1]].y, v[tri.vertex[1]].z); glVertex3f(v[tri.vertex[2]].x, v[tri.vertex[2]].y, v[tri.vertex[2]].z); glVertex3f(p1.x, p1.y, p1.z); glVertex3f(p3.x, p3.y, p3.z); glVertex3f(p2.x, p2.y, p2.z); for (j = 0; j < 3; ++j) { if (tri.edge[j] >= 0) { m_edges[tri.edge[j]].value--; } else { m_edges[-1-tri.edge[j]].value++; } } } } glEnd(); } else { for (i = 0; i < m_nb_triangles; ++i) { triangle_t& tri = m_triangles; Vector3 n = (v[tri.vertex[1]]-v[tri.vertex[0]])^(v[tri.vertex[2]]-v[tri.vertex[0]]); if (n*(light_pos-v[tri.vertex[0]]) < 0) { for (j = 0; j < 3; ++j) { if (tri.edge[j] >= 0) { m_edges[tri.edge[j]].value--; } else { m_edges[-1-tri.edge[j]].value++; } } } } } glBegin(GL_QUADS); for (i = 0; i < m_nb_edges; ++i) { edge_t& e = m_edges; if (e.value != 0) { Vector3 p1 = v[e.vertex[0]]+shadow_length*((v[e.vertex[0]]-light_pos).norm()); Vector3 p2 = v[e.vertex[1]]+shadow_length*((v[e.vertex[1]]-light_pos).norm()); if (e.value > 0) { for (; e.value > 0; e.value--) { glVertex3f(v[e.vertex[0]].x, v[e.vertex[0]].y, v[e.vertex[0]].z); glVertex3f(v[e.vertex[1]].x, v[e.vertex[1]].y, v[e.vertex[1]].z); glVertex3f(p2.x, p2.y, p2.z); glVertex3f(p1.x, p1.y, p1.z); } } else { for (; e.value < 0; e.value++) { glVertex3f(v[e.vertex[0]].x, v[e.vertex[0]].y, v[e.vertex[0]].z); glVertex3f(p1.x, p1.y, p1.z); glVertex3f(p2.x, p2.y, p2.z); glVertex3f(v[e.vertex[1]].x, v[e.vertex[1]].y, v[e.vertex[1]].z); } } if (e.value != 0) printf("ca merde\n"); } } glEnd(); } namespace { bool dlist_defined = false; GLuint dlist; } void ShadowVolume:: begin(const method_t method) { ASSERT(status == 0); current_method = method; Texture::none().bind(); GfxProgram::none.bind(); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDepthFunc(GL_LESS); glDepthMask(GL_FALSE); glEnable(GL_STENCIL_TEST); glClear(GL_STENCIL_BUFFER_BIT); if ( OpenGL::has_stencil_two_side && OpenGL::has_stencil_wrap) { glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); glDisable(GL_CULL_FACE); glActiveStencilFaceEXT(GL_FRONT); glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); glStencilMask(~0); glStencilFunc(GL_ALWAYS, 0, ~0); glActiveStencilFaceEXT(GL_BACK); glStencilOp(GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP); glStencilMask(~0); glStencilFunc(GL_ALWAYS, 0, ~0); } else { if (!dlist_defined) { dlist = glGenLists(1); dlist_defined = true; } // Setup stencil for front faces. glStencilMask(~0); glStencilFunc(GL_ALWAYS, 0, ~0); if (current_method == z_pass) { glCullFace(GL_FRONT); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); } else { glCullFace(GL_BACK); glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); } // Start display list. glNewList(dlist, GL_COMPILE_AND_EXECUTE); } status = 1; } void ShadowVolume:: end_shadow() { ASSERT(status == 1); if ( OpenGL::has_stencil_two_side && OpenGL::has_stencil_wrap) { glEnable(GL_CULL_FACE); } else { // End display list. glEndList(); // Setup stencil for back faces. if (current_method == z_pass) { glCullFace(GL_BACK); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); } else { glCullFace(GL_FRONT); glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); } // Draw display list glCallList(dlist); glCullFace(GL_BACK); } glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glColor4f(1, 1, 1, 1); glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP); glStencilMask(~0); if (current_method == z_pass) { glStencilFunc(GL_EQUAL, 0, ~0); } else { glStencilFunc(GL_EQUAL, 0, ~0); } glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); status = 2; } void ShadowVolume:: end() { ASSERT(status == 1); glDisable(GL_BLEND); glDisable(GL_STENCIL_TEST); status = 0; }
SaM3d!, a cross-platform API for 3d based on SDL and OpenGL.The trouble is that things never get better, they just stay the same, only more so. -- (Terry Pratchett, Eric)
i've got many problems with your code... even i cannot make it compile :/
i know i'm probably asking you too much, but couldn't you post a small demo of sample usage, with source?
i know i'm probably asking you too much, but couldn't you post a small demo of sample usage, with source?
It's likely this code depends on other parts of the stuff I wrote. And it's also possible it won't compile under MSVC (I usually code under Linux and use gcc under Windows). Maybe I should take some time to port it...
Hmm I'll try to prepare something for you (but it will take time).
Hmm I'll try to prepare something for you (but it will take time).
SaM3d!, a cross-platform API for 3d based on SDL and OpenGL.The trouble is that things never get better, they just stay the same, only more so. -- (Terry Pratchett, Eric)
Quote:
You will probably want to read the following article: http://legion.gibbering.net/projectx/paper/paper.pdf
It describes an excellent algorithm that will work with *all* models.
BTW, the paper was written by RipTorn (forgot to mention it ; thanx RipTorn !).
cheers rodzilla [smile] awesome to know that the algorithm worked a charm - makes me feel all warm and fuzzy inside [wink]
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement