Можем ли мы редактировать масштаб трехмерного объекта в мировом пространстве программно в SceneKit? - PullRequest
0 голосов
/ 03 июля 2019

Я работаю с ARKit в iOS и хочу уменьшить размер реального объекта в реальном мире.С помощью жеста мы можем изменить размер объекта, но когда я нажимаю, я хочу разместить объект с уменьшенным размером.В редакторе SceneKit, если мы выберем пространство для редактирования в мире, опция масштабирования будет недоступна.Так можно ли программно редактировать масштаб трехмерного объекта в мировом пространстве?

1 Ответ

0 голосов
/ 03 июля 2019

Я сделал это около 1,5 года назад.Я не могу обещать, что это все еще работает.Но сначала вы добавляете своих слушателей:

let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(adjustWindow))
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(adjustWindow))
    let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(adjustWindow))
    let tapGesture = UIPanGestureRecognizer(target: self, action: #selector(adjustWindow))
    pinchGesture.cancelsTouchesInView = false
    rotateGesture.cancelsTouchesInView = false
    panGesture.cancelsTouchesInView = false
    tapGesture.cancelsTouchesInView = false
    tapGesture.minimumNumberOfTouches = 2
    sceneView.addGestureRecognizer(panGesture)
    sceneView.addGestureRecognizer(pinchGesture)
    sceneView.addGestureRecognizer(rotateGesture)
    sceneView.addGestureRecognizer(tapGesture)

А затем некоторые для обработки действия:

@objc func adjustWindow(_ gesture: UIGestureRecognizer) {
        // Fetch location for touch in sceneView
        let location: CGPoint = gesture.location(in: sceneView)
        // Fetch targets at the current location
        let hits = self.sceneView.hitTest(location, options: nil)
        // Check if it's a node and it's a window node that has been touched
        guard let node = hits.first?.node, node.name == "window" else {return}

        // Rotate the window if the motion is of the rotation kind
        if let rotateRecognizer = gesture as? UIRotationGestureRecognizer {
            let action = SCNAction.rotateBy(x: 0, y: rotateRecognizer.rotation/200 , z: 0, duration: 0.1)
            node.runAction(action)
            return
        }

        // Make sure user is using 1 finger to move the view
        if gesture.numberOfTouches == 1 {
            switch gesture.state {
            case .failed, .cancelled, .ended:
                startPosition = CGPoint(x: 0, y: 0)
                break
            case .began:
                // Save start position, so that we can check how far the user have moved
                startPosition = location
            case .changed:
                // Fetch new x and y position

                // Note that 1 point is 1 meter and since we want minimal movement we divide it greatly
                let deltaX = Float(location.x-startPosition.x)/400
                let deltaY = Float(location.y-startPosition.y)/20000
                // Transform and apply the new location

                // You can either move the axises of the nodes parents by using "node.scale = SCNVector(x,y,z)"
                // Or you can move the axises of the node itself by transforming the nodes reality as below
                // https://stackoverflow.com/questions/43237805/how-to-move-a-rotated-scnnode-in-scenekit
                let box = node.transform
                let translation = SCNMatrix4MakeTranslation(-deltaX, deltaY, 1)
                let newTrans = SCNMatrix4Mult(translation, box)
                node.transform = newTrans

                node.localTranslate(by: SCNVector3Make(-deltaX, deltaY, 1))
                // Set new location
                startPosition = location
            default:
                break
            }
            // Make sure user is using 2 fingers for scaling the view
        } else if gesture.numberOfTouches == 2, let pinchGesture = gesture as? UIPinchGestureRecognizer {
            switch pinchGesture.state {
            case .began:
                // Save start position, so that we can check how far the user have moved
                startPosition = location
            case .changed:

                // MARK: - Scaling
                // Scaling is unaffected as long as it scales with it's own current value hence we fetch
                // node.scale locations where we want it to be unaffected

                // Scale vertically if user moved more than 4 points

                // https://stackoverflow.com/questions/44850927/scaling-a-scnnode-in-runtime-using-the-pan-gesture
                if abs(location.y-startPosition.y) > 4 {
                    let pinchScaleY: CGFloat = pinchGesture.scale * CGFloat((node.scale.y))
                    node.scale = SCNVector3Make(node.scale.x, Float(pinchScaleY), node.scale.z)
                // Else scale horizontally, if the user moved more than 4 points horizontally
                } else if abs(location.x-startPosition.x) > 4 {
                    let pinchScaleX: CGFloat = pinchGesture.scale * CGFloat((node.scale.x))
                    node.scale = SCNVector3Make(Float(pinchScaleX), node.scale.y, node.scale.z)
                }
                pinchGesture.scale = 1
            default:
                break
            }
        } else if let panGesture = gesture as? UIPanGestureRecognizer, panGesture.numberOfTouches == 2 {
            switch panGesture.state {
            case .failed, .cancelled, .ended:
                startPosition = CGPoint(x: 0, y: 0)
                break
            case .began:
                // Save start position, so that we can check how far the user have moved
                startPosition = location
            case .changed:
                // Fetch new x and y position
                let deltaZ = Float(location.y-startPosition.y)/2000
                // Set new position
                node.position = SCNVector3Make(node.position.x, node.position.y, node.position.z+deltaZ)
                // Set new location
                startPosition = location
            default:
                break
            }
        }
    }

Я знаю, что это содержит код для перемещения узла и его поворота и все.Но зажимающая часть находится посередине: else if gesture.numberOfTouches == 2, let pinchGesture = gesture as? UIPinchGestureRecognizer

...