【问题标题】:Depth test inverted by default in OpenGL, or did I get it wrong?深度测试在 OpenGL 中默认倒置,还是我弄错了?
【发布时间】:2010-11-15 23:19:08
【问题描述】:

我已经用 OpenGL 玩了一整周或同等时间。 在 2D 之后,我现在正在尝试 3D。我想重现您在http://johnnylee.net/projects/wii/ 的第三个视频中看到的 3D 场景。
我很难让纹理和深度的一切都正常工作。

我最近遇到了 2 个在视觉上具有相同影响的问题:

  • 使用我为 2D 找到的技术,纹理在 3D 中无法很好地融合。
  • 一个对象出现在顶部上方的底部。 喜欢这里暴露的问题:Depth Buffer in OpenGL

我已经解决了这两个问题,但我想知道我是否做对了尤其是第二点


第一个,我想我明白了。 我有一个圆形目标的图像,圆盘外的任何东西都带有 alpha。它在 OpenGL 中加载得很好。 它后面的一些(由于我的 z 排序问题)其他目标被我用来绘制它的自然正方形四边形的透明区域所隐藏。

这样做的原因是纹理的每个部分都被假定为对于深度缓冲区是完全不透明的。 使用 glEnable(GL_ALPHA_TEST)glAlphaFunc(GL_GREATER, 0.5f) 测试会使纹理的 alpha 层充当每像素(布尔)不透明度指示器,从而使混合变得毫无用处(因为我的图像具有布尔透明度)。

补充问题:顺便说一句,是否有一种方法可以为 alpha 测试指定一个不同于用于混合的 alpha 层的来源?


第二,我找到了解决问题的方法。 在清除颜色和深度缓冲区之前,我已将默认深度设置为 0 glClearDepth(0.0f),并且我使用了“更大”深度函数 glDepthFunc(GL_GREATER)

让我觉得奇怪的是深度是 1.0,深度函数默认是“更少”GL_LESS。 我基本上是在反转它,这样我的对象就不会倒置显示...

我在任何地方都没有看到过这样的 hack,但另一方面,我也没有看到任何地方以错误的顺序系统地绘制对象,无论我绘制它们的顺序是什么


好的,下面是现在按我想要的方式工作的代码(精简了,我不希望太多):

    int main(int argc, char** argv) {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
        glutInitWindowSize(600, 600); // Size of the OpenGL window
        glutCreateWindow("OpenGL - 3D Test"); // Creates OpenGL Window
        glutDisplayFunc(display);
        glutReshapeFunc(reshape);

        PngImage* pi = new PngImage(); // custom class that reads well PNG with transparency
        pi->read_from_file("target.png");
        GLuint texs[1];
        glGenTextures(1, texs);
        target_texture = texs[0];
        glBindTexture(GL_TEXTURE_2D, target_texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, pi->getGLInternalFormat(), pi->getWidth(), pi->getHeight(), 0, pi->getGLFormat(), GL_UNSIGNED_BYTE, pi->getTexels());

        glutMainLoop(); // never returns!
        return 0;
    }

    void reshape(int w, int h) {
        glViewport(0, 0, (GLsizei) w, (GLsizei) h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-1, 1, -1, 1);
        gluPerspective(45.0, w/(GLdouble)h, 0.5, 10.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }

    void display(void) {
        // The stared *** lines in this function make the (ugly?) fix for my second problem
        glClearColor(0, 0, 0, 1.00);
        glClearDepth(0);          // ***
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glShadeModel(GL_SMOOTH);
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_DEPTH_FUNC);  // ***
        glDepthFunc(GL_GREATER);  // ***

        draw_scene();

        glutSwapBuffers();
        glutPostRedisplay();
    }

    void draw_scene() {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(1.5, 0, -3, 0, 0, 1, 0, 1, 0);

        glColor4f(1.0, 1.0, 1.0, 1.0);
        glEnable(GL_TEXTURE_2D);
        // The following 2 lines fix the first problem
        glEnable(GL_ALPHA_TEST);       // makes highly transparent parts
        glAlphaFunc(GL_GREATER, 0.2f); // as not existent/not drawn
        glBindTexture(GL_TEXTURE_2D, target_texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        // Drawing a textured target
        float x = 0, y = 0, z = 0, size = 0.2;
        glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3f(x-size, y-size, z);
        glTexCoord2f(1.0f, 0.0f);
        glVertex3f(x+size, y-size, z);
        glTexCoord2f(1.0f, 1.0f);
        glVertex3f(x+size, y+size, z);
        glTexCoord2f(0.0f, 1.0f);
        glVertex3f(x-size, y+size, z);
        glEnd();
        // Drawing an textured target behind the other (but drawn after)
        float x = 0, y = 0, z = 2, size = 0.2;
        glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f);
        glVertex3f(x-size, y-size, z);
        glTexCoord2f(1.0f, 0.0f);
        glVertex3f(x+size, y-size, z);
        glTexCoord2f(1.0f, 1.0f);
        glVertex3f(x+size, y+size, z);
        glTexCoord2f(0.0f, 1.0f);
        glVertex3f(x-size, y+size, z);
        glEnd();
    }

