autorenew

🎉空间计算 + 人工智能 + iOS = ♾️, Let's visionOS 25 即将到来! 了解更多 →

用渲染排序解决 RealityKit 中的透明物体嵌套问题

透明物体交错

在本文的上篇中,我们通过使用 ModelSortingGroup 控制渲染顺序,解决了三个半透明球体嵌套的显示问题。但是,如果出现更加复杂的情况,仍然会有显示问题,比如克莱因瓶,如果里面装有水的话效果更加复杂:

我们还是用三个小球来演示,在交错的情况下,不指定排序的话,默认情况是下图这样,部分轮廓会随着视角变化消失和出现:

即使指定了物体的排序,只是避免了随着视角变化闪烁的情况,部分轮廓还是会“稳定”的看不见,比如下图中被蓝色球体挡住时,后面的物体轮廓消失了:

对静态模型进行分割处理

如果一个模型是相对固定的,比如克莱因瓶,就可以将内部的交错部分进行切割,让它成为单独的 Mesh,以便进行渲染排序,就可以得到更好的效果。

相信聪明的小伙伴已经想到了,干脆把透明物体分割成一千个或者一万个小零件,不就可以利用渲染引擎自带的方法,直接用中心点按距离排序处理了?

然而这是不可能的,原因:

所以一个复杂的透明模型,最多也就分成 3~5 块进行处理。分割之后,一般情况下我们还是需要用 ModelSortingGroup 进行手动排序,排序原则是:将最小的、最靠近内部的,排在最前面渲染;最大的、最靠近外部的,排在最后面渲染。

运动或动画中

那如果:

这时不管我们怎么改变的渲染顺序,对每一个物体来说,都可能是一部分在前,另一个部分在后,甚至还有一部分在中间。这时候又会出现后渲染的物体消失的情况,我们还是以三个透明球体做为示例,在有动画时很容易出现挡住其他物体轮廓的情况:

那有没有办法来控制不同部分(每个像素)的叠加效果呢?有,这就是下面要讲的内容:Depth Pass

使用 Depth Pass 近似模拟

前面我们讲过,真实世界的半透明颜色叠加公式是:

也就是根据每个像素的深度,分成前景色和背景色进行叠加。Depth Pass 选项,实际是在控制颜色混合策略。当然,改变颜色混合方式肯定会导致最终的颜色与真实世界不一致,但它可以帮我们节约性能开销,以及显示出物体轮廓。

ModelSortingGroup 中提供了三个 Depth Pass,来控制像素级颜色的混合策略,我们用伪代码来进行说明:

let objectList = 指定顺序
var colorInXY = 已有背景颜色
var depthInXY = 已有背景深度

for object in objectList {
  for pixel in object {
    //将 pixel 做为前景色进行处理,depthInXY 实际无用
    colorInXY = pixel.alpha * pixel.color + (1 - pixel.alpha) * colorInXY
  }
}
let objectList = 指定顺序或其他任意顺序,不影响结果
var colorInXY = 已有背景颜色
var depthInXY = 已有背景深度

for object in objectList {
  for pixel in object {
    //比较 depth,将 pixel 颜色直接覆盖
    if pixel.depth < depthInXY {
       colorInXY = pixel.color
       depthInXY = pixel.depth
    } else {
      //丢弃不处理
    }

  }
}
let objectList = 指定顺序
var colorInXY = 已有背景颜色
var depthInXY = 已有背景深度

for object in objectList {
  for pixel in object {
    //比较 depth,将 pixel 颜色根据透明度混合
    if pixel.depth < depthInXY {
       colorInXY = pixel.alpha * pixel.color + (1 - pixel.alpha) * colorInXY
       depthInXY = pixel.depth
    } else {
      //丢弃不处理
    }

  }
}

三种混合策略最终导致的效果也不一样:

三种效果如下图,分别是 Post,Pre,None:

没有银弹,只能权衡选择

受限于渲染引擎的性能,我们只能对透明物体进行一些特殊处理,来模拟现实世界中的真实物体,但不论怎样,都没有完美的选择,最终只能在性能和效果之间权衡选择处理。

像其他的游戏引擎一样,RealityKit 中提供了 ModelSortingGroup 来控制渲染排序,提供了 Depth Pass 来处理颜色混合策略,让大家选择不同的近似策略,希望本文能帮助大家理解原理,更好做出选择。

本文作者

苹果API搬运工