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的面便会向前或向后偏移一小段距离,这样就能区分谁前谁后了。

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

设置polygonOffsetFactor和 polygonOffsetUnits是有所讲究的:

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

参考文档

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 问题(模型的重叠部位便不停的闪烁起来。这便是Z-Fighting问题)的更多相关文章

  1. threejs 鼠标移动控制模型旋转

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  2. 手把手教你玩转SOCKET模型之重叠I/O篇(上)

    “身为一个初学者,时常能体味到初学者入门的艰辛,所以总是想抽空作点什么来尽我所能的帮助那些需要帮助的人.我也希望大家能把自己的所学和他人一起分享,不要去鄙视别人索取时的贪婪,因为最应该被鄙视的是不肯付 ...

  3. 转:变手把手教你玩转SOCKET模型之重叠I/O篇

    手把手教你玩转SOCKET模型之重叠I/O篇 “身为一个初学者,时常能体味到初学者入门的艰辛,所以总是想抽空作点什么来尽我所能的帮助那些需要帮助的人.我也希望大家能把自己的所学和他人一起分享,不要去鄙 ...

  4. 手把手教你玩转SOCKET模型之重叠I/O篇(下)

    四.     实现重叠模型的步骤 作 了这么多的准备工作,费了这么多的笔墨,我们终于可以开始着手编码了.其实慢慢的你就会明白,要想透析重叠结构的内部原理也许是要费点功夫,但是只是学会 如何来使用它,却 ...

  5. 基于WebGL/Threejs技术的BIM模型轻量化之图元合并

    伴随着互联网的发展,从桌面端走向Web端.移动端必然的趋势.互联网技术的兴起极大地改变了我们的娱乐.生活和生产方式.尤其是HTML5/WebGL技术的发展更是在各个行业内引起颠覆性的变化.随着WebG ...

  6. c++ 网络编程(十) LINUX/windows 异步通知I/O模型与重叠I/O模型 附带示例代码

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9662931.html 一.异步IO模型(asynchronous IO) (1)什么是异步I/ ...

  7. windows 异步通知I/O模型与重叠I/O模型

    一.异步IO模型(asynchronous IO) (1)什么是异步I/O 异步I/O(asynchronous I/O)由POSIX规范定义.演变成当前POSIX规范的各种早起标准所定义的实时函数中 ...

  8. 四.Windows I/O模型之重叠IO(overlapped)模型

    1.适用于除Windows CE之外的各种Windows平台.在使用这个模型之前应该确保该系统安装了Winsock2.重叠模型的基本设计原理是使用一个重叠的数据结构,一次投递一个或多个Winsock ...

  9. Unity 3D 游戏上线之后的流水总结

    原地址:http://tieba.baidu.com/p/2817057297?pn=1 首先.unity 灯光烘焙 :Unity 3D FBX模型导入.选项Model 不导入资源球.Rig 不导入骨 ...

随机推荐

  1. Hibernate学习笔记2.2(Hibernate基础Annotation配置)

    如果数据库表名与类名不一致 可以用使用 @Table(name="_teacher") 来指定表名,没有就会自己创建 也可以在配置文件上修改 为class添加table属性 如果什 ...

  2. 有关于tomcat启动时,利用listener来执行某个方法

    今天,项目经理让我调查一下(目的是锻炼我),刚开始的时候说用listener来实现服务器启动然后某个项目跟着启动.其实就是tomcat启动的时候去执行某个方法,通过这个方法启动某个项目.我网上调查了一 ...

  3. 消息中间件MQ详解及四大MQ比较

    一.消息中间件相关知识 1.概述 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流 ...

  4. 游戏编程模式KeyNote

    [游戏编程模式KeyNote] 1.命令模式. 重做在游戏中并不常见,但重放常见.一种简单的重放实现是记录游戏每帧的状态,这样它可以回放,但那会消耗太多的内存.相反,很多游戏记录每个实体每帧运行的命令 ...

  5. kangle web配置phpmyadmin

    1. kangle安装参考:https://www.kangleweb.com/thread-6001-1-1.html 2. 安装mysql-5.7.22:http://www.cnblogs.co ...

  6. vue 学习1

    .static{ border-radius:4px; } .active { width: 100px; height: 100px; background: green; } .text-dang ...

  7. SpringMVC参考

    史上最简单的 Spring MVC http://blog.csdn.net/column/details/14594.html

  8. 弹出序列(python)

    题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压 ...

  9. Attention Please

    关于BJJ与Matlab的学习时间安排在五六日晚间: 其余一切重心在学术!

  10. 贪吃蛇GamePanel Java实现(二)

    package cn.tcc.snake.tcc.View; import java.awt.Color;import java.awt.Graphics; import javax.swing.JP ...