【问题讨论】:

    标签: opengl transparency textures z-order depth-buffer


    【解决方案1】:

    通常,深度清除值是 1(实际上是无穷大),深度传递函数是 LESS,因为您想模拟现实世界,您可以在其中看到事物在其后面的事物。通过将深度缓冲区清除为 1,您实际上是在说应该绘制所有比最大深度更近的对象。除非您真正了解自己在做什么,否则通常不会更改这些参数。

    使用您传递给 gluLookAt 的相机参数和对象的位置,z=2 四边形将比 z=0 对象离相机更远。您想完成什么以使这看起来不正确?

    实现顺序正确的 Alpha 混合的标准方法是渲染所有不透明对象,然后将所有透明对象重新渲染到前面。将始终使用常规/默认深度函数。

    另外请注意,您在设置透视矩阵的方式中可能会遇到一些奇怪的行为。通常你会调用 gluOrtho 或 gluPerspective。但不是两者兼而有之。这会将两个不同的透视矩阵相乘,这可能不是您想要的。

    【讨论】:

    • 我逐段回答: 1)我只是将它反转来反转反转! 2)我正在测试两个对象的渲染,一个接一个,不应该看到 z=2 处的那个,但它是在第 1 段的修复之前。 3)我在阅读时知道,但我不太需要它。 4) 这就是诀窍!它现在无需反转深度即可工作!我基本上是一个 2D 代码,我已经适应了绘制 3D 并且我省略了这条愚蠢的线。谢谢!
    【解决方案2】:

    补充问题:顺便说一句,是 有一种指定不同的方法 alpha 测试的来源比 用于混合的 alpha 层?

    是的,如果您使用着色器,您可以自己计算输出片段的 alpha 值。

    【讨论】:

    • 我添加了一个鼠标选择,使用glRenderMode(GL_SELECT),但我遇到了一个问题:ALPHA_TEST 未在此模式下使用(是否禁用混合)。这个帖子stackoverflow.com/questions/1189891/… 似乎另有说明,尽管他没有测试它。如果有帮助,我有一张 ATI Mobility Radeon HD 2600 卡,在 Kubuntu Lucid Lynx 10.04.1 LTS 下,使用 fglrx 专有驱动程序版本 2:8.723.1-0ubuntu5。 (我提到它是为了以防万一,因为我注意到多边形平滑适用于较旧的 nVidia 而不是这张 ATI 卡......)
    • 我不明白你想用 alpha 做什么。
    【解决方案3】:

    关于第二个问题:你的 modelViewProjection 矩阵很可能有问题。

    我遇到了同样的问题(并且可以用你的 hack 来“修复”它),这是因为我使用了一个奇怪的错误矩阵。我解决了它实现我自己的矩阵生成。

    【讨论】:

      【解决方案4】:

      在标准 glOrtho 函数中实现的公式将 zNear 映射到 -1,zFar 映射到 1,默认情况下映射到窗口坐标为 [0,1](可通过 glDepthRange 更改固定管道,不确定该函数是否仍受支持) .深度测试确实在这些方面起作用。 解决这个问题的方法是假设 zNear 离投影平面最远,或者自己生成矩阵,如果你想摆脱遗留管道,无论如何都需要。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-21
        • 1970-01-01
        • 2015-10-12
        • 1970-01-01
        • 2018-10-09
        • 2012-02-21
        • 2012-11-28
        • 1970-01-01
        相关资源
        最近更新 更多