首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android图像处理系列:OpenGL深度测试的应用

Android图像处理系列:OpenGL深度测试的应用

作者头像
天天P图攻城狮
发布2018-11-30 18:53:38
1.5K0
发布2018-11-30 18:53:38
举报
文章被收录于专栏:天天P图攻城狮天天P图攻城狮

什么是深度测试?

深度测试是指检测从某个方向看过去时,两个点A和B谁在谁的前面,以便知道谁挡住了谁,被挡住的点一般不会进行绘制,以达到和真实世界一样的遮挡效果,OpenGL提供了深度测试的能力,开发者不用自己判断哪些被挡住然后不绘制,开启深度测试后,OpenGL会自动帮助我们完成。

在OpenGL中绘制3D物体时,几乎不可避免地要用到深度测试,因为希望绘制的结果像真实世界中的效果那样,前面的物体会挡住后面的物体。

例如绘制一前一后两个正方体,如下图所示,蓝色的在前面,绿色的在后面,按正常的逻辑,前面的会挡住后面的:

而不是像下面这样后面的挡住前面的:

有人可能会说:我先绘制绿色的,再绘制蓝色的不就行了吗?后绘制的会盖在先绘制的上面,就不用深度测试了 对于这个简单的case,是可以的,那么看下面这个case:

一个物体从另外一个物体中穿过,这时自己去算哪些点被遮挡,哪些不被遮挡,然后再自己拼接顶点来绘制?其中的复杂程度简直无法想像。另外,如果要绘制的物体很多呢?物体如果不规则呢?例如3D游戏里的场景,还算得过来吗?而且这还要基于OpenGL摄像机的摆放来算,换一个角度摆放,之前被挡住的可能又可见了,各种case难道都自己计算吗?脑子都要爆炸啦,显然不实现。 不必焦虑,OpenGL自动为我们完成了这一切,而开发者只需要简单地开启深度测试即可。 注意,这里说的深度是从OpenGL摄像机所对着的方向而言的,如下图所示:

离摄像机越近的,深度就越浅,反之越深,摄像机可以认为就是我们的眼睛,我们从一个方向看过来,离我们眼睛越近的东西深度就越浅,反之越深,深度浅的东西就能挡住后面深度深的东西。 小结一下,深度测试就是说OpenGL自动为我们判断所要渲染的东西的前后关系,并按某种规则来实现最后看到的是哪部分,这些说的“某种规则”是可以设置的,通常会设置为让OpenGL渲染出的来最终效果为看到的是深度最浅的部分,这样就把深度较深的部分挡住了,这就是符合真实世界的遮挡效果。 如何做这样的设置,以及还有什么其它的可以设置?下面就来说说。

如何使用深度测试?

下面以Android上的OpenGL ES 2.0为例,来看看相关的方法调用,其它平台的也类似。 要使用深度测试,首先要开启深度测试:

GLES20.glEnable(GLES20.GL_DEPTH_TEST);

开启了深度测试后,OpenGL会在透视除法之后执行深度测试逻辑,具体流程请见下图:

上图中提到了Color Buffer和Depth Buffer

Color Buffer

Color Buffer我们比较熟悉,可以理解为就是当前正在绘制的一个画布,因为绘制是要全都绘制好才更新到屏幕上,比如画一个三角形,并不是画一部分就先显示到屏幕一部分,而是全都画好之后,一次性把画布更新到屏幕上,那么就需要一个Buffer来暂存这些中间的结果。

Depth Buffer

Depth Buffer是用来存储像素对应的深度值,当存在遮挡时,同一个像素就会渲染多次,每次渲染该像素时就会将当前深度值与Depth Buffer中记录的该像素之前的深度值进行比较,然后根据比较的结果做相应的操作。

这里有几点tips:
  • 我们一般情况下是判断正在绘制的像素比Depth Buffer存储的该像素的深度值浅,然后做相应的操作,这里的规则可以控制,控制方法为设置深度比较函数: GLES20.glDepthFunc(GLES20.GL_LESS)

       设置为GLES20.GL_LESS的含义就是“如果正在绘制的像素比Depth Buffer存储的该像素的深度值浅,就执行后续操作”。可设置的func如下:

        GL_NEVER:永不绘制         GL_LESS:如果目标像素z值<当前像素z值,则绘制目标像素         GL_EQUAL:如果目标像素z值=当前像素z值,则绘制目标像素         GL_LEQUAL:如果目标像素z值<=当前像素z值,则绘制目标像素         GL_GREATER :如果目标像素z值>当前像素z值,则绘制目标像素         GL_NOTEQUAL:如果目标像素z值<>当前像素z值,则绘制目标像素         GL_GEQUAL:如果目标像素z值>=当前像素z值,则绘制目标像素         GL_ALWAYS:总是绘制

  • Depth Buffer是可以控制是否可写的,注意,“开启深度测试”和“Depth Buffer可写”是两回事,可以看上面的深度测试逻辑流程图。并不是说开启了深度测试Depth Buffer就是可写的,开启了深度测试,OpenGL就会去做深度测试,至于做完之后,是否允许将新的结果更新到Depth Buffer,可以自己再控制,具体是通过GLES20.glDepthMask()方法来控制,设为true是允许写,否则不允许写。
  • 深度测试和颜色混合同时使用时,注意深度测试不要影响了颜色混合,比如有A、B两个一前一后的物体,A在前,B在后,A带有半透明,B完全不透明,按照深度测试的原理,如果先渲染A,则先对A进行了深度测试,此时在Depth Buffer中存储的对应像素的深度值将是A的深度值,如果此后再渲染B,则会因为B的深度比A的浅,不会将B对应的颜色更新到Color Buffer,从而渲染出来透过半透明的A不能看到后面的B。解决方法可以是先渲染完全不透明的部分,再渲染半透明的部分,并且渲染半透明的部分时,禁止Depth Buffer可写,因为如果Depth Buffer可写,又先渲染了深度浅的半透明部分,那么深度较深的半透明部分也不会被渲染出来,除非将这堆半透明部分排了序从远到近渲染,所以干脆就禁止Depth Buffer可写。

上以简要介绍了OpenGL中深度测试的概念及使用场景,本人水平有限,难免有错误疏漏处,还请大家多多指正,也欢迎大家多多交流,谢谢!

作者简介:kenney, 天天P图 Android 工程师


文章后记: 天天P图是由腾讯公司开发的业内领先的图像处理,相机美拍的APP。欢迎扫码或搜索关注我们的微信公众号:“天天P图攻城狮”,那上面将陆续公开分享我们的技术实践,期待一起交流学习!

加入我们: 天天P图技术团队长期招聘: (1) AND / iOS 开发工程师 (2) 图像处理算法工程师  期待对我们感兴趣或者有推荐的技术牛人加入我们(base 上海)!联系方式:ttpic_dev@qq.com

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-11-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 天天P图攻城狮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何使用深度测试?
    • Color Buffer
      • Depth Buffer
        • 这里有几点tips:
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档