Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to realize z-fail algorithm in opengl?

I code as the NeHe tutors Lesson27 told me,but it's a z-pass algorithm.when i'm in the shadow,the shadow is gone.somebody told me I can use z-fail algorithm to solve this problem. so I spend two days to research z-fail algorithm.At last ,I can't figure it out.My program never run as what i think.

The z-fail algorithm as the wiki listed:

Depth fail Around the year 2000, several people discovered that Heidmann's method can be made to work for all camera positions by reversing the depth. Instead of counting the shadow surfaces in front of the object's surface, the surfaces behind it can be counted just as easily, with the same end result. This solves the problem of the eye being in shadow, since shadow volumes between the eye and the object are not counted, but introduces the condition that the rear end of the shadow volume must be capped, or shadows will end up missing where the volume points backward to infinity.

  1. Disable writes to the depth and color buffers.

  2. Use front-face culling.

  3. Set the stencil operation to increment on depth fail (only count shadows behind the object).

  4. Render the shadow volumes.

  5. Use back-face culling.

  6. Set the stencil operation to decrement on depth fail.

  7. Render the shadow volumes.

The Main question I think is the depth test. At step 3 and 6,the stencil operation is based on depth fail.Although it can show out the shadow,but it maybe shadowed on the object before it(i.e:the object which depth buffer value is less than it).so all the shadow effect looks mess.

But in z-pass algorithm,the stencil operation is based on depth pass,that means it not only can show out the shadow,but also shadowed only on the object behind it,that accords with eye system.

so how to solve this problem to make my depth fail algorithm show out the shadow on the right objects.

here is my z-fail algorithm code(somewhere may be where,please help me find out,the shadow effect is awful)

