Machineboy空

RealityKit - TextField에 입력한 글자를 3D Entity로 출력하기! 본문

언어/iOS

RealityKit - TextField에 입력한 글자를 3D Entity로 출력하기!

안녕도라 2024. 11. 11. 22:13

다음은 textField에 입력된 값을 MeshResource.generateText함수를 사용해 3D모델로 만드는 간단한 예제이다!

import SwiftUI
import ARKit
import RealityKit
import Combine

struct ContentView: View {
    @State private var text: String = ""
    
    var body: some View {
        VStack {
            ARViewContainer(text: $text)
                .ignoresSafeArea()
            
            // TextField
            VStack(alignment: .trailing, spacing: 6) {
                TextField("아무거나 입력해보소!", text: $text)
                                .padding()
                                .background(Color.gray.opacity(0.2))
                                .cornerRadius(8)
                                .padding()
            }
            .padding()
        }
    }
}

struct ARViewContainer: UIViewRepresentable {
    @Binding var text: String
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero, cameraMode: .nonAR, automaticallyConfigureSession: false)
        arView.environment.background = .color(.white)
        
        // TextEntity를 붙일 빈 앵커
        let emptyEntity = ModelEntity()
        let emptyAnchor = AnchorEntity(world: [0, 0, 0])
        emptyAnchor.addChild(emptyEntity)
        arView.installGestures([.all], for: emptyEntity)
        arView.scene.anchors.append(emptyAnchor)
        
        context.coordinator.emptyEntity = emptyEntity
        
        // 카메라
        let camera = PerspectiveCamera()
        camera.position = [0, 1, 1]
        
        let cameraAnchor = AnchorEntity(world: [0, 0, 0])
        cameraAnchor.addChild(camera)
        arView.scene.addAnchor(cameraAnchor)
        
        context.coordinator.camera = camera
        
        context.coordinator.cancellable = arView.scene.subscribe(to: SceneEvents.Update.self) { _ in
            camera.look(at: emptyEntity.position, from: camera.position, relativeTo: nil)
        } as? AnyCancellable
        
        return arView
    }
    
    // @binding값으로 호출 업데이트
    func updateUIView(_ uiView: ARView, context: Context) {
        // 텍스트 입력값에 따라 update
        context.coordinator.updateText(text: text)
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
}

class Coordinator: NSObject {
    var emptyEntity: ModelEntity?
    var camera: PerspectiveCamera?
    var textEntity: ModelEntity?
    var cancellable: AnyCancellable?
    
    func updateText(text: String) {
        guard let emptyEntity = emptyEntity else { return }
        // 입력값이 바뀔 때마다 reset해주기 위함
        textEntity?.removeFromParent()
        
        let textMesh = MeshResource.generateText(text, extrusionDepth: 0.03, font: .systemFont(ofSize: 0.15), containerFrame: .zero, alignment: .center, lineBreakMode: .byTruncatingTail)
        let textMaterial = SimpleMaterial(color: .black, isMetallic: true)
        textEntity = ModelEntity(mesh: textMesh, materials: [textMaterial])
        
        if let textEntity = textEntity {
            textEntity.position = [-0.7, 0.2, 0]
            textEntity.generateCollisionShapes(recursive: true)
            emptyEntity.addChild(textEntity)
        }
        
        
    }
}