【问题标题】:OpenGL Face culling not working properlyOpenGL人脸剔除无法正常工作
【发布时间】:2012-05-02 11:11:36
【问题描述】:

我在屏幕上画了一个 glutSolidCube 和一个 glutSolidTeapot。

每当我激活 glEnable(GL_CULL_FACE) 时,每个对象都会得到不同的结果。我可以让立方体正确显示 (glCullFace(GL_BACK)) 或茶壶 (glCullFace(GL_FRONT)),但不能同时显示它们。

如果我禁用剔除,那么它们都会正确显示,但我希望能够激活它。

我定义的其他对象也没有正确显示。

由于这些对象是在 GLUT 中定义的,我猜这不是它们的法线问题,或者是吗?

我展示了效果的图像:

光定义:

void setLighting(void) {

//setMaterial();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);

//ambient light color variables
GLfloat alr = 0.0;
GLfloat alg = 0.0;
GLfloat alb = 0.0;

//diffuse light color variables
GLfloat dlr = 1.0;
GLfloat dlg = 1.0;
GLfloat dlb = 1.0;

//specular light color variables
GLfloat slr = 1.0;
GLfloat slg = 1.0;
GLfloat slb = 1.0;


//light position variables
GLfloat lx = 0.0;
GLfloat ly = 100.0;
GLfloat lz = 100.0;
GLfloat lw = 0.0;


GLfloat DiffuseLight[]  = {dlr, dlg, dlb}; //set DiffuseLight[] to the specified values
GLfloat AmbientLight[]  = {alr, alg, alb}; //set AmbientLight[] to the specified values
GLfloat SpecularLight[] = {slr, slg, slb}; //set AmbientLight[] to the specified values
GLfloat LightPosition[] = {lx, ly, lz, lw}; //set the LightPosition to the specified values



GLfloat global_ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glEnable(GL_LIGHTING);

glLightfv (GL_LIGHT0, GL_DIFFUSE,   DiffuseLight); //change the light accordingly
glLightfv (GL_LIGHT0, GL_AMBIENT,   AmbientLight); //change the light accordingly
glLightfv (GL_LIGHT0, GL_SPECULAR,  SpecularLight); //change the light accordingly

glLightfv (GL_LIGHT0, GL_POSITION,  LightPosition); //change the light accordingly
    }

深度测试和剔除启用:

    glEnable(GL_DEPTH_TEST);    // Enable the depth buffer
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Ask for nicest perspective correction

glEnable(GL_CULL_FACE);     // Cull back facing polygons
    glCullFace(GL_BACK); 

