阅读 396

OpenGL绘制甜甜圈及正背面剔除和深度测试(5)

采用OpenGL提供的固定着色器,绘制甜甜圈,并使用上下左右方向键控制旋转它,具体代码:github.com/xiaTing/Ope…

图1
我们看到,当我旋转它的时候,图形显示出现来问题,出现来一片片的黑色,这是我绘制时,并没有开启深度测试,我们知道一个图形有正面、反面之分,OpenGL 绘制图形时也是有正面、反面的规律的,OpenGL 中色使用习惯:
图2
在立体图形中,我们看到某一面,并不总是正面,或者反面,与我们观察图形的角度是有关系的,如下图中:
图3
左侧的三角形的顶点顺序为1->2->3,右侧的三角形的顺序为1->2->3,

1.当观察者在右侧时,则右边的三角形我正面,左侧的三角形为背面

2.当观察者在左侧时,则左侧的三角形为正面,右侧的三角形为背面

总结:正⾯和背⾯是有三⻆形的顶点定义顺序和观察者⽅向共同决定的,随着观察者的⻆度⽅向的改变,正⾯背⾯也逻辑教育会跟着改变

了解了上面的正面背面的定义后,我们再回到第一张图中的问题,图1中的问题是应为,OPenGL在绘制时,不知道该绘制正面的效果,还是背面的效果而引起的;从日常的生活中,我们知道,我们在观察一个正方体时,无论站在什么角度观察,我们最多只能看到正方体的三个面,那么,如果我们使用OpenGL绘制立体图形时,将我们看不到的面的像素点的情况丢弃,不绘制,这样既能将绘制效率提高50%,还能解决上面出现的问题; 接下来我打开OpenGL的正背面剔除开关,并剔除背面,glFrontFace可以指定逆时针三角形面为正面,也可以指定顺时针三角形为正面,默认逆时针三角形面为正面,GL_CCW,通常我们使用默认,如要改为顺时针,参数为GL_CW

问题1解决:背面剔除

        //开启表面剔除
        glEnable(GL_CULL_FACE);
        //设置正面 默认 GL_CCW
        glFrontFace(GL_CCW);
        //设置剔除面 默认 GL_BACK
        glCullFace(GL_BACK);
复制代码

再来看一下,增加背面剔除后的效果

图4
OpenGL的表面剔除模式有三种,分别为

1.GL_FILL
2.GL_LINE
3.GL_POINT
复制代码

上图中显示的是GL_FILL模式,使用下面方法可以设置剔除模式

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
复制代码

下面分别给出GL_LINE和GL_POINT模式剔除的效果,最后会给出代码,代码中可以通过右击选择剔除效果

图5
图6
我们看到,背面剔除后,不在出现黑色的情况,但是图4中出现来新的问题,就是图形会有缺口的效果出现,这是由于OpenGL在绘制一个立体图形是,无法判断应该绘制离观察者近的的效果、还是绘制离观察者远的的效果,这里的远近,就是OpenGL中的深度,要解决图中的问题,我们需要开启深度测试;

什么是深度?

深度其实就是该像素点在3D世界中距离摄像机的距离,Z值

什么是深度缓冲区?

深度缓存区,就是⼀块内存区域,专⻔存储着每个像素点(绘制在屏幕上的)深度值,深度值(Z值)越⼤,则离摄像机就越远.

为什么需要深度缓冲区?

在不使⽤深度测试的时候,如果我们先绘制⼀个距离⽐较近的物理,再绘制距离较远的物理,则距离远的位图因为后绘制,会把距离近的物体覆盖掉。有了深度缓冲区后,绘制物体的顺序就不那么᯿要的。实际上,只要存在深度缓冲区,OpenGL 都会把像素的深度值写⼊到缓冲区中。除⾮调⽤ glDepthMask(GL_FALSE).来禁⽌写⼊。

深度测试

深度缓冲区(DepthBuffer)和颜⾊缓存区(ColorBuffer)是对应的,颜⾊缓存区存储像素的颜⾊信息,⽽深度缓冲区存储像素的深度信息。在决定是否绘制⼀个物体表⾯时, ⾸先要将表⾯对应的像素的深度值与当前深度缓冲区中的值进⾏⽐较,如果⼤于深度缓冲区中的值,则丢弃这部分,否则利⽤这个像素对应的深度值和颜⾊值,分别更新深度缓冲区和颜⾊缓存区,这个过程称为”深度测试”;

问题2解决

通过以上概念的解释,我们知道深度值越大,距离观察者越远,也就是距离我们的眼睛越远,常识告诉我们,离我们眼睛近的物体,会挡住离我们远的物体,所以距离远的将被丢弃,对应的数据不存储被离得近的数据覆盖(颜色和深度);那我们利用以下代码开启深度测试后,再看最终效果

glEnable(GL_DEPTH_TEST);
复制代码

到此,就解决来我们这个案例中遇到的两个问题,当然在绘制结束后,记得将背面剔除、深度测试关闭,以免影响后续的绘制

glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
复制代码

此案例代码见: github.com/xiaTing/Ope… 案例5

文章分类
iOS
文章标签