Sign in to follow this  
RPTD

Shadow Volume Flickering

Recommended Posts

i've implemented the shadow volume algorithme after the good tutorial on gamasutra. now my problem is that while the algorithme works well on distance i get disturbing results if getting close to a model. if i am at medium distance the shadow is correct. if i get closer to the model the shadows start to 'fade' away or 'pop' up on the model. it looks to me like the z-buffer values used during shadowing and rendering are not the same. for rendering the shadow volume and rendering i use an infinite matrix using this:
decMatrix decMatrix::CreateProjectionInfinite(int width, int height, float fov, float fovRatio, float znear){
	if( width<1 || height<1 || fov<=0 || fov>=PI || fovRatio==0 ) THROW(dueInvalidParam);
	decMatrix m;
	float a = (float)width / (float)height;
	float fx = 1.0f / tan(fov * 0.5f);
	float fy = a / tan(fov * fovRatio * 0.5f);
	float e = 0.0001f;
	m.a11=fx; m.a12=0;  m.a13=0;   m.a14=0;
	m.a21=0;  m.a22=fy; m.a23=0;   m.a24=0;
	m.a31=0;  m.a32=0;  m.a33=1-e; m.a34=znear*(e-2);
	m.a41=0;  m.a42=0;  m.a43=1;   m.a44=0;
	return m;
}
multiplied with a small translation matrix (translate z around 0.0001) to avoid z-fighting. how can it happen that getting close to objects in my scene (funny not all of them) show this strange behaviour? is the z-offset not good? or is the matrix not fully correct?

Share this post


Link to post
Share on other sites
Quote:
Original post by RPTD
multiplied with a small translation matrix (translate z around 0.0001) to avoid z-fighting.


Excuse me, but why do you think that any z-fighting will occur in this case? Do you render different geometry/apply different vertex shaders when you are doing the second pass?

Share this post


Link to post
Share on other sites
You shouldn't need the translation matrix. Just render each geometry pass with the same exact vertices and use LEQUAL as your depth function, and you should be fine.

Which API are you using, OpenGL or DirectX? I think your infinite projection matrix may need an adjustment, but it depends on the API. (The matrix in the gamasutra article is correct for OpenGL.)

-- Eric Lengyel

Share this post


Link to post
Share on other sites
Quote:
Original post by Generic Guest
Quote:
Original post by RPTD
multiplied with a small translation matrix (translate z around 0.0001) to avoid z-fighting.


Excuse me, but why do you think that any z-fighting will occur in this case? Do you render different geometry/apply different vertex shaders when you are doing the second pass?

i'm using this anti-z-flickering as if i am not using it all shadows on surfaces are flickering like hell. with that small fix i got all shadows working except this case with the model very close to the camera.

Share this post


Link to post
Share on other sites
Quote:
Original post by Eric Lengyel
You shouldn't need the translation matrix. Just render each geometry pass with the same exact vertices and use LEQUAL as your depth function, and you should be fine.

Which API are you using, OpenGL or DirectX? I think your infinite projection matrix may need an adjustment, but it depends on the API. (The matrix in the gamasutra article is correct for OpenGL.)

-- Eric Lengyel

i'm using opengl on linux on a ati radeon. and my matrix implementation inside my engine is a directx-like matrix which i convert to opengl format upon setting it (special render module system to separate engine and os).

about the LEQUAL, i'm using this before shadowing.
			// setup stuff for shadow rendering
OGL_CHECK( glClear(GL_STENCIL_BUFFER_BIT) );
OGL_CHECK( glEnable(GL_STENCIL_TEST) );
OGL_CHECK( glStencilFunc(GL_ALWAYS, 0, ~0) );
OGL_CHECK( glEnable(GL_DEPTH_TEST) );
OGL_CHECK( glDepthFunc(GL_LESS) );
OGL_CHECK( glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) );
OGL_CHECK( glDepthMask(GL_FALSE) );
pSetMatrix( GL_PROJECTION, zSafeProjMat );



this is what i took out of the gamasutra article unless i understood something wrong there.

