【问题标题】:Moving SCNNode in ARSCNView using a gesture使用手势在 ARSCNView 中移动 SCNNode
【发布时间】:2020-10-04 04:30:43
【问题描述】:

我一直在尝试使用 UIPanGestureRecognizer 移动附加到 iOS ARKit 中的 UISceneView 的 SCNNode。它在 x 维度上移动得很好,但我似乎无法弄清楚如何在 y 方向上移动它。我遵循了两种不同的方法,每种方法都没有成功:

  1. How do I find my mouse point in a scene using SceneKit?

  2. https://github.com/rajubd49/ARKit-Sample-ObjC

任何关于为什么 y 维度的行为似乎与 x 不同的见解将不胜感激。这可能与仅在 XZ 平面中的运动有关吗?这是上面#2中引用的GitHub示例代码之后的代码):

==============

//移动SCNNode - (void)handlePanGesture:(UIPanGestureRecognizer *)pagr {

switch (pagr.state)
{
    case UIGestureRecognizerStateBegan:
    {
        CGPoint tapPoint    =   [pagr locationInView:sceneView];
        NSLog(@"%s tapPoint  %@",__FUNCTION__,NSStringFromCGPoint(tapPoint));

        NSArray *hitResults = [sceneView hitTest:tapPoint types:ARHitTestResultTypeFeaturePoint | ARHitTestResultTypeEstimatedHorizontalPlane];
        lastHitTestResult   =   [hitResults firstObject];
    }
        break;
    case UIGestureRecognizerStateChanged:
    {
        CGPoint tapPoint            =   [pagr locationInView:sceneView];
        if (windScreenView.buttonState == GypsyTargetAdded)
        {
            NSArray *hitResults         =   [sceneView hitTest:tapPoint types:ARHitTestResultTypeFeaturePoint | ARHitTestResultTypeEstimatedHorizontalPlane];
            ARHitTestResult *result     =   [hitResults lastObject];

            [SCNTransaction begin];

            SCNMatrix4 lastMatrix   =   SCNMatrix4FromMat4(lastHitTestResult.worldTransform);
            SCNVector3 lastVector   =   SCNVector3Make(lastMatrix.m41, lastMatrix.m42, lastMatrix.m43);

            SCNMatrix4 newMatrix    =   SCNMatrix4FromMat4(result.worldTransform);
            SCNVector3 newVector        =   SCNVector3Make(newMatrix.m41, newMatrix.m42, newMatrix.m43);
            CGFloat dx              =   newVector.x-lastVector.x;
            CGFloat dy              =   newVector.y-lastVector.y;
            SCNVector3 adjVector        =   SCNVector3Make(gypsyTargetNode.position.x + dx, gypsyTargetNode.position.y + dy, gypsyTargetNode.position.z);
            gypsyTargetNode.position    =   adjVector;

            [SCNTransaction commit];

            NSLog(@"%s lastVector: x = %f, y = %f, z = %f",__FUNCTION__,lastVector.x,lastVector.y,lastVector.z);
            NSLog(@"%s newVector: x = %f, y = %f, z = %f",__FUNCTION__,newVector.x,newVector.y,newVector.z);
            NSLog(@"%s dx = %f, dy = %f",__FUNCTION__,dx,dy);
            NSLog(@"%s gypsyTargetNode.position: x = %f, y = %f, z = %f",__FUNCTION__,gypsyTargetNode.position.x,gypsyTargetNode.position.y,gypsyTargetNode.position.z);
            NSLog(@"%s hitResults.count: %li",__FUNCTION__,hitResults.count);
            lastHitTestResult       =   result;
        }
    }
        break;
    case UIGestureRecognizerStateEnded:
    {
        lastHitTestResult   =   nil;
    }
        break;
    default:
        break;
}

}

这里是输出控制台的sn-ps。请注意,计算出的 "dx" 始终为 .000000 。

[CalibrationController handlePanGesture:] tapPoint  {207.33332824707031, 507}

[CalibrationController handlePanGesture:] lastVector: x = -0.016018, y = -0.083625, z = 0.006696

[CalibrationController handlePanGesture:] newVector: x = -0.015562, y = -0.083862, z = 0.006658

[CalibrationController handlePanGesture:] dx = 0.000456, dy = **-0.000237**

[CalibrationController handlePanGesture:] gypsyTargetNode.position: x = -0.018142, y = -0.087894, z = 0.008041

[CalibrationController handlePanGesture:] hitResults.count: 2

[CalibrationController handlePanGesture:] lastVector: x = -0.015562, y = -0.083862, z = 0.006658

[CalibrationController handlePanGesture:] newVector: x = -0.015562, y = -0.083862, z = 0.006658