【问题讨论】:

    标签: c++ opengl glut


    【解决方案1】:

    您的深度缓冲看起来很糟糕。

    你呢,

    1. 要求有足够分辨率的深度缓冲区? (类似于 32 位)
    2. 将 GL_DEPTH_BUFFER_BIT 传递给 gl_clear
    3. 尝试调整近剪裁平面和远剪裁平面之间的距离以获得更好的分辨率?

    我知道你发布的关于你定义的对象与 glut 茶壶的部分,但 glut 茶壶肯定有一个逆时针顶点缠绕,所以当你打开剔除时它没有显示的事实让我思考深度缓冲区。

    【讨论】:

    • 1) 是 2) 是 3) 我将距离设置为 0.1 到 1000,因为我有大物体。尝试减少一点,但没有喜悦。也许知道我正在使用 GLFW 会有所帮助。
    • 我的东西也使用 GLFW,我非常喜欢它。好吧,这打破了我的猜测,但附带说明一下,您通常可以使用远小于 1000 的剔除距离。例如,为简单起见,许多引擎将 1.0f 表示为一米,因此 1000.0f 的剔除距离能够看到一公里的距离,这取决于您的应用程序,可能没有必要。
    【解决方案2】:

    简单的面剔除基于顶点的顺序 - 无论它们最终在屏幕空间中是顺时针还是逆时针。因此,问题可能出在顶点的定义顺序中,或者您可能正在应用某种变换,它会翻转顺序(例如负缩放)。法线只在光照中起作用。

    【讨论】:

    • 好的,但我不会缩放茶壶。 glut包自带的,不应该和cube一样定义顺序吗?
    • @kelmer:是的,我希望他们会这样。当茶壶渲染好后,如何判断立方体是由里向外的?如果基于照明,你在场景中有什么类型的光,在哪里?
    • 我不断旋转立方体,由于光照,它显示出来了。我编辑了 OP 以显示我的灯光定义。
    • 好吧,试试改变深度比较函数(glDepthFunc)!请注意,OpenGL 默认采用右手坐标系,但也可以使用左手坐标系(您可能正在这样做)。确保您了解这对事物的影响!
    • 我知道,我理解右手定则,但我认为法线也参与面部剔除。无论如何,专注于该死的茶壶,我尝试了所有深度功能,但没有更好的结果。我在这里假设是茶壶而不是我:)
    【解决方案3】:

    这种说法似乎很奇怪:

    每当我激活 glEnable(GL_CULL_FACE) 时,每个对象都会得到不同的结果。我可以让立方体正确显示 (glCullFace(GL_BACK)) 或茶壶 (glCullFace(GL_FRONT)),但不能同时显示它们。

    对此有两种可能的解释:

    1. 要么您的 GLUT 有问题,要么您(不小心?)交换了 Z 轴(例如,对近剪裁平面和远剪裁平面使用所有负距离)。

    2. 您切换了正面绕线方向(致电glFrontFace

    我定义的其他对象也没有正确显示。

    正面由屏幕空间顶点缠绕决定。屏幕上的顶点以顺时针或逆时针顺序排列。默认情况下,OpenGL 假定以逆时针顺序绘制顶点的面作为正面。法线没有被考虑在内。

    我认为解决此问题的最简单方法是交换提交顶点的顺序。

    【讨论】:

    • 可能我自己定义的对象确实定义错了,但是茶壶,我没有在那个上面碰任何东西,也没有调用glFrontFace。我不确定“将所有距离用于近距和远距剪裁平面”是什么意思。我将它们分别定义为 0.1 和 1000。
    • “我不小心说了一个词”——我的意思是所有的距离。 0.1 和 1000 是一个非常糟糕的选择,但是,它会给你带来糟糕的深度缓冲区分辨率。您应该选择尽可能贴合您的场景的它们
    【解决方案4】:

    我认为 GLUT 茶壶只有在未启用 CULL_FACE 的情况下才能正确渲染,这表明生成的法线与顶点顺序不对应。这样做的视觉效果是茶壶似乎与其他物体的旋转方向相反。这是众所周知的旋转空心面罩的效果。大脑试图从灯光中获取线索来理解场景。如果我在绘制之前通过 glScalef(-1,-1,-1) 反转空间,它看起来就像一个普通的茶壶,即使在剔除时也是如此。

    还要注意茶壶不是一个封闭的表面,通过剔除可以让您沿着盖子周围的缝隙看穿它。

    如果您想在这个不可剔除的茶壶旁边组合“可剔除”对象,您可以在渲染茶壶时关闭剔除。

    【讨论】:

      【解决方案5】:

      天哪,我最近几天一直在研究这个问题,只是找到了解决方案。

      显然!,您必须设置:

      glEnable(GL_DEPTH_TEST);
      glEnable(GL_CULL_FACE);     //    Don't waste energy trying the glCullFace(GL_BACK);  
                                  //    thing since its set at GL_BACK by default.
                                  //    Yes, it does cuts triangle NOT facing you.
      

      另外,请确保您的相机没有处于 0.0000001f 到 10 亿这样的疯狂距离。

      然后,除了一个晦涩的教程之外,我在任何地方都没有找到它,但是你必须设置你的 depthframebuffer(是的,另外 5 行就在那里)。

      在生成帧缓冲区名称 (glGenFramebuffers(1, &FramebufferName);) 之后和显示/循环之前,将这 5 行放在任何位置,这样就可以解决问题。我在 FramebufferName 生成之前尝试过它并没有用。但在纹理生成之前或之后,它仍然有效。

      // The depth buffer
      GLuint depthrenderbuffer = 0;
      glGenRenderbuffers(1, &depthrenderbuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
      glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, windowWidth, windowHeight);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer);
      

      多年来,这个 openGL 确实让我发疯了,但我仍然找不到一个完整的更高级别的 c++ 库来包含每个 opengl 调用。但是我现在正在构建一个,如果有人感兴趣,我可能会在这些天发布它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-25
        • 1970-01-01
        • 2015-07-17
        • 1970-01-01
        • 2021-05-11
        • 1970-01-01
        • 2015-09-09
        • 1970-01-01
        相关资源
        最近更新 更多