Unity3D中的Z-fithgting问题
一、什么是Z-fighting
-
多个对象争夺最接近相机的渲染(争夺顶部)。当对象由于在渲染场景时具有相似的z-buffer值而重叠时,可能会发生这种情况。
-
简单的讲,就是多个平面共面,导致的他们之间相互“打架”,都想让相机先看到自己而产生闪烁,如下图:
-
正常的渲染应如下图:
二、如何解决Z-fighting
1. 在物理上将对象移得更远
- 不推荐,视觉效果差,而且实际工程中也不允许对象的位置发生偏移。
2. 增加相机的近剪裁平面并减少相机的远剪裁平面
- 调整主相机的Clipping Planes中的Near与Far属性
3. 修改Shader深度偏移设置不同对象的渲染顺序
- 在shader中添加
Offset <factor>, <units>
三、示例——基于方法3
-
新建shader脚本:Create->Shader->Stander Surface Shader
-
打开脚本
-
Properties中添加
Properties { _OffsetFactor("Offset Factor", Float) = 0 _OffsetUnits("Offset Units", Float) = 0 }
-
SubShader中添加
SubShader { Offset[_OffsetFactor],[_OffsetUnits] }
-
将shader拖拽到材质球中,点击材质球,在inspector中可以看到
Offset Factor
与Offset Units
属性 -
Offset Factor
与Offset Units
官方介绍中取值为[-1, 1],笔者实际操作发现-2、-3等数值,也可以使用 -
为不同材质球设置不同的
Offset Factor
与Offset Units
,即可解决Z-fighting问题
四、相同材质物体的Z-fighting问题
-
如果发生Z-fighting的物体材质相同,则还需进一步的优化:
-
思路:不同的物体设置不同的
Offset Factor
与Offset Units
-
核心:获取对象
InstanceID
,通过C#代码改变物体材质 -
代码如下:
GameObject obj = new GameObject(); // 获取独一无二的InstanceID int instanceID = obj.GetInstanceID(); // 获取材质 Material _material = obj.GetComponent<MeshRenderer>().material; // 设置材质属性_OffsetFactor与_OffsetUnits _material.SetFloat("_OffsetFactor", instanceID * 0.00002f); _material.SetFloat("_OffsetUnits", instanceID * 0.00002f);
-
优化前:
-
优化后: