Jump to content


Problem with stencil volume shadows


7 replies to this topic

#1 draculr

    New Member

  • Members
  • Pip
  • 7 posts

Posted 06 July 2005 - 03:18 AM

Hi I have created my shadow volume and am having trouble getting my shadows out correctly.

I have checked that all my normals are correct on the shadow volume so I do not think that is the problem. Here are some images demonstrating the issue:

Posted Image
Here it looks fine


Posted Image
Here when I move the camera it screws up


I do not understand why it is not working, I am trying the Zpass method and have capped my shadow volume from where the object is. Everything from the objects to the lights are in world space.

These are the calls I am using:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);	// Clear the Screen the Depth Buffer and the Stencil Buffer
glLoadIdentity();

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
glDepthMask(GL_TRUE);

RenderUnlitScene(); // with ambient only

glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x0, 0xffff);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
glDepthMask(GL_FALSE);

glEnable(GL_CULL_FACE);

for each contour edge
{
 glCullFace(GL_BACK);
 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
 BuildBackfaceShadowPolygon();
 glCullFace(GL_FRONT);
 glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
 BuildBackfaceShadowPolygon();
 glCullFace(GL_BACK);
}

glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
glDepthFunc(GL_LEQUAL);
glStencilFunc(GL_EQUAL,0,~0);
glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
glDepthMask(GL_TRUE);

RenderScene(); // with lighting



So when I render my shadow volumes with normals they are all facing outward, but this thing just doesnt want to work. Anything I am doing wrong with the opengl calls??

#2 draculr

    New Member

  • Members
  • Pip
  • 7 posts

Posted 06 July 2005 - 03:21 AM

If you cannot see those images:

http://imagestore.ugbox.net/image/d8b98074...e9cc2f1a2f3.jpg

http://imagestore.ugbox.net/image/2e46a66f...360dae31aa2.jpg

#3 Reedbeta

    DevMaster Staff

  • Administrators
  • 4782 posts
  • LocationBellevue, WA

Posted 06 July 2005 - 06:50 PM

Your code looks fine to me. Could we see the source for BuildBackfaceShadowPolygon()?

I assume the yellow dot in the second image is the light?
reedbeta.com - developer blog, OpenGL demos, and other projects

#4 draculr

    New Member

  • Members
  • Pip
  • 7 posts

Posted 06 July 2005 - 11:00 PM

Reedbeta said:

Your code looks fine to me. Could we see the source for BuildBackfaceShadowPolygon()?

I assume the yellow dot in the second image is the light?

View Post


The yellow dot is the position of a light which has shadows turned off.

I simplified the BuildBackfaceShadowPolygon() in the sample code purposely since it is quite complex, it actually calls: CreateContourList();

Code is at bottom (quite a bit of code).

Now the funny thing is that my shadow volumes are ALWAYS correct. No matter what object or where my camera is it is always good and no faces on the shadow volume duplicate themselves. That is when I render my shadow volume as a actual object and display the normals. All the normals are outward, there are no cracks in my volume, and the backfaces of the polygon are capping the volume correctly.

However, when I render my volume to the stencil buffer, there are times when it is correct, then there are times when it does not seems to decrement the buffer.

If i place one plane above another, and a stationary light positioned above it, when I 'circle strafe' around the objects half the circle it works, the other half you can see the volume being rendered.