shadowing itself i do like this (i think this should be correct):
void deoglShadowVolume::RenderShadows(deGraphicOpenGl *ogl, deoglMeshData *mesh, bool renderCaps){
// first pass
if(renderCaps){
OGL_CHECK( glCullFace(GL_FRONT) );
OGL_CHECK( glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP) );
}else{
OGL_CHECK( glCullFace(GL_BACK) );
OGL_CHECK( glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT) );
}
pRenderShadowPass(mesh, renderCaps);
// second pass
if(renderCaps){
OGL_CHECK( glCullFace(GL_BACK) );
OGL_CHECK( glStencilOp(GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP) );
}else{
OGL_CHECK( glCullFace(GL_FRONT) );
OGL_CHECK( glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT) );
}
pRenderShadowPass(mesh, renderCaps);
}

Share this post


Link to post
Share on other sites
using LEQUAL and leaving out the anti-z-fight matrix yields z-fighting, like seen here:


can it be that the matrix is wrong? i see nothing wrong there though.

Share this post


Link to post
Share on other sites
i managed to narrow down the problem. it is not the perspective matrix. if rendering Depth-pass without caps i have no flickering, if i render all in Depth-fail with caps though it flickers like hell.

altering the 'e' value in the matrix i posted doesn't solve the problem hence i don't think the far clipping plane is the bad guy. i assume it is the near clipping plane but from my current understanding of this technic i don't get how this can be a problem with Depth-fail. somebody can give me some pointers or knows what problem i have run into?

Share this post


Link to post
Share on other sites
The blockiness in your image has driver bug written all over it.

For the caps, are you sure that the vertex program is producing the exact same vertex positions that are used in the shadow extrusion and the mesh itself? Can you post your vertex programs/shaders for the extrusion and caps?

