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:
SCNMaterial.(diffuse|emission|ambient|...).contents
SCNMaterial.transparency
(a CGFloat from 0.0 to 1.0)SCNMaterial.transparent
(another SCNMaterialProperty)SCNNode.opacity
(a CGFloat from 0.0 (fully transparent) to 1.0 (fully opaque))Questions:
SCNMaterial.transparent
interact with the other color channels such as diffuse
?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).
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With