我们可以在Scenekit中以编程方式编辑世界空间中的3D对象的比例



我正在与iOS中的Arkit合作,我想减少现实世界中实际对象的大小。使用紧缩手势,我们可以调整对象的大小,但是当我点击时,我想放置尺寸降低的对象。在Scenekit编辑器中,如果我们选择"为世界"的编辑空间,则无法提供缩放选项。那么,是否可以通过编程世界空间中的3D对象编辑比例?

我大约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

是的,这是可能的 - 您可以使用节点的scale参数(node.scale(调整节点的比例。

相关内容

  • 没有找到相关文章

最新更新