Z-Buffer

在threejs中,使用深度缓冲(Z-Buffer)来完成场景可见性计算,即确定场景哪部分可见,哪部分不可见。深度缓冲(Z-Buffer)是一个二维数组,其中的每一个元素对应屏幕上的一个像素,如果场景中的两个模型在同一个像素生成渲染结果,那么图形处理卡就会比较二者的深度,并且保留距离观察者较近的物体在该像素点的渲染结果,这样就形成了近的模型遮挡远的模型的结果。

上面说到,深度缓冲(Z-Buffer)是一个二维数组,但是数组的元素类型却可以不同,不同的元素类型代表着不同的精度。这和颜色的精度很像,比如GIF图像最多用8bit保存一个颜色,也即GIF最多支持256种色彩。以此类推,如果深度缓冲的也用8bit来保存一个像素的深度,那就是说该深度缓存只有256个深度级别。在threejs中只实现了一种深度缓冲,但是在例子中,又实现了一个精度更高的深度缓冲——logarithmicdepthbuffer,可以看示例webgl_camera_logarithmicdepthbuffer

Z-Fighting

当场景中的两个模型在同一个像素生成的渲染结果对应到一个相同的深度值时,渲染器就不知道该使用哪个模型的渲染结果了,或者说,不知道哪个面在前,哪个面在后,于是便开始“胡作非为”,这次让这个面在前面,下次让那个面在前面,于是模型的重叠部位便不停的闪烁起来。这便是Z-Fighting问题。

(图片来自:Three.js/WebGL: Large spheres appear broken at intersection)

解决 Z-Fighting

要解决Z-Fighting问题,有两个思路:

  • 让各模型渲染结果不要在同一个像素出现相同深度值
  • 人为设置渲染顺序,这样即使出现相同深度值,也能正确渲染

这里说一下第二种方法为什么也能解决Z-Fighting,比如有两个模型A和B,A的渲染顺序是0,B的渲染顺序是1,既是先渲染A,再渲染B,所以,如果A和B在某个地方出现了相同的深度值,那么后渲染的B会覆盖掉先渲染的A。下面是按照这两个思路提出的一些解决办法。

别让模型靠得那么近

手动设置一定的偏移即可让这个问题解决,比如下面两个例子:

  • 刻度的z值为0,和尺子处于同一平面,会出现z-fighting问题,可以看到刻度文字不停闪烁

    有z-fighting的例子

  • 刻度得z值设置3,和尺子分处不同的平面,无z-fighting问题

    无z-fighting的例子

设置合适的near和far值

在创建相机的时候,会有nearfar两个参数,用来设置相机的近平面和远平面。这个两个参数其实和深度缓冲(Z-Buffer)也密切相关,深度缓冲其实是非线性的,靠近相机的地方精度更高。什么意思呢?假如你的深度缓冲只有10个深度级别,你的相机的near=1,far=100,那么你的深度缓冲可能是这样的:

深度级别 深度范围
0 0~1.0
1 1.0~1.1
3 1.1~1.234
4 1.234~1.325
5 1.325~1.55667
6 1.55667~1.9634
7 1.9634~5.434
8 5.434~23.34834
9 23.34834~99.999

(数据是杜撰的)

这样的非线性深度缓存可能会造成在离相机较远的地方深度等级的划分过于粗糙,比如上面的深度等级9,离相机的距离从23.34834到99.999的面都属于同一个深度级别,从上面可以,两个面对应到同一个深度级别就可能会出现z-fighting,所以,这个深度缓存出现z-fighting的概率还是挺大的。

一般来说,选择一个稍微大一点的near值效果会明显,比如把near从0.1设为1。

参考:【Z-Fighting】【Three.js/WebGL: Large spheres appear broken at intersection】

设置多边形偏移(polygon offset)

threejs 的 material 定义了三个多边形偏移相关的属性:

  • polygonOffset 是否开启多边形偏移
  • polygonOffsetFactor 多边形偏移因子
  • polygonOffsetUnits 多边形偏移单位

当发生两个面深度值相同时,设置了polygonOffset的面便会向前或向后偏移一小段距离,这样就能区分谁前谁后了。

polygonOffsetFactorpolygonOffsetUnits的都是正值时,向远离相机的方向偏移,当两者都是负值时,向靠近相机的地方偏移。

设置polygonOffsetFactorpolygonOffsetUnits是有所讲究的:

  • 当面和近平面(near)、远平面(far)几乎平行的时候,一个很小的偏移就足够,你可以设置polygonOffsetFactor=0, polygonOffsetUnits=1.0
  • 当面和近平面(near)、远平面(far)有一个明显的角度时,这时候就需要一个较大的偏移和一个较小但非零的偏移因子。这是因为要分开两个交叉的面要比分开两个重合的面要更大的偏移。你可以设置如polygonOffsetFactor=0.75, polygonOffsetUnits=4.0

这部分内容很多都来自Z fighting & polygon offset,原文讲得更好点。

设置 render order

threejs的Object3D对象定义了一个renderOrder属性,可以指定对象的渲染顺序,按renderOrder从小到大排列,小的先渲染,大的后渲染。

设置完renderOrder之后,就算两个面有同样的深度,但是因为有渲染顺序,后渲染的面会覆盖掉先渲染的面。也因为这样,设置正确的渲染顺序很重要。

此外,这种方法更经常用在处理元素透明问题上,详见transparent-objects-in-threejs。

使用 logarithmicDepthBuffer 缓冲

