Machineboy空

RealityKit 입문 - Gestures 본문

언어/swift

RealityKit 입문 - Gestures

안녕도라 2024. 10. 11. 21:16

Tap을 어떻게 감지하는가

import SwiftUI
import RealityKit

struct ContentView : View {
    var body: some View {
        return ARViewContainer().edgesIgnoringSafeArea(.all)
    }
}

struct ARViewContainer: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)
        
        /// 모든 view는 gesture를 가지고 있음
        /// Coordinator = coordinate different kind of delegate functions like in this case and link attempt
        /// action = 어떤 행동을 pass할지
        arView.addGestureRecognizer(UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap)))
        
        context.coordinator.view = arView
        /// events of the view session will be delegated to the coordinator and the coordinator will be responsible
        arView.session.delegate = context.coordinator
        
        let anchor = AnchorEntity(plane: .horizontal)
        
        let box = ModelEntity(mesh: MeshResource.generateBox(size: 0.3), materials: [SimpleMaterial(color: .blue, isMetallic: true)])
        
        box.generateCollisionShapes(recursive: true)
        
        anchor.addChild(box)
        arView.scene.anchors.append(anchor)
        
        return arView
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
}
import Foundation
import ARKit
import RealityKit


class Coordinator: NSObject, ARSessionDelegate {
    
    /// weak 쓰는 이유: we don't really want it to hold a reference or to retain the actual view which is created in the content view
    weak var view: ARView?
    
    /// @objc : when we are registering our handle tap, it uses the selector base registration which is part of the objective-c framework or the objective -c language
    @objc func handleTap(_ recognizer: UITapGestureRecognizer) {
        
        guard let view = self.view else { return }
        
        let tapLocation = recognizer.location(in: view)
        
        /// wall 이나 carpet을 터치하면 modelEntity를 반환하지 않을것
        if let entity = view.entity(at: tapLocation) as? ModelEntity {
            let material = SimpleMaterial(color: UIColor.random(), isMetallic: true)
            entity.model?.materials = [material]
        }
    }
}

Raycasting

1)첫번째 방법 - ARAnchor 생성

import Foundation
import ARKit
import RealityKit


class Coordinator: NSObject, ARSessionDelegate {
    
    /// weak 쓰는 이유: we don't really want it to hold a reference or to retain the actual view which is created in the content view
    weak var view: ARView?
    
    /// @objc : when we are registering our handle tap, it uses the selector base registration which is part of the objective-c framework or the objective -c language
    @objc func handleTap(_ recognizer: UITapGestureRecognizer) {
        
        guard let view = self.view else { return }
        
        let tapLocation = recognizer.location(in: view)
        
        /// raycast: going to allow us to cast Ray from the center of screen
        /// .estimatedPlane : an estimate of how large the plane is
        /// .existingPlaneGeometry: requires a shape and the size
        /// .existingPlaneInfinite : it's a conflict claim which just goes on forever
            
        let results = view.raycast(from: tapLocation, allowing: .estimatedPlane, alignment: .horizontal)
        
        if let result = results.first {
            
            /// ARAnchor with WorldTransform
            /// ARAnchor는 ARKit에 포함되는 거지만 RealityKit에서도 사용할 수 있다.
            let anchor = ARAnchor(name: "Plane Anchor", transform: result.worldTransform)
            view.session.add(anchor: anchor)
            
            let modelEntity = ModelEntity(mesh: MeshResource.generateBox(size: 0.3), materials: [SimpleMaterial(color: .blue, isMetallic: false)])
            modelEntity.generateCollisionShapes(recursive: true)
            
            let anchorEntity = AnchorEntity(anchor: anchor)
            anchorEntity.addChild(modelEntity)
            
            view.scene.addAnchor(anchorEntity)
        }
    }
}

 

2)두번째 방법 -AnchorEntity(raycastResult:) 생성

import SwiftUI
import RealityKit

struct ContentView : View {
    var body: some View {
        return ARViewContainer().edgesIgnoringSafeArea(.all)
    }
}

struct ARViewContainer: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)
        
        /// 모든 view는 gesture를 가지고 있음
        /// Coordinator = coordinate different kind of delegate functions like in this case and link attempt
        /// action = 어떤 행동을 pass할지
        arView.addGestureRecognizer(UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap)))
        
        context.coordinator.view = arView
        
        
       
        return arView
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif
import Foundation
import ARKit
import RealityKit


class Coordinator: NSObject {
    
    /// weak 쓰는 이유: we don't really want it to hold a reference or to retain the actual view which is created in the content view
    weak var view: ARView?
    
    /// @objc : when we are registering our handle tap, it uses the selector base registration which is part of the objective-c framework or the objective -c language
    @objc func handleTap(_ recognizer: UITapGestureRecognizer) {
        
        guard let view = self.view else { return }
        
        let tapLocation = recognizer.location(in: view)
        
        /// raycast: going to allow us to cast Ray from the center of screen
        /// .estimatedPlane : an estimate of how large the plane is
        /// .existingPlaneGeometry: requires a shape and the size
        /// .existingPlaneInfinite : it's a conflict claim which just goes on forever
            
        let results = view.raycast(from: tapLocation, allowing: .estimatedPlane, alignment: .horizontal)
        
        if let result = results.first {
            
            /// AnchorEntity의 내장 raycastResult를 사용하면 ARSessionDelegate가 없어도 됌
            /// ARAnchor을 사용하지 않고 AnchorEntity로 쓰면 됌!
            let anchorEntity = AnchorEntity(raycastResult: result)
            
            let modelEntity = ModelEntity(mesh: MeshResource.generateBox(size: 0.3), materials: [SimpleMaterial(color: .blue, isMetallic: false)])
            modelEntity.generateCollisionShapes(recursive: true)
            

            anchorEntity.addChild(modelEntity)
            
            view.scene.addAnchor(anchorEntity)
        }
    }
}

Scale, Rotate and Moving Virtual Objects

진작에 강의를 들을 걸 그랬다..

view.installGestures(.all, for: modelEntity) 이거 한줄에 내가 고민했던 것들이 모두 구현이 되는구나

 

 

import Foundation
import ARKit
import RealityKit


class Coordinator: NSObject {
    
    /// weak 쓰는 이유: we don't really want it to hold a reference or to retain the actual view which is created in the content view
    weak var view: ARView?
    
    /// @objc : when we are registering our handle tap, it uses the selector base registration which is part of the objective-c framework or the objective -c language
    @objc func handleTap(_ recognizer: UITapGestureRecognizer) {
        
        guard let view = self.view else { return }
        
        let tapLocation = recognizer.location(in: view)
 
        let results = view.raycast(from: tapLocation, allowing: .estimatedPlane, alignment: .horizontal)
        
        if let result = results.first {
            
            /// AnchorEntity의 내장 raycastResult를 사용하면 ARSessionDelegate가 없어도 됌
            /// ARAnchor을 사용하지 않고 AnchorEntity로 쓰면 됌!
            let anchorEntity = AnchorEntity(raycastResult: result)
            
            let modelEntity = ModelEntity(mesh: MeshResource.generateBox(size: 0.3))
            modelEntity.generateCollisionShapes(recursive: true)
            modelEntity.model?.materials = [SimpleMaterial(color: .blue, isMetallic: true)]
            anchorEntity.addChild(modelEntity)
            view.scene.addAnchor(anchorEntity)
            
            view.installGestures(.all, for: modelEntity)
        }
    }
}