Also, this is a long shot, but you wouldn't happen to have GL_POINT_SPRITE_ARB or GL_VERTEX_PROGRAM_POINT_SIZE_ARB enabled? I've noticed similar blockiness problems on ATI hardware in the past with these enabled (even though they have nothing to do with what you're rendering).

Share this post


Link to post
Share on other sites
about the caps i don't get exactly what you are refering too, but it should always use the same vertices.

this vertex-program is used to project the shadow volume:
!!ARBvp1.0

#
# OpenGL Graphic Module Vertex Program
#
# Copyright (C) 2004, Plüss Roland ( rptd@gmx.net )
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#



# input data
##############
ATTRIB inPos = vertex.position; # position object space

# output data
###############
OUTPUT outHPos = result.position; # homogenous position

# constants
#############
# eye
PARAM pEyePos = program.local[0]; # eye position in object space
# light
PARAM pLightPos = program.local[1]; # object space
PARAM pLightDir = program.local[2]; # object space
PARAM pLightColor = program.local[3];
PARAM pLightOptions = program.local[4]; # type, power, cutoff, spotexp

# opengl states
#################
PARAM pMatMVP[4] = { state.matrix.mvp };

# variables
#############
TEMP t1;



# transform the vertex with the matrix
## t1 = inPos.w * pLightPos + (inPos - pLightPos, 0)
ADD t1.xyz, inPos, -pLightPos;
MOV t1.w, 0;
MAD t1, pLightPos, inPos.w, t1;
## outHPos = oglMatProj * (oglMatMdl * inPos);
DP4 outHPos.x, t1, pMatMVP[0];
DP4 outHPos.y, t1, pMatMVP[1];
DP4 outHPos.z, t1, pMatMVP[2];
DP4 outHPos.w, t1, pMatMVP[3];



# end of program
# 4 instructions
# 1 temp registers
END




this one used for the mesh (it's the ambient shader but the light shaders are all the same except some additional parameters calculated):

!!ARBvp1.0

#
# OpenGL Graphic Module Vertex Program
#
# Copyright (C) 2004, Plüss Roland ( rptd@gmx.net )
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#



# input data
##############
ATTRIB inPos = vertex.position; # position object space
ATTRIB inColor = vertex.color.primary; # ambient + emissive
ATTRIB inTexPos = vertex.texcoord[0]; # texture coordinates

# output data
###############
OUTPUT outHPos = result.position; # homogenous position
OUTPUT outColor = result.color.front.primary; # ambient + emissive
OUTPUT outTexPos = result.texcoord[0]; # texture coordinates

# constants
#############

# opengl states
#################
PARAM pMatTex1[4] = { state.matrix.texture[0] };
PARAM pMatMVP[4] = { state.matrix.mvp };

# variables
#############



# calculate texture coordinates
## outTexPos = oglMatTex1 * inTexPos
DPH outTexPos.x, inTexPos, pMatTex1[0];
DPH outTexPos.y, inTexPos, pMatTex1[1];

# color is ambient + emissive
## outColor = ambient + emissive;
MOV outColor, inColor;

# transform the vertex with the matrix
## outHPos = oglMatProj * (oglMatMdl * inPos);
DPH outHPos.x, inPos, pMatMVP[0];
DPH outHPos.y, inPos, pMatMVP[1];
DPH outHPos.z, inPos, pMatMVP[2];
DPH outHPos.w, inPos, pMatMVP[3];



# end of program
# 7 instructions
# 0 temp registers
END



about the extensions i'm not using them but it may be well the driver as i have also witnessed once texture-compression bugs where the driver compressed textures which he should not without asking me.

Share this post


Link to post
Share on other sites
Try changing your extrusion code to the following:


# transform the vertex with the matrix
## t1.xyz = (inPos.w < 0.5) ? inPos - pLightPos : inPos;
## t1.w = inPos.w;
SLT t1.w, inPos.w, 0.5;
MAD t1.xyz, pLightPos, -t1.w, inPos;
MOV t1.w, inPos.w;
## outHPos = oglMatProj * (oglMatMdl * inPos);
DP4 outHPos.x, t1, pMatMVP[0];
DP4 outHPos.y, t1, pMatMVP[1];
DP4 outHPos.z, t1, pMatMVP[2];
DP4 outHPos.w, t1, pMatMVP[3];



I've found that some processors with lower floating-point precision can cause problems when you try to do a + b - a, as I suggested in the gamasutra article. (At the time, it worked fine on all available GPUs, but on some newer GPUs you don't necessarily get exactly b back.) The above code is guaranteed to preserve your vertex position if its w component is 1.

Share this post


Link to post
Share on other sites
i'll try this one out once. one question though: what is SLT doing? don't remeber this command somehow.

Share this post


Link to post
Share on other sites
i tried out your suggestion and received a strange result. on components (models made with a 3d app) do work with this and procude no more flickering. terrain patches though (single sided, non closed, grid-like patch) does still flicker like hell. now this makes no sense as no matter which of both i use both end up as a triangle-list which is then shadow-rendered (hence it should be the same for both).

*scratch head*... anyways... it is a beginning (50% works now *grin*). one problem though still stays. if i get very close to a model surface the shadow gets wrong, even without the z-fight-matrix applied. can you look once more at the matrix and the shaders? i see no reason why very near to the camera-plane this effect happens. if the model moves roughly 10m away from you the effect vanishes. seen something like this?

Share this post


Link to post
Share on other sites
Quote:

one question though: what is SLT doing?


That's Set if Less Than -- it returns (ra < rb) ? 1.0 : 0.0.

Quote:

can you look once more at the matrix and the shaders?


I just noticed that the (3,3) and (4,3) entries of your projection matrix are negated (they should be e-1 and -1). Was there a reason for that? OpenGL won't be too happy without m.a43 = -1. It could be the source of your problems.

Share this post


Link to post
Share on other sites
the negation has a reason. my coordinate system has x towards right, y towards up and z into the screen. to get the matrices from my coordinate system to work with opengl i multiplied in a scale matrix with (1,1,-1). that's where the negation comes from.

i already played around with the e-1 value in the matrix but no matter if with or without minus it did not get rid of the effect. it's also not a one-machine problem. i have the same problem on both my machines, one with Radeon 9700 and one with Radeon 9600. no nvidia box around with shader support to test.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this