three.js 模型重合相交部分闪烁 Z-Fighting

Z-Fighting

当场景中两个模型在同一个位置时,渲染器会根据它们的深度值来显示前面的模型,隐藏背后的部分。而当他们的位置及深度值相同时,渲染器则不确定哪个将被绘制到颜色缓冲区中,相机旋转时,情况会变得更糟,于是就出现了闪烁现象,这就是“Z-Fighting”

想要解決这个问题,就是要让他们有不同的深度值(下面的主要说这种方法如何实现。)。

或者是手动设置渲染顺序,这样即使在同一位置同一个深度值当中也会将后渲染的覆盖之前的,这种出来的效果类似于设置了css当中的z-index,这种方法不太适用于我的场景,这里暂不做解释,需要的可以自行搜索相关文章。

如何让他们的深度值不同?

渲染器对深度等级的划分和相机的nearfar两个参数是相关的,由于深度级别的个数是有限的,当far/near值太大时,深度等级划分的跨度就可能越大,物体之间更容易被视为同一个深度值,z-buffer准确度就会降低。另外深度缓冲其实是非线性的,靠近相机的地方精度更高,远离相机的地方精度低,也就是说,靠近相机的地方可能一个单位就被划分为一个深度等级,而远离相机的位置可能一百个单位才被划分为一个等级。

所以我们有了两种方法:

1. 增加深度等级数量,使用更高精度的z缓冲,缓冲的级别越多,冲突的概率相应的也就越低,开启这个会影响一定的性能。

renderer = new THREE.WebGLRenderer( { logarithmicDepthBuffer: true } );
//logarithmicDepthBuffer - 是否使用对数深度缓存。如果要在单个场景中处理巨大的比例差异,就有必要使用。 默认是false。

2. 将near值调大,比如将0.1改为1改为10等;也可以尝试将far平面调小一些,但是由于非线性的影响,更改near值可能显得更有效。

var zNear = 0.1;//改为10
camera = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, zNear, 4000);

3. 设置多边形偏移(polygon offset)

WebGL为Z-Fighting问题提供了一个简单的解决方案:多边形偏移。它能够调整模型的深度值,以便可以清楚地确定哪个位于前面(或后面)。在Three.js中,可以在材质中修改这三个参数:

    polygonOffset : Boolean 是否使用多边形偏移,默认值为false

    polygonOffsetFactor : Integer 设置多边形偏移系数,默认值为0

    polygonOffsetUnits : Integer 设置多边形偏移单位,默认值为0

当这两个参数都为负时(深度减小),网格将被拉向摄影机(位于前面)。 当两个参数都为正(增加深度)时,网格会被推离摄影机(会落在后面)。

如何设置这两个参数?

  • 对于平行于近裁剪平面和远裁剪平面的多边形,深度斜率为零。对于场景中深度斜率接近零的多边形,只需要一个小的偏移单位即可,可以设置polygonOffsetFactor=0polygonOffsetUnits=1.0
  • 当面和近平面(near)、远平面(far)有一个明显的角度时,这时候就需要一个较大的偏移量和一个较小但非零的偏移单位(例如0.75或1.0),可能足以生成不同的深度值并消除令人不快的视觉伪像。可以设置如polygonOffsetFactor=0.75polygonOffsetUnits=4.0
  • 参考:https://sites.google.com/site/threejstuts/home/polygon_offset
图源: https://sites.google.com/site/threejstuts/home/polygon_offset
var mesh1 = new THREE.Mesh(new THREE.BoxGeometry(40, 50, 50),
    new THREE.MeshBasicMaterial({
        color: 0xff0000,
    }));
var mesh0 = new THREE.Mesh(new THREE.BoxGeometry(50, 50, 50),
    new THREE.MeshBasicMaterial({
        color: 0x0000ff,
        polygonOffset: true,
        polygonOffsetFactor: 1.0,
        polygonOffsetUnits: 4.0
    }));
this.scene.add(mesh1);
this.scene.add(mesh0);

注:我在使用过程中,使用这个需要把logarithmicDepthBuffer关闭才有效。

另外,在使用多边形偏移这个方法时,虽然效果显著,但可能会涉及到一个问题:鼠标点击得到的对象数组中第一个,和我们在视图上显示出来的不一样。这个解决办法详见:https://blog.csdn.net/sinat_35823840/article/details/112840465

 

4. 实例化网格模型中,实例之间相交部分闪烁

下图中所有几何体都属于一个InstanceMesh中的实例,他们相交部分当颜色不相同时也会出现闪烁问题

这个我暂时没有发现比较好的解决办法,因为我的场景是只有在点击某个实例之后才会改变他们的颜色,在常态下他们的颜色是相同的;

所以我可以在点击时隐藏了这个实例,单独创建一个与该实例大小位置相同的Mesh,使用多边形偏移的材质,与原本的InstanceMesh有了偏移,视觉上就不会出现闪烁了;

详情可见我的这篇文章:https://blog.csdn.net/sinat_35823840/article/details/112884138

而如果你的实例在常态下就是颜色不尽相同,那么我建议你不要将他们都作为一个InstanceMesh渲来染,InstanceMesh本身就是在材质相同、几何体相同的情况下使用的

 

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值