Блокировка объекта на месте после ориентации в AR - PullRequest
0 голосов
/ 08 декабря 2018

Ниже приведен код приложения, в котором пользователь размещает поле и затем ориентирует его по своему вкусу.Я могу добиться этого, однако у меня есть две проблемы.1) Дочерние узлы вращаются вокруг своей оси Y, как мне заставить их вращаться вокруг оси Y родительского узла?2) Как только пользователь сориентирует поле, как я могу нажать его, чтобы зафиксировать его на месте?

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

@IBOutlet var sceneView: ARSCNView!
private var movedField: SCNNode?
private var hud :MBProgressHUD!
var currentAngleY: Float = 0.0
var fieldNode: SCNNode!
var isRotating = false
override func viewDidLoad() {
    super.viewDidLoad()
    self.sceneView.autoenablesDefaultLighting = true
    sceneView.delegate = self
    sceneView.showsStatistics = true
    let scene = SCNScene()
    sceneView.scene = scene

    registerGestureRecognizers()
}
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for     anchor: ARAnchor) {

    if anchor is ARPlaneAnchor {

        DispatchQueue.main.async {
            self.hud = MBProgressHUD.showAdded(to: self.sceneView, animated: true)
            self.hud.label.text = "Detecting Plane..."
            self.hud.label.text = "Plane Detected"
            self.hud.hide(animated: true, afterDelay: 1.0)
        }
    }
}
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Create a session configuration
    let configuration = ARWorldTrackingConfiguration()
    configuration.planeDetection = .horizontal

    // Run the view's session
    sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    // Pause the view's session
    sceneView.session.pause()
}

private func registerGestureRecognizers() {

    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped(recognizer:)))
    tapGestureRecognizer.numberOfTapsRequired = 1
    self.sceneView.addGestureRecognizer(tapGestureRecognizer)

    let pinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(pinched(recognizer:)))
    self.sceneView.addGestureRecognizer(pinchGestureRecognizer)

    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(moveField(recognizer:)))
    panGestureRecognizer.maximumNumberOfTouches = 1
    panGestureRecognizer.minimumNumberOfTouches = 1
    self.sceneView.addGestureRecognizer(panGestureRecognizer)

    let rotateGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(rotateField(recognizer:)))
    rotateGestureRecognizer.maximumNumberOfTouches = 2
    rotateGestureRecognizer.minimumNumberOfTouches = 2
    self.view.addGestureRecognizer(rotateGestureRecognizer)
}

@objc func pinched(recognizer :UIPinchGestureRecognizer) {

    if recognizer.state == .changed {

        guard let sceneView = recognizer.view as? ARSCNView else {
            return
        }
        let touch = recognizer.location(in: sceneView)
        let hitTestResults = self.sceneView.hitTest(touch, options: nil)
        if let hitTest = hitTestResults.first {
            let fieldNode = hitTest.node
            let pinchScaleX = Float(recognizer.scale) * fieldNode.scale.x
            let pinchScaleY = Float(recognizer.scale) * fieldNode.scale.y
            let pinchScaleZ = Float(recognizer.scale) * fieldNode.scale.z
            fieldNode.scale = SCNVector3(pinchScaleX,pinchScaleY,pinchScaleZ)
            recognizer.scale = 1
        }
    }
}

@objc func moveField(recognizer: UIPanGestureRecognizer) {
    if recognizer.state == .began {
        let tapPoint: CGPoint? = recognizer.location(in: sceneView)
        let result = sceneView.hitTest(tapPoint ?? CGPoint.zero, options: nil)
        if result.count == 0 {
            return
        }
        let hitResult: SCNHitTestResult? = result.first
        if (hitResult?.node.name == "Terrain") {
            movedField = hitResult?.node
        } else if (hitResult?.node.parent?.name == "Terrain") {
            movedField = hitResult?.node.parent
        }
        if (movedField != nil) {
        }
    }
    if recognizer.state == .changed {
        if (movedField != nil) {
            let tapPoint: CGPoint? = recognizer.location(in: sceneView)
            let hitResults = sceneView.hitTest(tapPoint ?? CGPoint.zero, types: .featurePoint)
            let result: ARHitTestResult? = hitResults.last
            let matrix: SCNMatrix4 = SCNMatrix4((result?.worldTransform)!)
            //SCNMatrix4FromMat4((result?.worldTransform)!)
            let vector: SCNVector3 = SCNVector3Make(matrix.m41, matrix.m42, matrix.m43)
            movedField?.position = vector
        }
    }
    if recognizer.state == .ended {
        movedField = nil
    }
}

@objc func tapped(recognizer :UITapGestureRecognizer) {
    guard let sceneView = recognizer.view as? ARSCNView else {
        return
    }
    let touch = recognizer.location(in: sceneView)
    let hitTestResults = sceneView.hitTest(touch)
    guard let hitTest = hitTestResults.first?.node else {
        let hitTestResultsWithExistingPlane = sceneView.hitTest(touch, types: .existingPlane)
        let fieldScene = SCNScene(named: "Field.dae")!
        guard let fieldNode = fieldScene.rootNode.childNode(withName:"Terrain", recursively: true) else {
            return
        }
        if let hitTestAvailable = hitTestResultsWithExistingPlane.first {
            fieldNode.position = SCNVector3(hitTestAvailable.worldTransform.columns.3.x,hitTestAvailable.worldTransform.columns.3.y,hitTestAvailable.worldTransform.columns.3.z)
            self.sceneView.scene.rootNode.addChildNode(fieldNode)
            return
        }
        return
    }
    hitTest.removeFromParentNode()
}

@objc func rotateField(recognizer: UIPanGestureRecognizer) {

    let translation = recognizer.translation(in: recognizer.view!)
    var newAngleY = (Float)(translation.x)*(Float)(Double.pi)/180.0
    newAngleY += currentAngleY

    DispatchQueue.main.async {
        self.sceneView.scene.rootNode.enumerateChildNodes { (node, _) in
            node.eulerAngles.y = newAngleY
        }
    }
    if(recognizer.state == .ended) { currentAngleY = newAngleY }

}
}
...