iOS ARKit 中的手势检测

     智能移动设备的手势操作是使用者接受并已习惯的操作方式,在移动端 AR 应用中,对虚拟物体的操竹也基本通过手势操作完成,需要注意的是,本次所讲中手势检源是指用户在手机屏幕上的手指操作检测,不是指利用图像技术对使用者手部运动的检测。

    手势检测是指通过检测使用者在手机屏幕上的手指触控运动判断其操作意图的技术,如单击、双击、放、滑动等,ARKit 提供了对触控设备底层 API 的访问权限和高级手势检测功能,可以满足不同的手势定制需要,底层 APTI访问能够获取手指单击的原始位置、压力值、速度信息,高级手势检测功能则借助手勢识别器(Gesture Recognizer)识别预设手势(包括单击、双击、长按、滑动、缩放、平移等)。在AR应用中,对虚拟物体最常见的3种操控方式分别为平移、缩放、旋转,为简化手势使用难度,Reality Kit 使用 installGestures()方法对单物体操控提供快捷支持,该方法的原型为CdiscardableResult func installGestures(_ gestures: ARView. EntityGestures = . all, for entity: HasCoLlision) ->[ EntityGestureRecognizer] 其中,参数 gestures 为 ARView.EntityGestures 枚举类型,用于指定可执行的手势操作,entity 指定需要使用手势操作的实体(Entity)。ARView. EntityGestures 枚举包含 all、rotation、scale、translation 4 个枚举值,涵盖了最常见的旋转、缩放、平移操作。使用 installGestures()方法为 entity 添加手势操作时,entity 需要遵循 HasCollision 协议,简单讲就是虚拟物体必须有碰撞器(CollisionShapes),因为本质上手势操作也首先要用射线检测进行碰撞检查,不带碰撞器的虚拟元素无法参与碰撞检测。在代码清单中,我们创建了一个正方体,然后通过程序的方式生成碰撞器,再调用 installGestures()方法,允许用户对该立方体进行操控。

import SwiftUI
import RealityKit
import ARKit
import Combine

struct GestureControlView : View {
    var body: some View {
        return ARViewContainer6().edgesIgnoringSafeArea(.all)
    }
}

struct ARViewContainer6: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)
        let config = ARWorldTrackingConfiguration()
        config.planeDetection = .horizontal
        arView.session.run(config, options:[ ])
        arView.session.delegate = arView
        arView.createPlane1()
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
    }
}
var cubeEntity1 : ModelEntity?
var gestureStartLocation1: SIMD3<Float>?

extension ARView {
    
    func createPlane1(){
        let planeAnchor = AnchorEntity(plane:.horizontal)
        do {
            let cubeMesh = MeshResource.generateBox(size: 0.1)
            var cubeMaterial = SimpleMaterial(color:.white,isMetallic: false)
            cubeMaterial.color = try SimpleMaterial.BaseColor(tint:UIColor.yellow.withAlphaComponent(0.9999), texture: MaterialParameters.Texture(TextureResource.load(named: "Box_Texture.jpg")))
            cubeEntity1 = ModelEntity(mesh:cubeMesh,materials:[cubeMaterial])
            cubeEntity1!.generateCollisionShapes(recursive: false)
            cubeEntity1?.name = "this is a cube"
            
            planeAnchor.addChild(cubeEntity1!)
            self.scene.addAnchor(planeAnchor)
            self.installGestures(.all,for:cubeEntity1!).forEach{
                     $0.addTarget(self, action: #selector(handleModelGesture1))
                }
        } catch {
            print("找不到文件")
        }
    }
    
   @objc func handleModelGesture1(_ sender: Any) {
       switch sender {
       case let rotation as EntityRotationGestureRecognizer:
         print("Rotation and name :\(rotation.entity!.name)")
         rotation.isEnabled = false
       case let translation as EntityTranslationGestureRecognizer:
         print("translation and name \(translation.entity!.name)")
        
        if translation.state == .ended || translation.state == .cancelled {
            gestureStartLocation1 = nil
            return
        }
        guard let gestureCurrentLocation = translation.entity?.transform.translation else { return }
        guard let _ = gestureStartLocation1 else {
            gestureStartLocation1 = gestureCurrentLocation
            return
        }
         let delta = gestureStartLocation1! - gestureCurrentLocation
         let distance = ((delta.x * delta.x) + (delta.y * delta.y) + (delta.z * delta.z)).squareRoot()
         print("startLocation:\(String(describing: gestureStartLocation1)),currentLocation:\(gestureCurrentLocation),the distance is \(distance)")
          
       case let scale1 as EntityScaleGestureRecognizer:
           if let scale = scale1.entity?.scale{
               cubeEntity1?.scale = scale
           }
       default:
         break
       }
    }

}

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值