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, который также скрывает объект за сущностью.

Я нашел несколько способов сделать это.

  1. Без анимации и проще всего использоватьOcclusionMaterial():
let plane = ModelEntity(
                       mesh: .generatePlane(width: 0.1, depth: 0.1), 
                       materials: [OcculusionMaterial()]
            )

изменить прозрачность существующей сущности:

plane.model?.materials = [OcclusionMaterial()]
  1. С помощью анимации (вы можете настроить эти фрагменты под свои нужды):
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)

        }
}

надеюсь, это кому-то помогло)

Другие вопросы по тегам