RealityKit - Как установить прозрачность ModelEntity?
В SceneKit есть много опций, таких как
- Использовать альфа-канал UIColor через
SCNMaterial.(diffuse|emission|ambient|...).contents
- Использовать
SCNMaterial.transparency
(CGFloat от 0,0 до 1,0) - Использовать
SCNMaterial.transparent
(другой SCNMaterialProperty) - Использовать
SCNNode.opacity
(CGFloat от 0,0 (полностью прозрачный) до 1,0 (полностью непрозрачный))
Интересно, есть ли способ установить прозрачность / непрозрачность / альфа для ModelEntity в RealityKit?
3 ответа
На данный момент я вижу в RealityKit как минимум одно решение, позволяющее контролировать прозрачность объекта. Но, честно говоря, это решение работает только для моделей, созданных программно, поэтому вы не можете применять его к моделям, полученным из Reality Composer. Вы можете сделать это, используяbaseColor
или tintColor
свойства экземпляра SimpleMaterial()
:
var tintColor: NSColor { get set } /* color applied to the base color in macOS */
var baseColor: NSColor { get set } /* main (base) color in RealityKit macOS */
Вот как выглядит настоящий код (я тестировал его в macOS):
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)
Или, если вам не нужна текстура на модели (только цвет с непрозрачностью), вы можете управлять прозрачностью через baseColor
свойство экземпляра:
material.baseColor = MaterialColorParameter.color(.init(red: 0.0,
green: 1.0,
blue: 1.0,
alpha: 0.5))
Если ваша сцена содержит объекты обоих типов - созданные в Reality Composer и созданные программно в Xcode, и вы назначаете один и тот же материал обоим объектам, - скомпилированное приложение представляет некоторые артефакты рендеринга (см. Рисунок ниже).
Это связано с нестабильной работой RealityKit (потому что фреймворк пока слишком молодой). Я думаю, что в следующей версии RealityKit такие ошибки, как
missing texture on Reality Composer model
а такжеweird reflection left from sphere
будут устранены.
Используйте следующий код, если вы хотите полную прозрачность для вашего ModelEntity:
let invisibleMaterial = UnlitMaterial(color: .clear)
let tapEntity = ModelEntity(mesh: replaceThisWithYourMesh, materials: [invisibleMaterial])
Объяснение:
Изначально я использовал SimpleMaterial, и ни одно решение не делало объект полностью невидимым. Я просмотрел документацию и обнаружил, что есть еще один материал под названием UnlitMaterial, который идеально подходит для моего варианта использования:
UnlitMaterial: простой материал, который не реагирует на освещение в сцене.
Альтернативно вы также можете использовать OcclusionMaterial, который также скрывает объект за сущностью.
Я нашел несколько способов сделать это.
- Без анимации и проще всего использовать
OcclusionMaterial()
:
let plane = ModelEntity(
mesh: .generatePlane(width: 0.1, depth: 0.1),
materials: [OcculusionMaterial()]
)
изменить прозрачность существующей сущности:
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)
}
}
надеюсь, это кому-то помогло)