【问题标题】:SceneKit: Diffuse Alpha vs. Transparency / TransparentSceneKit:漫反射 Alpha 与透明度/透明
【发布时间】:2017-12-13 10:23:28
【问题描述】:

我正在尝试在 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 等其他颜色通道交互?
  • Alpha 通道是否必须按照https://stackoverflow.com/a/30195543/278842 中的建议进行预乘?

【问题讨论】:

    标签: ios opengl-es scenekit


    【解决方案1】:

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

    漫反射 Alpha 通道

    有时可以使用带有漫反射纹理的简单网格,而不是使用具有大量顶点的网格,另请参见下面的示例。

    SCNMaterial.transparency

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

    SCNMaterial.transparent

    您可以单独设置每个点的不透明度,而不是为整个材质设置透明度值,通常使用纹理。

    SCNNode.opacity

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

    还有更多可能的控制:

    SCNMaterial.transparencyMode

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

    色彩数学

    颜色数学由混合模式决定,并在此处描述:

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

    案例阿尔法

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

    案例添加

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

    案例减法

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

    大小写相乘

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

    案例屏幕

    通过将源颜色的倒数乘以目标颜色的倒数进行混合。

    大小写替换

    通过将目标颜色替换为源颜色来混合, 忽略阿尔法。

    示例

    树木/树叶

    通常可以使用透明的漫反射纹理,而不是使用具有大量顶点的网格,这会导致帧速率明显下降甚至无法接受。一个很好的例子是例如树木和树叶。

    在这里您可以看到左侧是透明纹理,中间是带有几个简单平面的网格,右侧是 SceneKit 渲染时的样子(网格和纹理取自 http://www.loopix-project.com)。

    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 级别工作,则不会受到影响,例如如果你加载一个透明的.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)
    }
    

    结果如下:

    【讨论】:

    • 很好的答案,我唯一知道的部分是使用透明纹理,例如。树,并不总是意味着性能提升,许多堆积层的 alpha 测试可能比具有所有几何细节的完整硬表面树要昂贵得多,alpha 测试在像 Metal 这样的前向渲染引擎上是昂贵的。
    猜你喜欢
    • 1970-01-01
    • 2019-04-27
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    • 2016-06-01
    • 1970-01-01
    • 2012-01-21
    相关资源
    最近更新 更多