6

In SceneKit, there are lots of options such as

  • 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))

I wonder if there is a way to set transparency/opacity/alpha for ModelEntity in RealityKit?

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Jian Jin
  • 111
  • 1
  • 5

2 Answers2

10

RealityKit 1.0 (iOS | macOS)

There's one solution in RealityKit 1.0 allowing you to control object's transparency. You can do it using baseColor or tintColor instance properties of SimpleMaterial():

 var tintColor: NSColor { get set }
 var baseColor: NSColor { get set }

 var tintColor: UIColor { get set }
 var baseColor: UIColor { get set }

It perfectly works in iOS even with color parameter:

import UIKit
import RealityKit

class GameViewController: UIViewController {
    
    @IBOutlet var arView: ARView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        arView.backgroundColor = .black

        var material = SimpleMaterial()

        material.tintColor = UIColor.init(red: 1.0, 
                                        green: 1.0, 
                                         blue: 1.0, 
                                        alpha: 0.025)

        material.baseColor = MaterialColorParameter.color(UIColor.red)

        let mesh: MeshResource = .generateSphere(radius: 0.7)
        let modelEntity = ModelEntity(mesh: mesh,
                                 materials: [material])
        let anchor = AnchorEntity()
        anchor.addChild(modelEntity)
        arView.scene.anchors.append(anchor)
    }
}

enter image description here

macOS solution (texture example for RealityKit 1.0):

var material = SimpleMaterial()
         
// CYAN TINT and SEMI-TRANSPARENT ALPHA   
material.tintColor = NSColor.init(red: 0.0, green: 1.0, blue: 1.0, alpha: 0.5)

material.baseColor = try! MaterialColorParameter.texture(TextureResource.load(contentsOf: url))
material.roughness = MaterialScalarParameter(floatLiteral: 0.0)
material.metallic = MaterialScalarParameter(floatLiteral: 1.0)
    
// CUBE WAS MADE IN REALITY COMPOSER
cubeComponent.materials = [material]
    
// SPHERE IS MADE PROGRAMMATICALLY
let mesh: MeshResource = .generateSphere(radius: 0.7)

let sphereComponent = ModelComponent(mesh: mesh,
                                materials: [material])

anchor.steelBox!.components.set(cubeComponent)
anchor.components.set(sphereComponent)
arView.scene.anchors.append(anchor)

Or if you do not need any texture on a model (just the color with opacity), you can control transparency via baseColor instance property:

material.baseColor = MaterialColorParameter.color(.init(red: 0.0,
                                                      green: 1.0, 
                                                       blue: 1.0, 
                                                      alpha: 0.5))

If your scene contains both types of objects – that made in Reality Composer and made programmatically in Xcode and you assign the same material to both objects – a compiled app is presenting some rendering artefacts (look at the picture below).

enter image description here

It's due to unstable work of RealityKit (because framework is too young at the moment). I think that in next version of RealityKit such bugs as missing texture on Reality Composer model and weird reflection left from sphere will be eliminated.


RealityKit 2.0 (iOS | macOS)

In RealityKit 2.0 engineers of AR team gave us a .color property instead of .baseColor and .tintColor. These two mentioned are deprecated in iOS 15.

iOS solution (color example for RealityKit 2.0)

var material = SimpleMaterial()

material.color =  .init(tint: .red.withAlphaComponent(0.05), texture: nil)

material.baseColor       // deprecated in iOS 15
material.tintColor       // deprecated in iOS 15

enter image description here

iOS solution (texture example for RealityKit 2.0)

Texture can be applied using the same initializer:

material.color = try! .init(tint: .white.withAlphaComponent(0.9999),
                         texture: .init(.load(named: "mat.png", in: nil)))

Pay particular attention to tint multiplier – you must use 0.9999 value in case your texture has transparent parts.

And HERE you can find how to setup transparency of PhysicallyBasedMaterial.


RealityKit (visionOS)

In RealityKit for visionOS, there's the OpacityComponent with a default opacity parameter = 1.0.

let model = ModelEntity(mesh: .generateSphere(radius: 0.1), 
                   materials: [SimpleMaterial(color: .red, 
                                         isMetallic: true)])