[CalibrationController handlePanGesture:] dx = 0.000000, dy = **0.000000**

[CalibrationController handlePanGesture:] gypsyTargetNode.position: x = -0.018142, y = -0.087894, z = 0.008041

[CalibrationController handlePanGesture:] hitResults.count: 2

[CalibrationController handlePanGesture:] lastVector: x = -0.015562, y = -0.083862, z = 0.006658

[CalibrationController handlePanGesture:] newVector: x = -0.015150, y = -0.083862, z = 0.006565

[CalibrationController handlePanGesture:] dx = 0.000412, dy = **0.000000**

[CalibrationController handlePanGesture:] gypsyTargetNode.position: x = -0.017730, y = -0.087894, z = 0.008041

[CalibrationController handlePanGesture:] hitResults.count: 2

[CalibrationController handlePanGesture:] lastVector: x = -0.015150, y = -0.083862, z = 0.006565

[CalibrationController handlePanGesture:] newVector: x = -0.014686, y = -0.083862, z = 0.006361

[CalibrationController handlePanGesture:] dx = 0.000463, dy = **0.000000**

【问题讨论】:

  • 道歉...意味着“dy”值始终为 0.000000(而不是“dx”)

标签: objective-c swift augmented-reality arkit uipangesturerecognizer


【解决方案1】:

对于平移手势,请执行以下方法:

let myScene = SCNScene(named: "scene.scn")!
let modelNode: SCNNode = myScene.rootNode
var selectedNode: SCNNode? = nil


override func viewDidLoad() {
    super.viewDidLoad()

    let moveGesture = UIPanGestureRecognizer(target: self, 
                                             action: #selector(moveModel))

    self.sceneView.addGestureRecognizer(moveGesture)
}

如果有重要条件,请检查:

private func myMethod(at position: CGPoint) -> SCNNode? {

    let nnn = self.sceneView.hitTest(position, options: nil).first(where: { 
        $0.node !== modelNode 
    })?.node

    return nnn
}

填写一个手势识别器@objc方法:

@objc func moveModel(_ gesture: UIPanGestureRecognizer) {

    let location = gesture.location(in: self.sceneView)

    switch gesture.state {
        case .began:
            selectedNode = myMethod(at: location)
        case .changed:
            guard let result = self.sceneView.hitTest(location, 
                                               types: .existingPlane).first 
            else { 
                return 
            }
            let transform = result.worldTransform
            let newPosition = SIMD3<Float>(transform.columns.3.x, 
                                           transform.columns.3.y, 
                                           transform.columns.3.z)
            selectedNode?.simdPosition = newPosition
        default:
            selectedNode = nil
    }
}

【讨论】:

  • 划界,这有助于解决核心问题。我正在努力查看是否可以使用平移手势来移动节点而无需直接“触摸”节点,因为手指在平移操作期间隐藏了节点图像。希望,我可以在触摸其他地方的同时移动节点。此外,在平移操作期间偶尔会出现可靠性问题,节点“跳出它所附着的表面”,并且似乎悬浮在它所附着的真实对象上方。将发布关于这些问题的任何进展。您认为将节点与 ARAnchor 关联会帮助解决第二个问题吗?
  • stackoverflow.com/users/13699247/demarcate,我尝试使用带有 SCNNode 的 ARAnchor 来实现这个,认为解决方案会更稳定。但我发现它并没有什么不同。如果我将相机从 ARTargetHitPoint 指向环境的其他部分,然后返回指向虚拟对象曾经所在的位置,该对象有时会变得“未连接”并重新连接到 ARTargetHitPoint 和物理相机之间的空间中。所以我不再追求它,因为它增加了不必要的复杂性。
  • 由于跟踪不佳(特征点数量不足、照明条件恶劣、容纳检测到的平面的空间小、没有强大的 6DoF 跟踪等)导致锚定模型不稳定,这就是为什么你有“浮动”模型...
  • 划界,是的,我理解这些问题。我不能依赖 ARPlaneNode 检测,因为我正在测量的平面不大于 25 厘米。当我打开 debugOptions 以显示FeaturePoints 时,它非常有帮助。当检测到一个或多个特征点时,是否有委托或可以使用的东西?我不希望在发布应用程序以供一般使用时启用 debugOption。根据您的经验,实施 ARAnchor 是否会导致更可靠的特征跟踪(与使用没有 ARAnchor 的 SCNnodes 相比)?
  • 是的,与不使用 ARAnchor 放置几何体相比,ARAnchor 的跟踪效果要可靠得多。但是特征点有自己的生活,它们不依赖于锚点。 stackoverflow.com/questions/52893075/what-is-aranchor-exactly/…
猜你喜欢
  • 2021-06-25
  • 2018-03-15
  • 2017-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多