VECTOR vec;        
void shadowvolume(SECTOR &sec,float *lp)
{
    unsigned int    p1, p2;
    VECTOR          v1, v2;
    int i, j, k, jj;
    for (i=0; i<sec.numplanes;i++)
    {
        if (sec.planes[i].visible)
        {
            for (j=0;j<3;j++)
            {
                k = sec.planes[i].neigh[j];
                if ((!k) || (!sec.planes[k-1].visible))//如果以第k个点开始的邻边没有相邻平面或者相邻平面不可见
                {
                    // here we have an edge, we must draw a polygon
                    p1 = sec.planes[i].p[j]-1;//邻边的起点
                    jj = (j+1)%3;           
                    p2 = sec.planes[i].p[jj]-1;//邻边的终点

                    //calculate the length of the vector
                    v1.x = (sec.points[p1].vec.x - lp[0])*100;
                    v1.y = (sec.points[p1].vec.y - lp[1])*100;
                    v1.z = (sec.points[p1].vec.z - lp[2])*100;

                    v2.x = (sec.points[p2].vec.x - lp[0])*100;
                    v2.y = (sec.points[p2].vec.y - lp[1])*100;
                    v2.z = (sec.points[p2].vec.z - lp[2])*100;

                    glBegin(GL_TRIANGLE_STRIP);//将光源连到邻边的起点并延长,将光源连到邻边的终点的并延长,最后延长出来的梯形,画了过后模板缓冲区的值加1
                    glVertex3f(sec.points[p1].vec.x,sec.points[p1].vec.y,sec.points[p1].vec.z);
                    glVertex3f(sec.points[p1].vec.x + v1.x,sec.points[p1].vec.y + v1.y,sec.points[p1].vec.z + v1.z);
                    glVertex3f(sec.points[p2].vec.x,sec.points[p2].vec.y,sec.points[p2].vec.z);
                    glVertex3f(sec.points[p2].vec.x + v2.x,sec.points[p2].vec.y + v2.y,sec.points[p2].vec.z + v2.z);
                    glEnd();
                }
            }
            // caps
            glBegin(GL_TRIANGLES);  
            for(k=0;k<3;k++)
                glVertex3fv((float*)&sec.points[sec.planes[i].p[k]-1].vec);
            glEnd();
            glBegin(GL_TRIANGLES);  

            for(k=2;k>=0;k--)
            {
                vec.x=sec.points[sec.planes[i].p[k]-1].vec.x+(sec.points[sec.planes[i].p[k]-1].vec.x-lp[0])*100;
                vec.y=sec.points[sec.planes[i].p[k]-1].vec.y+(sec.points[sec.planes[i].p[k]-1].vec.y-lp[1])*100;
                vec.z=sec.points[sec.planes[i].p[k]-1].vec.z+(sec.points[sec.planes[i].p[k]-1].vec.z-lp[2])*100;
                glVertex3fv((float*)&vec);
            }
            glEnd();

        }
    }



}
void  CastShadow(SECTOR &sec, float *lp)
{//lp是光源相对于物体的位置
    float           side;

    glEnable(GL_CULL_FACE); 
    int i;
    for (i=0;i<sec.numplanes;i++)
    {
        side =sec.planes[i].planeeq.a*lp[0]+sec.planes[i].planeeq.b*lp[1]+sec.planes[i].planeeq.c*lp[2]+sec.planes[i].planeeq.d*lp[3];
        if (side>0) 
            sec.planes[i].visible = TRUE;
        else
            sec.planes[i].visible = FALSE;
    }

    glDisable(GL_LIGHTING);
    glDepthMask(GL_FALSE);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_STENCIL_TEST);
    glColorMask(0, 0, 0, 0);
    glStencilFunc(GL_ALWAYS, 0, 0xffffffff);

    glCullFace(GL_FRONT);
    glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
    //glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
    shadowvolume(sec,lp);

    glCullFace(GL_BACK);
    glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
    //glStencilOp(GL_KEEP,GL_KEEP,  GL_INCR);
    shadowvolume(sec,lp);



    glColorMask(1, 1, 1, 1);

    //draw a shadowing rectangle covering the entire screen
    glColor4f(0.0f, 0.0f, 0.0f,0.4f);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glStencilFunc(GL_NOTEQUAL, 0, 0xffffffff);
    //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
    glPushMatrix();
    glLoadIdentity();
    glBegin(GL_TRIANGLE_STRIP);
        glVertex3f(-0.1f, 0.1f,-0.0010f);
        glVertex3f(-0.1f,-0.1f,-0.0010f);
        glVertex3f( 0.1f, 0.1f,-0.0010f);
        glVertex3f( 0.1f,-0.1f,-0.0010f);
    glEnd();
    glPopMatrix();
    glDisable(GL_BLEND);

    glDepthFunc(GL_LEQUAL);
    glDepthMask(GL_TRUE);
    glEnable(GL_LIGHTING);
    glDisable(GL_STENCIL_TEST);
    glShadeModel(GL_SMOOTH);
    glDisable(GL_CULL_FACE);
}

the VECTOR class is like this:

class VECTOR
{
public:
    float x,y,z;
    bool operator==(VECTOR vec)
    {
        if(x==vec.x && y==vec.y && z==vec.z)
            return true;
        return false;
    }
};

the SECTOR class and others is like this:

class PLANEEQ
{
public:
    float a,b,c,d;
};
class PLANE
{
public:
    unsigned int p[3];//点的序号
    VECTOR normal[3];
    unsigned int neigh[3];//平面3个相依平面的序号
    PLANEEQ planeeq;
    bool visible;
    PLANE()
    {
        neigh[0]=0;
        neigh[1]=0;
        neigh[2]=0;
        planeeq.a=0;
        planeeq.b=0;
        planeeq.c=0;
        planeeq.d=0;
        visible=false;
    }
};

