LearnOpenGL-高级OpenGL-4.面剔除

本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正

我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject

面剔除

  • 作用

    OpenGL能够检查所有面向(Front Facing)观察者的面,并渲染它们,而丢弃那些背向(Back Facing)的面,节省我们很多的片段着色器调用(它们的开销很大!)。

    但我们仍要告诉OpenGL哪些面是正向面(Front Face),哪些面是背向面(Back Face)。OpenGL使用了一个很聪明的技巧,分析顶点数据的环绕顺序(Winding Order)。

  • 记住

    确认在每个三角形中它们都是以逆时针定义的,这是一个很好的习惯

环绕顺序

  • 顺时针(Clockwise)的,也可能是逆时针(Counter-clockwise)的

  • 代码角度

    float vertices[] = {
        // 顺时针
        vertices[0], // 顶点1
        vertices[1], // 顶点2
        vertices[2], // 顶点3
        // 逆时针
        vertices[0], // 顶点1
        vertices[2], // 顶点3
        vertices[1]  // 顶点2  
    };
    

    每组组成三角形图元的三个顶点就包含了一个环绕顺序。OpenGL在渲染图元的时候将使用这个信息来决定一个三角形是一个正向三角形还是背向三角形。

    默认情况下,逆时针顶点所定义的三角形将会被处理为正向三角形

  • 解释这默认情况下

    当你定义顶点顺序的时候,你应该想象对应的三角形是面向你的,所以你定义的三角形从面看去应该是逆时针的。

    这样定义顶点很棒的一点是,实际的环绕顺序是在光栅化阶段进行的,也就是顶点着色器运行之后。这些顶点就是从观察者视角所见的了。

  • 图示

    我们所面向的三角形将会是正向三角形,而背向面的三角形则是背向三角形

    faceculling_frontback

    • 解释

      两个三角形都以逆时针顺序定义

      如果从观察者当前视角使用1、2、3的顺序来绘制的话,从观察者的方向来看,向面的三角形将会是以时针顺序渲染。向面的三角形将会是以时针顺序渲染。

    • 重点

      结合图:虽然向面的三角形是以逆时针定义的,但以现在视角的角度它现在是以时针顺序渲染的了。这正是我们想要剔除(Cull,丢弃)的不可见面了!

      向面的三角形也是以逆时针定义的,但以现在视角的角度它现在依旧是以逆时针顺序渲染的。

面剔除

  • 启用

    OpenGL默认是关闭的

    glEnable(GL_CULL_FACE);
    
  • OpenGL允许我们改变需要剔除的面的类型

    glCullFace(GL_FRONT); 
    
    • GL_BACK:只剔除向面。
    • GL_FRONT:只剔除向面。
    • GL_FRONT_AND_BACK:剔除正向面和背向面。
  • 告诉OpenGL我们希望将顺时针还是逆时针的面定义为正向面

    • GL_CCW:逆时针的环绕顺序是正面(默认)
    • GL_CW:顺时针的环绕顺序是正面

测试1:顶点环绕顺序不按照时钟定义,开启剔除并且默认逆时针的环绕顺序是正面

// 1.裁剪后面
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
float cubeVertices[] = {
    // positions          // texture Coords
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
    0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};

环绕顺序不按照时钟定义,导致面剔除出现错误

测试2:顶点环绕顺序按照逆时钟定义,开启剔除并且默认逆时针的环绕顺序是正面

按照逆时钟定义,正确的剔除后面

// 1.裁剪后面
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
float cubeVertices[] = { // 确保三角形是逆时针定义的
    // Back face:背面,从视角看的话是顺时针顺序渲染的,实际上是逆时针定义的
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f, // Bottom-left
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-right
    0.5f, -0.5f, -0.5f,  1.0f, 0.0f, // bottom-right         
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-right
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f, // bottom-left
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f, // top-left
    // Front face,正面,从视角看的话是逆时针渲染的,实际上也是逆时针定义的
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-left
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f, // bottom-right
    0.5f,  0.5f,  0.5f,  1.0f, 1.0f, // top-right
    0.5f,  0.5f,  0.5f,  1.0f, 1.0f, // top-right
    -0.5f,  0.5f,  0.5f,  0.0f, 1.0f, // top-left
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-left
    // Left face
    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // top-right
    -0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-left
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // bottom-left
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // bottom-left
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-right
    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // top-right
    // Right face
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // top-left
    0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // bottom-right
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-right         
    0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // bottom-right
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // top-left
    0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-left     
    // Bottom face
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // top-right
    0.5f, -0.5f, -0.5f,  1.0f, 1.0f, // top-left
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f, // bottom-left
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f, // bottom-left
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-right
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // top-right
    // Top face
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f, // top-left
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // bottom-right
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-right     
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // bottom-right
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f, // top-left
    -0.5f,  0.5f,  0.5f,  0.0f, 0.0f  // bottom-left        
};
float planeVertices[] = {
    // positions          // texture Coords (note we set these higher than 1 (together with GL_REPEAT as texture wrapping mode). this will cause the floor texture to repeat)
    // 逆时针
    5.0f, -0.5f,  5.0f,  2.0f, 0.0f,// 右下
    5.0f, -0.5f, -5.0f,  2.0f, 2.0f,// 右上
    -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,// 左上

    -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,// 左上
    -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,// 左下
    5.0f, -0.5f,  5.0f,  2.0f, 0.0f,// 右下
};

可见箱子的背面不被渲染

测试3:环绕顺序按照逆时钟定义,开启剔除

  • 告诉OpenGL现在改为三角形顶点顺时针的环绕顺序是正面

    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    glFrontFace(GL_CW);// 顺时针的环绕顺序是正面
    

    同样效果的

    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);
    

    三角形顶点使用默认的时针环绕顺序是面,但剔除正向面

  • 效果

    请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值