我创建了一个SCNSphere所以它现在看起来像一颗行星。这正是我想要的。我的下一个目标是允许用户使用平移手势识别器旋转球体。允许它们围绕X或Y轴旋转它们。我只是想知道如何做到这一点。这是我到目前为止所做的。
origin = sceneView.frame.origin
node.geometry = SCNSphere(radius: 1)
node.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "world.jpg")
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(CategoryViewController.panGlobe(sender:)))
sceneView.addGestureRecognizer(panGestureRecognizer)
func panGlobe(sender: UIPanGestureRecognizer) {
// What should i put inside this method to allow them to rotate the sphere/ball
}
答案 0 :(得分:4)
我们有一个ViewController,它包含一个包含我们球体的节点sphereNode
。
要旋转球体,我们可以使用UIPanGestureRecognizer
。
由于识别器会报告我们的手指在屏幕上移动的总距离,因此我们会缓存报告给我们的最后一点。
var previousPanPoint: CGPoint?
let pixelToAngleConstant: Float = .pi / 180
func handlePan(_ newPoint: CGPoint) {
if let previousPoint = previousPanPoint {
let dx = Float(newPoint.x - previousPoint.x)
let dy = Float(newPoint.y - previousPoint.y)
rotateUp(by: dy * pixelToAngleConstant)
rotateRight(by: dx * pixelToAngleConstant)
}
previousPanPoint = newPoint
}
我们计算dx
和dy
,因为我们上次调用识别器后手指在每个方向上移动了多少像素。
使用pixelToAngleConstant
,我们将角度(在randians中)转换为像素值以旋转我们的球体。使用更大的常数来加快旋转速度。
手势识别器返回state
,我们可以使用它来确定手势是否已开始,已结束或手指是否已移动。
手势开始时,我们将手指位置保存在previousPanPoint
中。
当我们的手指移动时,我们调用上面的函数。
当手势结束或取消时,我们会清除previousPanPoint
。
@objc func handleGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
switch gestureRecognizer.state {
case .began:
previousPanPoint = gestureRecognizer.location(in: view)
case .changed:
handlePan(gestureRecognizer.location(in: view))
default:
previousPanPoint = nil
}
}
我们如何旋转球体?
函数rotateUp
和rotateRight
只调用我们更通用的函数rotate(by: around:)
,它不仅接受角度,还接受旋转的轴。
rotateUp
绕x轴旋转,rotateRight
绕y轴旋转。
func rotateUp(by angle: Float) {
let axis = SCNVector3(1, 0, 0) // x-axis
rotate(by: angle, around: axis)
}
func rotateRight(by angle: Float) {
let axis = SCNVector3(0, 1, 0) // y-axis
rotate(by: angle, around: axis)
}
rotate(by:around:)
在这种情况下相对简单,因为我们假设节点未被翻译/我们想围绕节点局部坐标系的原点旋转。
当我们看一般情况时,一切都有点复杂,但这个答案只是一个很小的起点。
func rotate(by angle: Float, around axis: SCNVector3) {
let transform = SCNMatrix4MakeRotation(angle, axis.x, axis.y, axis.z)
sphereNode.transform = SCNMatrix4Mult(sphereNode.transform, transform)
}
我们从angle
和axis
创建一个旋转矩阵,并将我们球体的旧transform
与计算的一个相乘,得到新的transform
。
这是我创建的小演示:
这种方法有两个主要缺点。
它只围绕节点坐标原点旋转,只有在节点位置为SCNVector3Zero
时才能正常工作
当手势停止时,它既不会考虑手势的速度,也不会继续旋转球体。 使用此方法无法轻松实现类似于桌面视图的效果,您可以在其中翻转手指并快速滚动表格视图然后减速。 一种解决方案是使用物理系统。
答案 1 :(得分:2)
以下是我尝试过的,不确定角度是否准确但是......它足以满足我的大部分需求....
@objc func handleGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
let translation = gestureRecognizer.translation(in: gestureRecognizer.view!)
let x = Float(translation.x)
let y = Float(-translation.y)
let anglePan = (sqrt(pow(x,2)+pow(y,2)))*(Float)(Double.pi)/180.0
var rotationVector = SCNVector4()
rotationVector.x = x
rotationVector.y = y
rotationVector.z = 0.0
rotationVector.w = anglePan
self.earthNode.rotation = rotationVector
}