如何在opengl中实现z-fail算法?

nom*_*ncy 6 opengl shadow stencil-buffer

我代码作为NeHe导师Lesson27告诉我,但它是一个z-pass算法.当我在阴影中时,阴影消失.有人告诉我,我可以使用z-fail算法来解决这个问题.所以我花了两天时间来研究z-fail算法.最后,我无法弄明白.我的程序永远不会像我想的那样运行.

作为wiki列出的z-fail算法:

深度失败在2000年左右,有几个人发现Heidmann的方法可以通过反转深度来适用于所有摄像机位置.而不是计算对象表面前面的阴影表面,它后面的表面可以很容易地计算,具有相同的最终结果.这解决了眼睛处于阴影中的问题,因为眼睛和物体之间的阴影体积不计算,但是引入了阴影体积的后端必须加盖的条件,或者阴影将最终丢失在体积指向的位置向后无穷大.

  1. 禁用对深度和颜色缓冲区的写入.

  2. 使用正面剔除.

  3. 将模板操作设置为在深度失败时递增(仅计算对象后面的阴影).

  4. 渲染阴影卷.

  5. 使用背面剔除.

  6. 将模板操作设置为在深度失败时递减.

  7. 渲染阴影卷.

我认为的主要问题是深度测试.在步骤3和6,模板操作基于深度失败.虽然它可以显示阴影,但它可能在它之前的对象上阴影(即:深度缓冲值小于它的对象).所有阴影效果看起来很乱.

但是在z-pass算法中,模板操作基于深度通过,这意味着它不仅可以显示阴影,而且仅在其后面的对象上阴影,符合眼睛系统.

所以如何解决这个问题使我的深度失败算法显示出正确对象的阴影.

这是我的z-fail算法代码(某处可能在哪里,请帮我看看,阴影效果很糟糕)

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);
}
Run Code Online (Sandbox Code Playgroud)

VECTOR类是这样的:

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;
    }
};
Run Code Online (Sandbox Code Playgroud)

SECTOR课程和其他人是这样的:

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;
};
Run Code Online (Sandbox Code Playgroud)

我的main.cpp中的DrawGLScene函数是这样的:

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
}
Run Code Online (Sandbox Code Playgroud)

由于我的声望低于10,我无法捕捉到阴影效果,向你展示它看起来有多糟糕!请帮助我,我会请你注意你的时间!

Naxzero为我提供了5个声望,现在我可以捕捉屏幕以显示效果.我将附加详细说明如下.

z-pass算法效果:当我没有效果时,没关系!(橙色的锅代表灯光) 在此输入图像描述

但是,当我在wall_shadow中时,它不行!尽管brick_shadow仍然存在,但wall_shadow已经消失了.

在此输入图像描述

所以我需要z-fail算法来解决这个问题.但是我的代码实现的最后一个效果是这样的: 在此输入图像描述 刻度表示阴影效果是正确的,十字表示阴影不应出现在对象上.

另一个截图, 在此输入图像描述

nom*_*ncy 2

哈哈,终于在我的代码中找到了问题。我太高兴了,哈哈!!!!!!!!!!

\n\n

问题是 gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.001f,100.0f);

\n\n

正如 GuentherKrass 在http://www.opengl.org/discussion_boards/showthread.php/146157-Z-Fail-Stencil-Shadow-Volumes中所说

\n\n

如果您这样做,请务必使用具有无限远平面的透视投影矩阵或使用 GL_DEPTH_CLAMP 以避免后盖被远剪裁平面剔除。

\n\n

所以我只需将上面的代码更改为

\n\n

gluPerspective(45.0f,(GLfloat)宽度/(GLfloat)高度,0.001f,1000000.0f);

\n\n

好吧,看起来很完美!!!!!!!!!!!!!!!!!!111 哈哈哈哈哈哈

\n\n

两天\xef\xbc\x8c熬夜\xef\xbc\x8c方便面..这该死的太值得了!!

\n\n

好的,我会把最后的效果图放出来。如果有人想要我的代码,请发电子邮件给我(nomorefancy@gmail.com)

\n\n

在此输入图像描述\n在此输入图像描述\n在此输入图像描述\n在此输入图像描述

\n\n

注意:\n砖块阴影独立于墙壁阴影。

\n