图形图像渲染中的深度缓冲区
在绘制3D场景的时候,我需要决定哪部分是对观察者可见,哪部分是不可见,不透明的地方不应该渲染,这叫做“隐藏面消除”
解决方法:油画算法:先绘制场景中的离观察者较远的物体,再绘制较近的物体。
油画发弊端:使用油画法,只要将场景按照物理距离观察者远近排序,由远及近的绘制即可。如果三个三角形是叠加的,油画无法处理
解决方案:正背面剔除(任何平面都有2个面 正/反 意味着你一个时刻只能看到一个面)
如何区分正反面?
通过分析顶点数据的顺序
GLfloat vertices[] = {
//顺时针
vertices[0], // vertex 1
vertices[1], // vertex 2
vertices[2], // vertex 3
// 逆时针
vertices[0], // vertex 1
vertices[2], // vertex 3
vertices[1] // vertex 2
}
正面:按照逆时针顶点连接顺序的三角面
背面:按照顺时针顶点连接顺序的三角面
什么是深度缓冲区?为什么需要深度缓冲区?
深度缓存区就是一块内存区域,专门存储着每个像素点(绘制在屏幕上)深度值,深度值(Z值)越大,则离摄像机就越远
在不同深度测试的时候,如果我们先绘制一个距离比较近的物理,再绘制距离较远的距离,则距离远的位图因为后图绘制,会把距离近的物体覆盖掉,有了深度缓冲区,绘制物体的顺序就不那么重要的,实际,只要存在深度缓冲区,OpenGL 都会把像素的深度值写入到缓冲区中,除非调用glDepthMask(GL_FALSE)来禁⽌写⼊
Z-buffer方法(深度缓冲区buffer)
深度测试:
深度缓冲区 与 颜色缓冲区 是对应的。颜色缓冲区存储像素的颜色信息,而深度缓冲区存储像素的深度信息。
在决定是否绘制一个物体表面时,首先要将表面对应的像素的深度值与当前深度缓冲区中的值进行比较。如果大于 深度缓冲区的值,则丢弃这部分;否则利用这个像素对应的深度值和颜色值,分别更新深度缓冲区 和颜色缓冲区。
视图空间 z 值 到 [0,1] 的范围内,下⾯的 (线性) ⽅程把 z 值转换为 0.0 和 1.0 之间的值 :
1.png
far 和near 是提供到投影矩阵设置可见视图截锥的远近值。
非线性深度缓存
在实践中是可以减少使用这样的线性深度缓存区。正确的投影特性的非线性深度方程是和1/z成正比的,由于非线性函数和1/z成正比。例如1.0和2.0 之间的z值,将变成1.0 到0.5之间,这样在z非常小的时候给了我们很高的精度。
//⽚元着⾊器
out vec4 color;
float LinearizeDepth(float depth)
{
float near = 0.1;
float far = 100.0;
float z = depth * 2.0 - 1.0; // Back to NDC
return (2.0 * near) / (far + near - z * (far - near));
}
void main()
{
float depth = LinearizeDepth(gl_FragCoord.z);
color = vec4(vec3(depth), 1.0f);
}
深度缓冲区,一般有窗口管理系统,GLFW创建,深度值一般由16位、24位、32位值表示,通常是24位,位数越到,深度精确度更好。
• 开启深度测试
glEnable(GL_DEPTH_TEST);
• 在绘制场景前,清除颜⾊缓存区在绘制场景前,清除颜⾊缓存区,深度缓冲
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
• 清除深度缓冲区默认值为1.0,表示最⼤的深度值,深度值的范围为(0,1)之间. 值越⼩表示越靠近观察者,值越⼤表示越远离观察者
打开/阻断 深度缓存区写⼊
void glDepthMask(GLBool value);
value : GL_TURE 开启深度缓冲区写⼊; GL_FALSE 关闭深度缓冲区写⼊
指定深度测试判断模式
void glDepthFunc(GLEnum mode);
截屏2020-07-1811.24.05.png