Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SceneKit: Diffuse Alpha vs. Transparency / Transparent

I am trying to achieve transparency for a mesh in SceneKit on iOS. I am confused by the documentation as there seem to be multiple ways to make a mesh transparent:

  • Use alpha channel of UIColor via SCNMaterial.(diffuse|emission|ambient|...).contents
  • Use SCNMaterial.transparency (a CGFloat from 0.0 to 1.0)
  • Use SCNMaterial.transparent (another SCNMaterialProperty)
  • Use SCNNode.opacity (a CGFloat from 0.0 (fully transparent) to 1.0 (fully opaque))

Questions:

  • Is there any detailed description of the color math somewhere?
  • What is the common way to add transparency (per object, not via textures/per vertex)?
  • How does SCNMaterial.transparent interact with the other color channels such as diffuse?
  • Is it true that alpha channel must be premultiplied as suggested in https://stackoverflow.com/a/30195543/278842?
like image 956
Christopher Oezbek Avatar asked Jul 09 '17 17:07

Christopher Oezbek


1 Answers

Some of the properties are animatable, some of them apply a value uniformly to the entire object, while others allow you to use an alpha channel texture to control transparency for each point. Applying a value to a node with children allows to set a transparency value for multiple nodes at once.

Diffuse alpha channel

Instead of using a mesh with a high number of vertices, sometimes simple meshes with diffuse textures can be used, see also the example below.

SCNMaterial.transparency

Adjust the opacity uniformly for the whole material. This property is animatable.

SCNMaterial.transparent

Instead of setting a transparency value for the entire material, you can set the opacity for each point individually, usually using a texture.

SCNNode.opacity

Sets the opacity of the whole node and any children.

There is even more control possible:

SCNMaterial.transparencyMode

With the property transparencyMode of a material you can use different modes: .aOne uses the alpha channel, .rgbZero determines the transparency from the color luminance.

Color Math

The color math is determined by the blend mode and is described here:

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

case alpha

Blend by multiplying source and destination color values by their corresponding alpha values.

case add

Blend by adding the source color to the destination color.

case subtract

Blend by subtracting the source color from the destination color.

case multiply

Blend by multiplying the source color with the background color.

case screen

Blend by multiplying the inverse of the source color with the inverse of the destination color.

case replace

Blend by replacing the destination color with the source color, ignoring alpha.

Examples

Trees / Foliage

Instead of using meshes with a high number of vertices, which would result in a noticeable or even unacceptable decrease in the frame rate often transparent diffuse textures can be used. A good example for this are e.g. trees and leaves.

Here you see on the left a transparent texture, in the middle the mesh with a few simple planes and on the right how it looks like when rendered by the SceneKit (Mesh and texture taken from http://www.loopix-project.com).

leaves

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

Glow effect

For different effects one can use blend mode, e.g. to get a kind of glow effect one can use the blendMode .add:

mat.blendMode = .add

Fade in/Fade out

SCNNode.opacity refers to a node including all subnodes. This property is animatable, so if you want to fade in or out a node (or a group of nodes), this is the right way.

You would also use this to apply transparency per object.

Premultiplied alpha vs straight alpha

Internally SceneKit uses premultiplied alpha. So if you are writing shaders you should be aware of this.

If you are only working at the API level, you are not affected, e.g. if you load a.png file with transparency, you do not need to do anything to pre-multiply RGB yourself.

Interaction of e.g. SCNMaterial.transparent with other channels

Transparencies must be able to be used together for different usage scenarios. For example, you want to fade out an object with already partially transparent areas.

Artifical demo example

  • a sphere with some noise texture that has already transparent areas

  • display the sphere with material alpha .75

  • add a second sphere for comparison

The setup:

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)

Now apply a fade out via 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)
}

The result looks like this:

combined transparency

like image 110
Stephan Schlecht Avatar answered Nov 15 '22 13:11

Stephan Schlecht