Динамически изменять текст сущности RealityKit
Я создал очень простую сцену ("SpeechScene"), используя Reality Composer, с одним объектом речевого выноски ("Speech Bubble"), привязанным к Face
якорь.
Я загрузил эту сцену в код следующим образом:
let speechAnchor = try! Experience.loadSpeechScene()
arView.scene.anchors.append(speechAnchor)
let bubble = (arView.scene as? Experience.SpeechScene)?.speechBubble
Он отображается как ожидалось. Однако я хотел бы динамически изменять текст этой существующей сущности.
Я нашел аналогичный вопрос здесь, но непонятно мне, как обратиться кmeshResource
свойство ванили RealityKit.Entity
объект.
Это возможно? Спасибо!
3 ответа
Первый подход
Сначала вам нужно выяснить, что представляет собой иерархия в сцене Reality Composer, содержащая
Bubble Speech
объект. Для этого я использовал простую команду print():
print(textAnchor.swift!.children[0].components.self) /* Bubble Plate */
print(textAnchor.swift!.children[1].components.self) /* Text Object */
Теперь я могу извлечь объект текстовой сущности:
let textEntity: Entity = textAnchor.swift!.children[1].children[0].children[0]
И объект сущности пузырьковой пластины:
let bubbleEntity: Entity = textAnchor.swift!.children[0]
Вот окончательная версия кода, которую вы можете адаптировать под свои нужды:
import RealityKit
class GameViewController: UIViewController {
@IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
let textAnchor = try! SomeText.loadTextScene()
let textEntity: Entity = textAnchor.swift!.children[1].children[0].children[0]
textAnchor.swift!.parent!.scale = [4,4,4] // Scale for both objects
var textModelComp: ModelComponent = (textEntity.components[ModelComponent])!
var material = SimpleMaterial()
material.baseColor = .color(.red)
textModelComp.materials[0] = material
textModelComp.mesh = .generateText("Obj-C",
extrusionDepth: 0.01,
font: .systemFont(ofSize: 0.08),
containerFrame: CGRect(),
alignment: .left,
lineBreakMode: .byCharWrapping)
textEntity.position = [-0.1,-0.05, 0.01]
textAnchor.swift!.children[1].children[0].children[0].components.set(textModelComp)
arView.scene.anchors.append(textAnchor)
}
}
Второй подход
И вы всегда можете использовать более простой подход для этого случая - создать несколько сцен в Reality Composer, каждая из которых должна содержать разные speech-object
.
Учтите, что этот код не для отслеживания, это просто тест для динамического переключения двух объектов с использованием
Tap Gesture
. Затем вам нужно адаптировать этот код для отслеживания лиц.
import RealityKit
class ViewController: UIViewController {
@IBOutlet var arView: ARView!
var counter = 0
var bonjourObject: FaceExperience.Bonjour? = nil
var holaObject: FaceExperience.Hola? = nil
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Reality Composer Scene named "Bonjour"
// Model name – "french"
bonjourObject = try! FaceExperience.loadBonjour()
bonjourObject?.french?.scale = SIMD3(x: 2, y: 2, z: 2)
bonjourObject?.french?.position.y = 0.25
// Reality Composer Scene named "Hola"
// Model name – "spanish"
holaObject = try! FaceExperience.loadHola()
holaObject?.spanish?.scale = SIMD3(x: 2, y: 2, z: 2)
holaObject?.spanish?.position.z = 0.3
}
@IBAction func tapped(_ sender: UITapGestureRecognizer) {
if (counter % 2) == 0 {
arView.scene.anchors.removeAll()
arView.scene.anchors.append(holaObject!)
} else {
arView.scene.anchors.removeAll()
arView.scene.anchors.append(bonjourObject!)
}
counter += 1
}
}
Если вы хотите, чтобы текстовая часть находилась на одном месте - просто скопируйте и вставьте объект из одной сцены в другую.
@maxxfrazer прав в своем утверждении, что в настоящее время единственный способ динамически изменять текст - это заменить ModelComponent
из Entity
при условии, конечно, что он придерживается HasModel Protocol
.
Я написал простое расширение, которое может в этом помочь:
//-------------------------
//MARK: - Entity Extensions
//-------------------------
extension Entity{
/// Changes The Text Of An Entity
/// - Parameters:
/// - content: String
func setText(_ content: String){ self.components[ModelComponent] = self.generatedModelComponent(text: content) }
/// Generates A Model Component With The Specified Text
/// - Parameter text: String
func generatedModelComponent(text: String) -> ModelComponent{
let modelComponent: ModelComponent = ModelComponent(
mesh: .generateText(text, extrusionDepth: TextElements().extrusionDepth, font: TextElements().font,
containerFrame: .zero, alignment: .center, lineBreakMode: .byTruncatingTail),
materials: [SimpleMaterial(color: TextElements().colour, isMetallic: true)]
)
return modelComponent
}
}
//--------------------
//MARK:- Text Elements
//--------------------
/// The Base Setup Of The MeshResource
struct TextElements{
let initialText = "Cube"
let extrusionDepth: Float = 0.01
let font: MeshResource.Font = MeshResource.Font.systemFont(ofSize: 0.05, weight: .bold)
let colour: UIColor = .white
}
Допустим, вы создали Entity
называется textEntity
:
var textEntity = Entity()
Затем вы можете установить динамическое изменение текста, заменив ModelComponent
и установка MeshResource
в любое время, просто вызвав следующий метод:
textEntity.setText("stackru")
Конечно, что касается центрирования или выравнивания текста, вам нужно будет проделать некоторые простые вычисления (которые я здесь опустил).
Надеюсь, это поможет.
Найдите сущность своей модели (возможно, поставив точку останова и сначала просмотрев дочерние элементы), найдите сущность, которая соответствует протоколу HasModel, затем замените ее модель другой с помощью generatetext:
https://developer.apple.com/documentation/realitykit/meshresource/3244422-generatetext