如何使用手势旋转和缩放 ARKit 模型?
How can I rotate and scale an ARKit model using gestures?
我正在尝试旋转和缩放 ARKit 模型,如 this video:
这是我的代码:
添加手势:
let tapGesure = UITapGestureRecognizer(target: self, action: #selector(handleTap))
sceneView.addGestureRecognizer(tapGesure)
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(moveNode(_:)))
self.view.addGestureRecognizer(panGesture)
let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotateNode(_:)))
self.view.addGestureRecognizer(rotateGesture)
对应的方法如下:
点击手势:
// MARK: - Gesture Recognizers
@objc func handleTap(gesture: UITapGestureRecognizer) {
let location = gesture.location(in: sceneView)
guard let hitTestResult = sceneView.hitTest(location, types: .existingPlane).first else { return }
let position = SCNVector3Make(hitTestResult.worldTransform.columns.3.x,
hitTestResult.worldTransform.columns.3.y,
hitTestResult.worldTransform.columns.3.z)
addFoodModelTo(position: position)
}
使用 UIPanGestureRecognizer
的平移手势:
@objc func moveNode(_ gesture: UIPanGestureRecognizer) {
if !isRotating {
//1. Get The Current Touch Point
let currentTouchPoint = gesture.location(in: self.sceneView)
//2. Get The Next Feature Point Etc
guard let hitTest = self.sceneView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }
//3. Convert To World Coordinates
let worldTransform = hitTest.worldTransform
//4. Set The New Position
let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)
//5. Apply To The Node
baseNode.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)
}
}
旋转手势 UIRotationGestureRecognizer
:
@objc func rotateNode(_ gesture: UIRotationGestureRecognizer){
//1. Get The Current Rotation From The Gesture
let rotation = Float(gesture.rotation)
//2. If The Gesture State Has Changed Set The Nodes EulerAngles.y
if gesture.state == .changed{
isRotating = true
baseNode.eulerAngles.y = currentAngleY + rotation
}
//3. If The Gesture Has Ended Store The Last Angle Of The Cube
if(gesture.state == .ended) {
currentAngleY = baseNode.eulerAngles.y
isRotating = false
}
}
}
但是没用。我做错了什么?
对于旋转手势执行以下方法:
override func viewDidLoad() {
super.viewDidLoad()
let rotationGesture = UIRotationGestureRecognizer(target: self,
action: #selector(rotation))
self.sceneView.addGestureRecognizer(rotationGesture)
}
然后:
let myScene = SCNScene(named: "scene.scn")!
let modelNode: SCNNode = myScene.rootNode
var originalRotation: SCNVector3? = nil
您还可以检查任何重要条件:
private func nodeMethod(at position: CGPoint) -> SCNNode? {
let n = self.sceneView.hitTest(position, options: nil).first(where: {
[=12=].node !== modelNode
})?.node
return n
}
然后:
@objc func rotation(_ gesture: UIRotationGestureRecognizer) {
let location = gesture.location(in: self.sceneView)
guard let node = nodeMethod(at: location)
else {
return
}
switch gesture.state {
case .began:
originalRotation = node.eulerAngles
case .changed:
guard var originalRotation = originalRotation
else {
return
}
originalRotation.y -= Float(gesture.rotation)
node.eulerAngles = originalRotation
default:
originalRotation = nil
}
}
P.S.
检查模型的轴心点位于何处。如果它在模型容器之外,您的模型将不可预测地旋转和缩放。使用以下代码控制枢轴点的位置:
modelNode.simdPivot.columns.3.z = 0.25
另请阅读 Quaternion
与 Euler
旋转 and 。
如果您需要锁定任何轴以进行旋转,请阅读 post。
我正在尝试旋转和缩放 ARKit 模型,如 this video:
这是我的代码:
添加手势:
let tapGesure = UITapGestureRecognizer(target: self, action: #selector(handleTap))
sceneView.addGestureRecognizer(tapGesure)
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(moveNode(_:)))
self.view.addGestureRecognizer(panGesture)
let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotateNode(_:)))
self.view.addGestureRecognizer(rotateGesture)
对应的方法如下:
点击手势:
// MARK: - Gesture Recognizers
@objc func handleTap(gesture: UITapGestureRecognizer) {
let location = gesture.location(in: sceneView)
guard let hitTestResult = sceneView.hitTest(location, types: .existingPlane).first else { return }
let position = SCNVector3Make(hitTestResult.worldTransform.columns.3.x,
hitTestResult.worldTransform.columns.3.y,
hitTestResult.worldTransform.columns.3.z)
addFoodModelTo(position: position)
}
使用 UIPanGestureRecognizer
的平移手势:
@objc func moveNode(_ gesture: UIPanGestureRecognizer) {
if !isRotating {
//1. Get The Current Touch Point
let currentTouchPoint = gesture.location(in: self.sceneView)
//2. Get The Next Feature Point Etc
guard let hitTest = self.sceneView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }
//3. Convert To World Coordinates
let worldTransform = hitTest.worldTransform
//4. Set The New Position
let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)
//5. Apply To The Node
baseNode.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)
}
}
旋转手势 UIRotationGestureRecognizer
:
@objc func rotateNode(_ gesture: UIRotationGestureRecognizer){
//1. Get The Current Rotation From The Gesture
let rotation = Float(gesture.rotation)
//2. If The Gesture State Has Changed Set The Nodes EulerAngles.y
if gesture.state == .changed{
isRotating = true
baseNode.eulerAngles.y = currentAngleY + rotation
}
//3. If The Gesture Has Ended Store The Last Angle Of The Cube
if(gesture.state == .ended) {
currentAngleY = baseNode.eulerAngles.y
isRotating = false
}
}
}
但是没用。我做错了什么?
对于旋转手势执行以下方法:
override func viewDidLoad() {
super.viewDidLoad()
let rotationGesture = UIRotationGestureRecognizer(target: self,
action: #selector(rotation))
self.sceneView.addGestureRecognizer(rotationGesture)
}
然后:
let myScene = SCNScene(named: "scene.scn")!
let modelNode: SCNNode = myScene.rootNode
var originalRotation: SCNVector3? = nil
您还可以检查任何重要条件:
private func nodeMethod(at position: CGPoint) -> SCNNode? {
let n = self.sceneView.hitTest(position, options: nil).first(where: {
[=12=].node !== modelNode
})?.node
return n
}
然后:
@objc func rotation(_ gesture: UIRotationGestureRecognizer) {
let location = gesture.location(in: self.sceneView)
guard let node = nodeMethod(at: location)
else {
return
}
switch gesture.state {
case .began:
originalRotation = node.eulerAngles
case .changed:
guard var originalRotation = originalRotation
else {
return
}
originalRotation.y -= Float(gesture.rotation)
node.eulerAngles = originalRotation
default:
originalRotation = nil
}
}
P.S.
检查模型的轴心点位于何处。如果它在模型容器之外,您的模型将不可预测地旋转和缩放。使用以下代码控制枢轴点的位置:
modelNode.simdPivot.columns.3.z = 0.25
另请阅读 Quaternion
与 Euler
旋转
如果您需要锁定任何轴以进行旋转,请阅读