使用手势在 ARSCNView 中移动 SCNNode
Moving SCNNode in ARSCNView using a gesture
我一直在尝试使用 UIPanGestureRecognizer 移动附加到 iOS ARKit 中的 UISceneView 的 SCNNode。它在 x 维度上移动得很好,但我似乎无法弄清楚如何在 y 方向上移动它。我遵循了两种不同的方法,尝试了每一种都没有成功:
How do I find my mouse point in a scene using SceneKit?
如能深入了解为什么 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;
}
}
这里是输出控制台的片段。请注意,计算得出的 "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**
对于平移手势实现以下方法:
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: {
[=11=].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
}
}
我一直在尝试使用 UIPanGestureRecognizer 移动附加到 iOS ARKit 中的 UISceneView 的 SCNNode。它在 x 维度上移动得很好,但我似乎无法弄清楚如何在 y 方向上移动它。我遵循了两种不同的方法,尝试了每一种都没有成功:
How do I find my mouse point in a scene using SceneKit?
如能深入了解为什么 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;
}
}
这里是输出控制台的片段。请注意,计算得出的 "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**
对于平移手势实现以下方法:
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: {
[=11=].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
}
}