Reputation: 141
In SceneKit, there are lots of options such as
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))I wonder if there is a way to set transparency/opacity/alpha for ModelEntity in RealityKit?
Upvotes: 9
Views: 7551
Reputation: 58563
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)
}
}
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).
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
andweird 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.
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
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 4.0
(iOS 18+ | macOS 15+ | visionOS 1+)In RealityKit 4.0, 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)
Upvotes: 17
Reputation: 566
Use the following code if you want full transparency for your ModelEntity:
let invisibleMaterial = UnlitMaterial(color: .clear)
let tapEntity = ModelEntity(mesh: replaceThisWithYourMesh, materials: [invisibleMaterial])
Explanation:
Initially, I was using SimpleMaterial, and no solution was making the entity completely invisible. So I looked at the documentation and it turns out there is another Material called UnlitMaterial that was perfect for my use case:
UnlitMaterial: A simple material that doesn’t respond to lights in the scene.
Alternatively, you can also use the OcclusionMaterial which also hides the object behind the entity.
Upvotes: 0
Reputation: 127
I've found a several ways to do that.
OcclusionMaterial()
:let plane = ModelEntity(
mesh: .generatePlane(width: 0.1, depth: 0.1),
materials: [OcculusionMaterial()]
)
change existing Entity's opacity:
plane.model?.materials = [OcclusionMaterial()]
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 )
Upvotes: -2