深度测试

深度测试

为什么需要深度测试?

  • 为了实现场景中物体的遮挡效果
  • 如果没有深度测试,场景前边的物体不会挡住后边的物体;同一个物体前边的部分也不会挡住后边的部分,会使物体出现显示不全、闪烁等一些不好的现象

什么是深度测试?

  • 当前片段的深度值与深度缓冲中的深度值比较,如果符合预设的比较结果,就认为测试通过,然后用当前片段的深度值替换深度缓冲中的深度值;如果测试不通过,就丢弃当前片段的深度值
  • 当前片段的深度值指的是:从观察者角度看向物体时的距离,这个距离再通过投影变换(变换到裁剪空间)、标准化设备坐标(变换到[-1.0,1.0])、缩放平移(变换到[0.0,1.0])后,最终得到的值

怎么进行深度测试?

深度缓冲

  • 深度缓冲中存储了每个片段的深度值,默认1.0
  • 有宽度和高度,这个宽和高是他的分辨率。
  • 一般是在窗口系统中自动创建的,他可以以16、24或32位float的形式存储深度值;在大部分系统中,深度缓冲的精度都是24位

深度测试

在光栅化中的位置
  • 深度测试在片段着色器执行之后,并且在模板测试之后在屏幕空间坐标进行(屏幕空间坐标与glViewport所定义的视口大小密切相关)
  • 屏幕空间坐标可以用gl_FragCoord在片段着色器中直接访问;vec3类型的gl_FragCoord的x、y分量分别代表片段在屏幕空间中的坐标x、y((0,0)点位于左下角);z代表片段的深度,就是需要与深度缓冲中的内容所比较的那个值
  • 现代GPU提供提前深度测试的硬件特性。这个特性允许深度测试在片段着色器之前运行,但前提是需要知道某个片段始终是被遮挡的,并且不能在片段着色器中修改深度值
控制函数
  • 启用——glEnable(GL_DEPTH_TEST),深度测试默认是禁用的
  • 清空深度缓冲——glClear(GL_DEPTH_BUFFER_BIT),如果启用了深度测试,就要在每帧之前清空深度缓冲,不然使用的还是上一帧写入深度缓冲的深度值
  • 禁用写入——glDepthMask(GL_FALSE),通过设置深度掩码,实现禁用深度缓冲的写入,使深度缓冲变为一个只读的缓冲;这个函数只在深度测试被启用的情况下有用
  • 设置比较结果——前边说过,通过比较达到预设的比较结果,就认为是通过深度测试,这个比较结果就是用glDepthFunc(XX)设置的;XX默认的是GL_LESS,还有另外7种设置
深度值的大小
  • 深度值是介于0.0与1.0之间的值
  • 深度值是从观察者角度所看到的场景中物体的z值,这个值是投影矩阵作用后的,又经过标准设备坐标变换,再经过范围变换(变换到0.0与1.0之间)得到的值
  • 深度值在透视投影中是非线性的,原因如下:裁剪空间中的坐标等于投影矩阵乘以观察空间中的坐标,即

( x c y c z c w c ) = p r o j M a t ∗ ( x v y v z v 1.0 ) \left( \begin{matrix} x_c \\ y_c \\ z_c \\ w_c \end{matrix} \right) = projMat * \left( \begin{matrix} x_v \\ y_v \\ z_v \\ 1.0 \end{matrix} \right) xcyczcwc=projMatxvyvzv1.0
而透视投影矩阵projMat为:
p r o j M a t = ( 2 n r − l 0 r + l r − l 0 0 2 n t − b t + b t − b 0 0 0 − ( f + n ) f − n − 2 f n f − n 0 0 − 1 0 ) projMat = \left( \begin{matrix} \frac{2n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & \frac{2n}{t-b} & \frac{t+b}{t-b} & 0 \\ 0 & 0 & \frac{-(f+n)}{f-n} & \frac{-2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{matrix} \right) projMat=rl2n0000tb2n00rlr+ltbt+bfn(f+n)100fn2fn0
由此可知:
z c = − ( f + n ) f − n z v + − 2 f n f − n = − ( f + n ) z v − 2 f n f − n z_c = \frac{-(f+n)}{f-n}z_v + \frac{-2fn}{f-n} = \frac{-(f+n)z_v - 2fn}{f-n} zc=fn(f+n)zv+fn2fn=fn(f+n)zv2fn
因此zc与近远平面之间的距离成反比,然后再将其转换为标准设备坐标zndc = zc / wc,最后再将zndc * 0.5 + 0.5,得到[0.0,1.0]之间的值,就是最后的深度值(上面的l,r,t,b,f,n分别代表平截头体的左,右,上,下,远,近平面的位置)

深度图像
  • 由于深度值在透视投影中是非线性的,深度值0.5不代表平截头体的中间,实际是很接近近平面的一个位置;这样非线性的深度值给近平面附近的物体提供了很高的精度,远平面出的物体有着较低的精度;片段的深度值随物体离近平面的距离迅速增加,所以大部分物体顶点的深度值都是接近1.0的,所以深度图像一般都偏白色
副作用
  • 深度缓冲在增加了良好的透视效果同时,也有可能会引起不良的副作用,比如出现奇怪的花纹,这种现象叫做深度冲突
  • 避免深度冲突的三个方法:
    1. 不要把多个物体放的太近
    2. 尽可能将近平面设置的远一些
    3. 使用更高精度的深度缓冲
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值