unity渲染排序
结论
影响渲染排序有这几个
不同相机按深度从小到大排序 > 不透明物体队列在透明物体队列前 > Sorting Layer 从小到大排序 > Order in Layer 从小到大排序 > RenderQueue 从小到大排序 > 深度排序(可能从大到小,也可能从小到大)
相机深度排序
- 这个是最高级别的,深度低的相机永远先渲染
- 应用
模型设为 Layer = Model
头顶血条设为 Layer = Head
相机1设置 CullingMask=Model ,深度 -1
相机2设置 CullingMask=Head,深度0
则相机2后渲染,血条永远不会被模型盖住
不透明物体队列在透明物体队列前
-
注意这里是不透明物体队列,不是不透明物体,不透明物体也可以放在透明物体队列,
只要使用的 shader 采用 “RenderType”=“Opaque”,或材质参数中选择 RenderingMode=Opaque -
不透明物体(材质RenderingMode设置为Opaque),渲染时进行深度比较,离镜头近则覆盖,并且修改深度值
跟其它物体无所谓渲染顺序关系,但所有Opaque物体要最先进行渲染 -
透明物体之间要排序,按离镜头由远到近进行渲染,渲染时进行深度比较,
离镜头近则进行混合,但不改变深度值,所有Transparent物体在Opaque渲染后进行渲染
如果2个Transparent物体有交错,则渲染顺序只跟物体中心点离镜头距离有关系,即使近的物体上的某个点比远的物体
上的某个点还要远,也会先渲染 -
由于物体属于哪个队列由 shader 和材质控制,一般只在写 shader 和 材质时考虑,平时的物体排序不考虑该方案
-
如果存在WorldSpace的Canvas,则把Canvas下的Opaque元素加入到Opaque物体中绘制,
把整个Canvas做为一个透明物体参与Transparent物体的排序,其z值等于所有UI元素中z值最大值和最小值的平均值,
然后当绘制Canvas时按照在Hierarchy窗口中的顺序从上到下来绘制UI元素,跟其z值无关 -
如果 Canvas 要在所有物体最前面,则修改 sortingOrder ,使其在透明物体前,
修改 shader ,忽略深度检测(ZTest Off 或 ZTest Always 这2句效果一样,默认是 ZTest LEqual),
使其在不透明物体前,参考 libs/unity/shader/UIOverlay.shader
如果是修改shader则所有UI元素都得修改显得比较麻烦,有个想法是把 UI 放在最后渲染,然后在 UI 渲染前清除深度值 -
如果存在Sprite物体,按照普通透明3d物体处理
除了相机深度外的影响排序的变量
主要有 SortingLayer,OrderInLayer,RenderQueue 直接用下面的伪代码解释
// 影响因素 OrderLayer > OrderInLayer > RenderQueue > SortFlag
// 下面是推测的排序代码
var sortFunc = (left,right)=>{
// 在 SpriteRenderer 组件上设置的 SortingLayer
// 在 MeshRenderer 组件上要通过代码设置 meshRenderer.sortingLayerName
if ( left.orderLayer != right.orderLayer )
return left.orderLayer < right.orderLayer;
// 在 SpriteRenderer 组件上设置的 OrderInLayer
// 在 MeshRenderer 组件上要通过代码设置 meshRenderer.sortingOrder
if ( left.orderInLayer != right.orderInLayer )
return left.orderInLayer < right.orderInLayer;
// 在 shader 或 材质 中通过 Render Queue 设置
// 注意 shader 的 RenderType 决定了 Render Queue 的取值范围
if ( left.RenderQueue != right.RenderQueue )
return left.RenderQueue < right.RenderQueue;
// sortFlag 取决于 shader 中的 RenderType
// "RenderType"="Opaque" 不透明物体使用 defaultOpaqueSortFlags
// "RenderType"="Transparent" 透明物体使用 CommonTransparent
if ( sortFlag == SortingCriteria.CommonTransparent )
{
// 透明物体按从远到近排序,这样才能正确渲染
return left.distanceToCamera > right.distanceToCamera;
}
else // ( sortFlag == defaultOpaqueSortFlags )
{
// 不透明物体从近到远排序,这样提升效率,
// 因为不透明物体会写入深度,从近到远不影响最终渲染结果
return left.distanceToCamera < right.distanceToCamera;
}
}
- 我们要测试这几个属性对排序的影响时,应该在透明队列中测试,也就是材质的 RenderingMode=Transparent,
不透明队列,物体的排序不影响渲染结果,因为会写入深度,且渲染时会对比深度
透明队列,则物体的排序影响渲染结果,因为只会对比深度,而不会写入深度(不透明物体在透明队列中也一样不写入深度)
应用
- RenderingMode 和 RenderQueue 是材质和 shader 中用来调整层级,一般写 shader 时才用到
相机、orderLayer 和 orderInLayer 是用来逻辑上调整层级,是比较常用的
除了相机,其它变量调整渲染顺序后都会受到不透明物体的深度影响
示例
- 透明物体和不透明物体的交错
- 按离相机从近到远有3个物体 A(透明) B(不透明) C(透明)
显示结果
B 盖住 C, A 盖住 B - 设置 C 的 orderInLayer 为 1,则显示结果
在 B 的范围内,B 盖住 C, A 盖住 B
在 B 的范围外,C 盖住 A
可以看到 A 和 C 会互相穿插,为什么会这样呢
B 先渲染并写入深度
A 接着渲染,盖住 B
C 最后渲染,在 B 的范围内由于 C 的深度比B 大,因此深度测试直接不通过,不渲染
在 B 的范围外 C 会渲染,盖住 A
- 按离相机从近到远有3个物体 A(透明) B(不透明) C(透明)