model.components[OpacityComponent.self] = .init(opacity: 0.5)

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • Have you found a way to animate fading? Seems you can create the animation in RealityComposer, but only completely show or completely hide. – ColdLogic Jan 15 '20 at 08:22
  • You should do it in RealityKit, not in Reality Composer. – Andy Jazz Jan 15 '20 at 09:43
  • I agree, but since it's in RealityComposer there has to be a way to do it programatically, which I can't find haha. An Entity conforms to HasTransform, but that will only allow you to animate scale, position, and orientation. Nothing to do with animation of the material for something like fading it in or out. – ColdLogic Jan 15 '20 at 14:15
  • @ColdLogic, please create a new question and publish a link here – I'll try to answer it. – Andy Jazz Jan 15 '20 at 18:54
  • 1
    https://stackoverflow.com/questions/59765252/realitykit-animate-opacity-of-a-modelentity – ColdLogic Jan 16 '20 at 08:04
  • this literally doesn't work at all if you use a simplematerial without a texture when running on iOS in arkit. The material is metallic with no opacity at all – zackify Feb 24 '21 at 15:16
  • 2
    https://twitter.com/MaxxFrazer/status/1364947082981818374?s=20 opacity doesn't work if you are updating the mesh size after the initial creation of the model entity. This is yet another realitykit bug, and the reason i thought your solution didnt work :) fixed the vote for you – zackify Feb 25 '21 at 19:06
  • Hi @zackify, if you wanna discuss any question, please post it here, I don't like twitter)) – Andy Jazz Feb 25 '21 at 19:09
  • Hi, i have been using an image and used as a texture, but i only want to use the image as texture not any color. how can i do i?. tintcolor .clear does clears the mesh – elk_cloner Dec 11 '21 at 17:46
  • Hi @elk_cloner, publish it as a question, I'll answer it. – Andy Jazz Dec 11 '21 at 18:00
  • 1
    @AndyJazz, could you please check this? https://stackoverflow.com/questions/70321744/how-to-show-image-from-gallery-in-realitykit – elk_cloner Dec 12 '21 at 08:05
  • 1
    @AndyJazz About the "weird reflection left from sphere" bug. I have used SimpleMaterial with UIColor.clear & UIColor.clear.withAlphaComponent(0.0) to get a transparent ModelEntity horizontal plane. It is never fully transparent, there is always this "white-like" plane color. When I use the UnlitMaterial then its a "black-like" plane color. This seems to be a bug. Do you know any workarounds (or should I post another q)? – Darkwonder Mar 20 '23 at 14:58
  • Please post a new question, I'll answer it tomorrow. )) – Andy Jazz Mar 20 '23 at 15:03
-2

I've found a several ways to do that.

  1. Without animation and the easiest is to use OcclusionMaterial():
let plane = ModelEntity(
                       mesh: .generatePlane(width: 0.1, depth: 0.1), 
                       materials: [OcculusionMaterial()]
            )

change existing Entity's opacity:

plane.model?.materials = [OcclusionMaterial()]
  1. With animation (you can tweak these snippets for your needs):
var planeColor = UIColor.blue

func fadeOut() {
        runTimer(duration: 0.25) { (percentage) in
            let color = self.planeColor.withAlphaComponent(1 - percentage)
            var material: Material = SimpleMaterial(color: color, isMetallic: false)
            if percentage >= 0.9 {
                material = OcclusionMaterial()
            }
            self.plane.model?.materials = [material]
        }

}

func fadeIn() {
        runTimer(duration: 0.25) { (percentage) in
            let color = self.planeColor.withAlphaComponent(percentage)
            let material: Material = SimpleMaterial(color: color, isMetallic: false)

            self.plane.model?.materials = [material]
        }
}

func runTimer(duration: Double, completion: @escaping (_ percentage: CGFloat) -> Void) {
        let startTime = Date().timeIntervalSince1970
        let endTime = duration + startTime

        Timer.scheduledTimer(withTimeInterval: 1 / 60, repeats: true) { (timer) in
            let now = Date().timeIntervalSince1970

            if now > endTime {
                timer.invalidate()
                return
            }
            let percentage = CGFloat((now - startTime) / duration)
            completion(percentage)

        }
}

hope this helped someone )

Dilshod Turobov
  • 132
  • 2
  • 12