void CShadow::CreateContourList(std::vector<CMesh> &pengineObjects, CVector3 lightPosition, int lightNumber)
{
	glEnable(GL_STENCIL_TEST);
	glStencilFunc(GL_ALWAYS, 0x0, 0xffff);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);

	glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
	glDepthMask(GL_FALSE);

	glEnable(GL_CULL_FACE);

	// Go through each mesh object
	for (unsigned int mesh = 0; mesh < pengineObjects.size(); mesh++)
	{
 // Go through each face group
 for (int faceGroup = 0; faceGroup < pengineObjects[mesh].NbFacesGroups; faceGroup++)
 {
 	for (int face = 0; face < pengineObjects[mesh].Groups[faceGroup].NbFaces; face++)
 	{
  CVector3 vertexA = pengineObjects[mesh].Vertices[pengineObjects[mesh].Groups[faceGroup].Vertices_Index[(face*3)]];
  CVector3 vertexB = pengineObjects[mesh].Vertices[pengineObjects[mesh].Groups[faceGroup].Vertices_Index[(face*3)+1]];
  CVector3 vertexC = pengineObjects[mesh].Vertices[pengineObjects[mesh].Groups[faceGroup].Vertices_Index[(face*3)+2]];

  CVector3 normalA = pengineObjects[mesh].Normals[pengineObjects[mesh].Groups[faceGroup].Normals_Index[(face*3)]];
  CVector3 normalB = pengineObjects[mesh].Normals[pengineObjects[mesh].Groups[faceGroup].Normals_Index[(face*3)+1]];
  CVector3 normalC = pengineObjects[mesh].Normals[pengineObjects[mesh].Groups[faceGroup].Normals_Index[(face*3)+2]];

  CVector3 faceAverage = (vertexA + vertexB + vertexC) / 3;
  CVector3 faceNormal = (normalA + normalB + normalC) / 3;
  faceNormal = Normalize(faceNormal);

  CVector3 IncidentLightDir = faceAverage - lightPosition;

  float dot = Dot(IncidentLightDir, faceNormal);

  if (dot >= 0.0)
  {
  	glCullFace(GL_BACK);
  	glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
  	BuildBackfaceShadowPolygon(pengineObjects, mesh, faceGroup, face, 1);
  	glCullFace(GL_FRONT);
  	glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
  	BuildBackfaceShadowPolygon(pengineObjects, mesh, faceGroup, face, 1);
  	glCullFace(GL_BACK);
  }
 	}
 }

 
 // Make all contour edges extend to become the shadow volume
 for (unsigned int edge = 0; edge < pengineObjects[mesh].Edges.size()-1; edge++)
 {
 	CVector3 vertexA, vertexB;

 	// Get relevant data
 	CVector3 faceAVertexA = pengineObjects[mesh].Edges[edge].vertexA;
 	CVector3 faceAVertexB = pengineObjects[mesh].Edges[edge].vertexB;

 	CVector3 faceAAverage = pengineObjects[mesh].Edges[edge].faceAAverage;

 	CVector3 faceANormal = Normalize(pengineObjects[mesh].Edges[edge].faceANormal);


 	if (pengineObjects[mesh].Edges[edge].numConnectedFaces == 2)
 	{
  // Get relevant data
  CVector3 faceBVertexA = pengineObjects[mesh].Edges[edge].vertexB;
  CVector3 faceBVertexB = pengineObjects[mesh].Edges[edge].vertex2B;

  CVector3 faceBAverage = pengineObjects[mesh].Edges[edge].faceBAverage;

  CVector3 faceBNormal = Normalize(pengineObjects[mesh].Edges[edge].faceBNormal);

  // Get light direction
  CVector3 IncidentLightDirA = faceAAverage - lightPosition;
  IncidentLightDirA = Normalize(IncidentLightDirA);
  CVector3 IncidentLightDirB = faceBAverage - lightPosition;
  IncidentLightDirB = Normalize(IncidentLightDirB);

  float dot1 = Dot(IncidentLightDirA, faceANormal);
  float dot2 = Dot(IncidentLightDirB, faceBNormal);
  
  //glFrontFace(GL_CCW);
  if (dot1 >= 0 && dot2 < 0)
  {
  	vertexA = faceAVertexA;
  	vertexB = faceAVertexB;
  }
  else if (dot2 >= 0 && dot1 < 0)
  {
  	vertexA = faceAVertexB;
  	vertexB = faceAVertexA;
  }
 	}
 	else
 	{
  // Get light direction
  CVector3 IncidentLightDir = faceAAverage - lightPosition;
  IncidentLightDir = Normalize(IncidentLightDir);

  float dot = Dot(IncidentLightDir, faceANormal);

  if (dot >= 0.0)
  {
  	vertexA = faceAVertexA;
  	vertexB = faceAVertexB;
  }
  else
  {
  	vertexA = faceAVertexB;
  	vertexB = faceAVertexA;
  }
 	}

 	glCullFace(GL_BACK);
 	glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
 	BuildShadowPolygon(pengineObjects, lightPosition, mesh, edge, vertexA, vertexB, 1);

 	glCullFace(GL_FRONT);
 	glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
 	BuildShadowPolygon(pengineObjects, lightPosition, mesh, edge, vertexA, vertexB, 1);

 	glCullFace(GL_BACK);
 }
	}
}