class SECTOR
{
public:
    int numpoints;
    int numplanes;
    vector<VERTEX> points;
    vector<PLANE> planes;
    MATERIAL material;
    bool read();
    bool loadtexture();
    bool build();
    bool plane_calc();
    void SetConnectivity();
    SECTOR& SECTOR::subdivide(long depth);
    SECTOR(string str1,string str2):modelfilename(str1),texturefilename(str2)
    {
        numpoints=0;
        numplanes=0;

    }
    SECTOR()
    {
        numpoints=0;
        numplanes=0;

    }

private:
    FILE *modelfilein,*texturefilein;
    string modelfilename,texturefilename;
    char oneline[255];
    UINT texturename;
    AUX_RGBImageRec *TextureImage;
};
class POSITION
{
public:
    float x,y,z,w;
};

the DrawGLScene function in my main.cpp is like this:

int DrawGLScene(GLvoid)                                 
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |GL_STENCIL_BUFFER_BIT);  
    glLoadIdentity();
    DrawGLRoom();
    glLoadIdentity();
    GLfloat xtrans = -xpos;
    GLfloat ztrans = -zpos;
    GLfloat ytrans = -ypos-1.2f;
    GLfloat sceneroty = 360.0f - yrot;  

    glRotatef(lookupdown,1.0f,0,0);
    glRotatef(sceneroty,0,1.0f,0);
    glTranslatef(xtrans, ytrans, ztrans);
    brick_sec.build();
    floor_sec.build();
    //wall_sec.build();

    //CastShadow(wall_sec,(float *)&lightgroup.lights[0].pos);
    CastShadow(brick_sec,(float*)&lightgroup.lights[0].pos);
    CastShadow(floor_sec,(float*)&lightgroup.lights[0].pos);    


    lightgroup.build(); 
    glColor4f(0.7f, 0.4f, 0.0f, 1.0f);  
    glDisable(GL_LIGHTING);                             
    glDepthMask(GL_FALSE);                              
    glTranslatef(lightgroup.lights[0].pos.x, lightgroup.lights[0].pos.y, lightgroup.lights[0].pos.z);               
    gluSphere(q, 0.2f, 16, 8);  
    glEnable(GL_LIGHTING);  
    glDepthMask(GL_TRUE);
    if(space_time>0)
    {
        ypos=sin(space_time*3.1415926/180);
        space_time-=4;
    }
    else
    {
        sp=false;
    }
    //glFlush();
    return TRUE;                                        // Everything Went OK
}

Since my reputation is under 10,I can't capture the shadow effect to show u how badly it looks like! pls help me,I would thx u for ur attention and ur time!!!

thx Najzero for giving me 5 reputation,now i can capture the screen to show the effect.I will append a detail description follow.

the z-pass algorithm effect: when i'm not in the effect,it's ok!(the orange pot represent the light) enter image description here

but when i'm in the wall_shadow,it's not ok!the wall_shadow is gone,although the brick_shadow is still there.

enter image description here

so I need z-fail algorithm to solve this problem.but the last effect my code realized is like this: enter image description here the tick represent the shadow effect is right,the cross represent the shadow shouldn't appear on the object.

another screenshot, enter image description here

like image 335
nomorefancy Avatar asked Sep 23 '12 09:09

nomorefancy


1 Answers

a ha,At last,I find the problem in my code.I am so happy ,lol!!!!!!!!!

the problem is gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.001f,100.0f);

as the GuentherKrass said in the http://www.opengl.org/discussion_boards/showthread.php/146157-Z-Fail-Stencil-Shadow-Volumes

If you do it this way, be sure to use a perspective projection matrix with an infinite far plane or use GL_DEPTH_CLAMP to avoid the back cap being culled by the far clipping plane.

so I just change the code above to

gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.001f,1000000.0f);

alright,It looks like perfect!!!!!!!!!!!!!!!!!111 hahahahaaa

two days, stay up, instant noodles..it's god damn so worth!!

ok,, I will put the last effct picture out.If anyone want my code just email me([email protected])

enter image description hereenter image description hereenter image description hereenter image description here

attention: the brick shadow is independent of the wall shadow.

like image 189
nomorefancy Avatar answered Nov 09 '22 03:11

nomorefancy