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

如何在opengl中实现z-fail算法?,opengl,shadow,stencil-buffer,Opengl,Shadow,Stencil Buffer,我按照NeHe导师第27课的要求编写代码,但这是一个z-pass算法。当我在阴影中时,阴影消失了。有人告诉我我可以使用z-fail算法来解决这个问题。 所以我花了两天时间研究z-fail算法。最后,我搞不懂它。我的程序从来没有像我想的那样运行 wiki列出的z-fail算法: 深度失效 大约在2000年,一些人发现海德曼的方法可以通过反转深度来适用于所有摄像机的位置。与计算对象曲面前面的阴影曲面不同,可以同样轻松地计算对象曲面后面的曲面,最终结果相同。这解决了眼睛处于阴影中的问题,因为眼睛和对象

我按照NeHe导师第27课的要求编写代码,但这是一个z-pass算法。当我在阴影中时,阴影消失了。有人告诉我我可以使用z-fail算法来解决这个问题。 所以我花了两天时间研究z-fail算法。最后,我搞不懂它。我的程序从来没有像我想的那样运行

wiki列出的z-fail算法:

深度失效 大约在2000年,一些人发现海德曼的方法可以通过反转深度来适用于所有摄像机的位置。与计算对象曲面前面的阴影曲面不同,可以同样轻松地计算对象曲面后面的曲面,最终结果相同。这解决了眼睛处于阴影中的问题,因为眼睛和对象之间的阴影体积不被计算,但引入了阴影体积后端必须被覆盖的条件,否则阴影将在体积向后指向无穷大时丢失

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

  • 使用正面剔除

  • 将模具操作设置为“深度失败时递增”(仅计算对象后面的阴影)

  • 渲染阴影体积

  • 使用背面剔除

  • 将模具操作设置为深度失败时递减

  • 渲染阴影体积

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

    但在z-pass算法中,模板操作是基于深度传递的,这意味着它不仅可以显示阴影,而且只能在后面的物体上阴影,这符合人眼系统

    那么如何解决这个问题,让我的深度失败算法在正确的物体上显示阴影呢

    这是我的z-fail算法代码(可能在某个地方,请帮我找出,阴影效果很糟糕)

    扇区类和其他类如下所示:

    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;
        }
    };
    
    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;
    };
    
    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
    }
    
    因为我的名声在10岁以下,我无法捕捉阴影效果来告诉你它看起来有多糟糕!请帮助我,我会感谢你的关注和你的时间

    thx Najzero给了我5点声誉,现在我可以抓拍屏幕显示效果了。我会在下面附上详细说明

    z-pass算法的效果: 当我不在效果中时,没关系!(橙色的罐子代表灯)

    但是当我在墙的阴影里时,那就不好了!墙的影子不见了,尽管砖的影子还在

    所以我需要z-fail算法来解决这个问题。但是我的代码实现的最后一个效果是这样的: 勾号表示阴影效果正确,十字表示阴影不应出现在对象上

    另一个截图,
    哈哈,我终于在代码中找到了问题。我很高兴,哈哈

    问题是透视(45.0f,(GLfloat)宽度/(GLfloat)高度,0.001f,100.0f)

    正如根瑟克拉斯在《圣经》中所说的那样

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

    所以我把上面的代码改成

    玻璃液位(45.0f,(玻璃液位)宽度/(玻璃液位)高度,0.001f,1000000.0f)

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

    两天,熬夜,方便面…真他妈的值

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

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

    哦,这应该很有趣。我们遇到了一个类似的问题。你的近距离飞机设定在什么位置?不要看到gluPerspective()调用来进行猜测。当“近平面”为0时,涉及Z渲染的所有内容都会得到一些疯狂的结果。这是我的gluPerspective函数:我的“近平面”设置为0.001f gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.001f,100.0f);nearplane不能为0,您可以改为使用0.00001。此代码非常不推荐使用。
    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
    }