SceneKit:漫反射Alpha与透明度/透明

18

我正试图在 iOS 上的 SceneKit 中实现网格透明度。但是,文档中似乎有多种方法可以使网格透明:

  • 通过 SCNMaterial.(diffuse|emission|ambient|...).contents 使用 UIColor 的 alpha 通道
  • 使用 SCNMaterial.transparency(从0.0到1.0的 CGFloat)
  • 使用 SCNMaterial.transparent(另一个 SCNMaterialProperty)
  • 使用 SCNNode.opacity(从0.0(完全透明)到1.0(完全不透明)的 CGFloat)

问题:

  • 是否有任何关于颜色数学的详细说明?
  • 添加透明度的常见方式是什么(按对象计算,而不是通过纹理/每个顶点)?
  • SCNMaterial.transparent如何与其他颜色通道(如diffuse)交互?
  • 根据https://dev59.com/uYrda4cB1Zd3GeqPPrLX#30195543建议,是否真的必须预乘 alpha 通道?
1个回答

31

一些属性是可动画的,有些应用于整个对象,而其他一些允许您使用alpha通道纹理来控制每个点的透明度。将值应用于具有子节点的节点允许为多个节点设置透明度值。

漫反射Alpha通道

有时候可以使用带有漫反射纹理的简单网格代替顶点数量较高的网格,下面的示例中也可以看到这种情况。

SCNMaterial.transparency

统一调整整个材料的不透明度。此属性是可动画的。

SCNMaterial.transparent

与其为整个材料设置透明度值,不如为每个点分别设置不透明度,通常使用纹理实现。

SCNNode.opacity

设置整个节点及其所有子节点的不透明度。

还有更多的控制方式:

SCNMaterial.transparencyMode

使用材料的transparencyMode属性可以使用不同的模式:.aOne使用alpha通道,.rgbZero从颜色亮度确定透明度。

颜色计算

混合模式决定了颜色计算方式,详见:

https://developer.apple.com/documentation/scenekit/scnblendmode

alpha

通过将源颜色和目标颜色的对应alpha值相乘来混合。

add

通过将源颜色添加到目标颜色来混合。

subtract

通过从目标颜色中减去源颜色来混合。

multiply

通过将源颜色与背景颜色相乘来混合。

screen

通过将源颜色的补数与目标颜色的补数相乘来混合。

replace

用源颜色替换目标颜色,忽略alpha通道。

示例

树木/植被

使用顶点数量较高的网格会导致帧率明显或甚至无法接受的降低,通常可以使用透明的漫反射纹理。一个很好的例子是树木和叶子。

左边是透明的纹理,中间是由几个简单平面组成的网格,右边是SceneKit呈现的效果(网格和纹理取自http://www.loopix-project.com)。

leaves

let mat = SCNMaterial()
mat.diffuse.contents = "palms1.png"
if let geometry = palm.geometry {
    geometry.materials = [mat]
}

发光效果

为了得到不同的效果,可以使用混合模式。例如,要获得一种发光效果,可以使用blendMode .add:

mat.blendMode = .add

渐入/渐出

SCNNode.opacity 属性是指包括所有子节点的节点。该属性可动画化,因此如果您想淡入或淡出一个节点(或一组节点),这是正确的方法。

您也可以使用此属性来对每个对象应用透明度。

预乘 alpha 与直接 alpha

在内部,SceneKit 使用预乘 alpha。因此,如果您正在编写着色器,请注意这一点。

如果您仅在 API 级别上工作,则不受影响,例如,如果您加载带有透明度的 a.png 文件,则无需自行对 RGB 进行预乘。

例如 SCNMaterial.transparent 与其他通道的交互

透明度必须能够在不同的使用情况下一起使用。例如,您想要淡出已经具有部分透明区域的对象。

人造演示示例

  • 带有某些噪音纹理且已具有透明区域的球体

  • 以材质 alpha .75 显示球体

  • 添加第二个球体进行比较

设置:

let sphere1 = SCNSphere(radius: 0.5)
let material1 = SCNMaterial()
material1.diffuse.contents = "art.scnassets/colorTex.png"
material1.transparent.contents = UIColor(red: 1, green: 1, blue: 1, alpha: 0.75)
sphere1.materials = [material1]
let sphereNode1 = SCNNode(geometry: sphere1)
sphereNode1.position = SCNVector3(x: 0, y: -2, z: 0)

let sphere2 = SCNSphere(radius: 0.25)
let sphereNode2 = SCNNode(geometry: sphere2)
sphereNode2.position = SCNVector3(x: 0, y: -0.5, z: 0)

let spheres = SCNNode()
spheres.addChildNode(sphereNode1)
spheres.addChildNode(sphereNode2)
self.scnScene.rootNode.addChildNode(spheres)

现在通过SCNNode.opacity应用淡出效果:

let fadeOut = SCNAction.customAction(duration: 5) { (node, elapsedTime) -> () in
    node.opacity = 1 - elapsedTime / 5
}

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    spheres.runAction(fadeOut)
}
结果看起来是这样的:

combined transparency


很好的回答,唯一需要注意的是,例如树木使用透明纹理并不总是意味着性能提升,许多堆叠层的Alpha测试可能比使用几何制作的完整硬表面树更昂贵,在像Metal这样的前向渲染引擎上Alpha测试是昂贵的。 - Juan Boero

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接