深度缓冲是在三维图形中处理图像深度坐标(个人认为可以理解成距离我们观察摄像机远近的距离)的过程----From wiki
这听起来不好理解啊啊啊啊。
所以就举个栗子喽XD,就好比我可能要按由近到远顺序渲染两个面(实际上是任意顺序,我是说假如按这个顺序),近处的面先渲染,之后渲染远处的面,但是如果没有开启深度测试glEnable(GL_DEPTH_TEST),那么远的面将要覆盖掉我们近处渲染的面,显然这不是我们所想要看到的。所以此时就需要深度测试,远的面的深度值与近处的面的深度值进行比较,一旦远的面深度值比较大即距离我们较远,那么该片段就会被丢弃掉,但这与面剔除似乎是不一样的,面剔除是根据面向观察者和背向观察者去判断是否丢弃片段,不知道我这样讲是否正确,求看到此篇的大神用力的打我脸!
其中我最不理解的“丢弃片段”(为什么片段丢弃后我摄像机移动,还是能看到原先背向我的那一些片段?)后来发现仅仅是在此帧渲染时丢弃这些片段。但是之后摄像机一旦移动那么又是渲染另一帧,所以重新进入渲染管线进行渲染,同时这就是为什么我们要创建顶点数组缓冲对象的原因,否则我们就要创建VBO,设置顶点指针属性等等复杂操作。虽然现代的OpenGL是不支持不创建VAO的。
深度缓冲区的原理:
最初先使用glClear(GL_DEPTH_BUFFER_BIT)把所有窗口上的像素的深度值设置为最大值。
然后在场景中以任意顺序绘制所有物体。OpenGL计算把每一个绘制表面转换为窗口上一些像素的集合,此时没有启动深度测试并不考虑是否被其他物体遮挡。所以可能导致远的绘制表面把近的绘制表面覆盖掉
其次,OpenGL会计算这些表面和观察平面的距离。如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把它的深度值和已经存储在这个像素的深度值进行比较。如果新像素深度值<原先像素深度值,则新像素值会取代原先的像素值;反之,新像素值包括他的颜色值和深度将被丢弃。
深度测试的笔记:
1.深度缓冲是由我们使用的创建窗口库自动创建的,我使用的是GLFW库所以就由它创建,同时它在大部分系统上将深度值存储为24位的浮点数
2.深度测试在渲染管线(pipeline)中是在模板测试之后
3.OpenGL执行深度测试时,如果此片段测试通过,OpenGL自动在深度缓冲区存储片段的 z 值,否则将丢弃该片段
4.屏幕空间坐标直接有关的视区,由glViewport()函数给定(glViewport()在默认情况下,视口被设置为占据打开窗口的整个像素矩形),同时也可由片段着色器中glFragCoord的x和y的分量访问,同时z坐标也包含了片段实际深度值
5.片段着色器的运行相当费时,提前深度测试可以更早的放弃用于那不会出现的片段(不知道算不算要点)
6. 在某些情况下,我们需要进行深度测试并相应地丢弃片段,但我们不希望更新深度缓冲区,基本上,可以使用一个只读的深度缓冲区,此时可以通过glDepthMask(GL_FASLE)来禁止对缓冲区写入,实际上,只要存在深度缓冲区,无论是否启用深度测试,OpenGL在像素被绘制时都会尝试将深度数据写入到缓冲区内。
7.glDepthFunc()如果参数是GL_LESS,那么将设置成在片段深度值小于缓冲区深度时通过测试,否则丢弃片段,具体参数可以见下表:
深度值的精度(将平截头题中的z值转换成[0.0,1.0]范围内然后进行深度值的比较):
计算这个精度有两个转换公式和
两者对应的函数图片分别如下
和
其中前者是非线性的转换而后者是线性的转化,但是后者的话在实践中是几乎从来不使用这样的线性深度缓冲区。如果使用线性,那么100单位和1单位精度是基本一样的,而非线性他们在z很小的时候有很高的精度(即函数变化快,较为精确),而较大的 z 值有较低的精度。因为我们所做的就是要越近的物体比较越精细(函数变化越快)才能更好的渲染细节,远的物体比较个大概即可(此处原因是我个人理解,不知道我这样讲是否正确,求看到此篇的大神用力的打我脸!),所以常使用前者。
两者计算比较图
使用前者那么渲染出来的结果如下:
z值由小变大,很快颜色就由暗变亮,这就说明只要短短移动一点距离,变化就越明显,暗色就快速的变亮
使用后者渲染图
由暗变亮需要很长距离的变化,这就是两者区别
最后一点,如果发现图像闪烁考虑是否发生了深度冲突及两个图像的某个部分深度相同造成的
本文仅仅是为了学习,篇中有些是改了改前辈的,再加上自己的理解放入的,侵删!欢迎大神来打我脸!!!
-----------2016/12/14