void CShadow::BuildShadowPolygon(std::vector<CMesh> &pengineObjects, CVector3 lightPosition, int mesh, int edge, CVector3 vertexA, CVector3 vertexB, bool drawNormal)
{
	CVector3 vertex1, vertex2, vertex3, vertex4;
	vertex1 = vertexA;
	vertex2 = vertexB;
	vertex3 = vertexB + 0.5 * (vertexB - lightPosition);
	vertex4 = vertexA + 0.5 * (vertexA - lightPosition);

	glColor3f (1,0,0);

	glBegin(GL_QUADS);
	glVertex3f(vertex1.x, vertex1.y, vertex1.z);
	glVertex3f(vertex2.x, vertex2.y, vertex2.z);
	glVertex3f(vertex3.x, vertex3.y, vertex3.z);
	glVertex3f(vertex4.x, vertex4.y, vertex4.z);
	glEnd();
}

void CShadow::BuildBackfaceShadowPolygon(std::vector<CMesh> &pengineObjects, int mesh, int faceGroup, int face, bool drawNormal)
{
	glColor3f (1,0,0);

	CVector3 vertex1 = pengineObjects[mesh].Vertices[pengineObjects[mesh].Groups[faceGroup].Vertices_Index[(face*3)]];
	CVector3 vertex2 = pengineObjects[mesh].Vertices[pengineObjects[mesh].Groups[faceGroup].Vertices_Index[(face*3)+1]];
	CVector3 vertex3 = pengineObjects[mesh].Vertices[pengineObjects[mesh].Groups[faceGroup].Vertices_Index[(face*3)+2]];

	glBegin(GL_TRIANGLES);
	glVertex3f(vertex1.x, vertex1.y, vertex1.z);
	glVertex3f(vertex2.x, vertex2.y, vertex2.z);
	glVertex3f(vertex3.x, vertex3.y, vertex3.z);
	glEnd();
}



#5 draculr

    New Member

  • Members
  • Pip
  • 7 posts

Posted 06 July 2005 - 11:12 PM

Oh I seem to have fixed it...

I have to first render ALL the front faces and incr, THEN render ALL the back faces and decr...

Still seems to be some poping here and there on the very edges of some objects....but that should be fairly simple to fix.

Awesome.

#6 Reedbeta

    DevMaster Staff

  • Administrators
  • 4782 posts
  • LocationBellevue, WA

Posted 07 July 2005 - 02:45 AM

Oh...I assumed that's what you were already doing.

If you interleave increments and decrements, then you might try to decrement a value of 0 sometimes - this doesn't work, it just does nothing. That would account for why it seems not to be decrementing sometimes.

There is an extension, EXT_stencil_wrap I believe, that gives you increment-wrap and decrement-wrap operators. Combined with EXT_stencil_two_side, which allows separate stencil operations to be set for front-facing and back-facing triangles, allows you to render the shadow geometry only once, saving some vertex throughput.
reedbeta.com - developer blog, OpenGL demos, and other projects

#7 draculr

    New Member

  • Members
  • Pip
  • 7 posts

Posted 07 July 2005 - 04:29 AM

Reedbeta said:

Oh...I assumed that's what you were already doing.

If you interleave increments and decrements, then you might try to decrement a value of 0 sometimes - this doesn't work, it just does nothing. That would account for why it seems not to be decrementing sometimes.

There is an extension, EXT_stencil_wrap I believe, that gives you increment-wrap and decrement-wrap operators. Combined with EXT_stencil_two_side, which allows separate stencil operations to be set for front-facing and back-facing triangles, allows you to render the shadow geometry only once, saving some vertex throughput.

View Post


So the stencil buffer never goes into negative values then?

Thats what I thought it did and thats where my mistake was :)

#8 Reedbeta

    DevMaster Staff

  • Administrators
  • 4782 posts
  • LocationBellevue, WA

Posted 07 July 2005 - 05:32 AM

Nope, it's just basically an unsigned char per pixel. :)
reedbeta.com - developer blog, OpenGL demos, and other projects





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users