缓冲的级别越多,冲突的概率相应的也就越低,所以,我们可以使用一个精度更高的z缓冲,来代替原有的Z缓冲。对于这个方法,threejs官网已经提供了一个例子webgl_camera_logarithmicdepthbuffer。不过,官网的例子为了演示效果,写得比较复杂,实际上只需要将logarithmicDepthBuffer参数设为true即可:

var renderer = new THREE.WebGLRenderer({ logarithmicDepthBuffer: true });

参考文档

1、解释如什么是z-fighting及何用polygon offset
Z fighting & polygon offset

2、讲到了near far 设置的问题
(1)Three.js/WebGL: Large spheres appear broken at intersection

(2)Z-Fighting

3、解释了 depth write的使用
How to use polygonOffset solving Z-fighting poblems

4、讲到了解决透明问题的方法,比较全面
Transparent objects in Threejs

threejs- z-fighting 问题相关推荐

  1. threeJs中镜头拉远导致物体闪烁

    Z-Buffer 在threejs中,使用深度缓冲(Z-Buffer)来完成场景可见性计算,即确定场景哪部分可见,哪部分不可见.深度缓冲(Z-Buffer)是一个二维数组,其中的每一个元素对应屏幕上的 ...

  2. 透视投影,与Z BUFFER求值

    透视投影,与Z BUFFER求值         为什么有透视.因为眼球是个透镜.假如地球生物进化的都靠超声波探测空间,那也许眼睛就不会有变成球,而是其他形状... 为什么有人玩3D头晕?其中一个重要 ...

  3. threejs- z-fighting 问题(模型的重叠部位便不停的闪烁起来。这便是Z-Fighting问题)

    Z-Buffer 在threejs中,使用深度缓冲(Z-Buffer)来完成场景可见性计算,即确定场景哪部分可见,哪部分不可见.深度缓冲(Z-Buffer)是一个二维数组,其中的每一个元素对应屏幕上的 ...

  4. [工作积累] shadow map问题汇总

    1.基本问题和相关 Common Techniques to Improve Shadow Depth Maps: https://msdn.microsoft.com/en-us/library/w ...

  5. R markdown的笔记02

    R markdown的笔记02 1. R Markdown 可以做什么? 3. 文档总体设置 4. 富文本格式 4.1 普通文本 2. 分段 4. 各级标题 5.分隔线 6. RMarkdown 的注 ...

  6. UNREAL ENGINE 4.12 正式发布!下载地址

    UNREAL ENGINE 4.12 正式发布! 下载地址:https://www.unrealengine.com/ Alexander Paschall 在 June 1, 2016 |功能新闻社 ...

  7. Direct3D模板技术

    网络游戏客户端编程 学习目标 1.掌握模板的概念 2.掌握模板的使用方法 3.掌握阴影体的概念 4.掌握实时阴影的技术实现 知识背景 1.掌握D3D程序的基本框架 2.掌握D3D基本图形的绘制 本章要 ...

  8. Real-Time Rendering (10) - 图形硬件及学习小结(Graphics Hardware)

    提要 时代在变,硬件也在变,但一些基本的架构其实根本未变,就像计算机发展了这么多年,还是逃不了几百年前图灵机所定下的:存储器:控制器:运算器,输入设备和输出设备.图形硬件也有自己的套路. 流处理器和R ...

  9. threejs更改z轴朝向问题,拖拽平时视图在xy轴平面

    常规的相机实现代码 // 相机场景 this.camera = new PerspectiveCamera(45, width/height, 1, 10000); this.camera.posit ...

最新文章

  1. 尚硅谷图解Java数据结构和算法一
  2. Linux下C高手成长过程----经典书籍推荐
  3. tushare pro接口_利用tushare获取新闻联播文字稿并制作词云
  4. bootstrap 列表--水平定义列表
  5. IT项目的面向对象分析设计、开发及管理
  6. 【正睿2021寒假省选第二轮集训 day 1】令牌生成 (组合数+二分)
  7. 转Java调用C/C++编写的第三方dll动态链接库(非native API)--- JNI
  8. 华为负一屏Java_干货分享:华为手机负一屏使用设置方法详解,不会的赶紧了解一下...
  9. c# asp.net页面传值方法总结
  10. 【Note2】MPS/PXE/ADS/INA电流电压,i2c设备在位和读,samba/nfs,ntp/log/me/树莓派,pip/office,vr,i2ctool,大数据,pam
  11. SCSI代码分析(3)SCSI设备的管理2
  12. 河北省计算机考试报名的照片要求,「河北省考」河北公务员考试报名照片制作在线处理照片教程...
  13. 怎么linux添加guest,如何为Ubuntu 16.04安装VirtualBox Guest Additions
  14. 什么是编程?为什么要编程?
  15. QT编译时查找不到GL /usr/bin/ld cannot find -lGL
  16. 数学中的术语与常用表达
  17. Canvas流星雨特效
  18. imx6ull驱动开发经验
  19. Pytorch踩坑记之交叉熵(nn.CrossEntropy,nn.NLLLoss,nn.BCELoss的区别和使用)
  20. 滑动过渡之Scroller

热门文章

  1. spring拦截器-过滤器的区别
  2. Android 微信分享
  3. docker 报错 Container is not running
  4. JMeter事务控制器(Transaction controller)
  5. oracle 10 expdp impdp 导入、导出
  6. 【转】store_schema.sql
  7. 【网络爬虫入门04】彻底掌握BeautifulSoup的CSS选择器
  8. POJ 3613 Cow Relays (floyd + 矩阵高速幂)
  9. Python开发之--前端 HTML基础
  10. __bridge,__bridge_retained,__bridge_transfer