use*_*652 3 ios uipangesturerecognizer scenekit swift
我创建了一个 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
}
Run Code Online (Sandbox Code Playgroud)
我们有一个 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
}
Run Code Online (Sandbox Code Playgroud)
我们计算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
}
}
Run Code Online (Sandbox Code Playgroud)
我们如何旋转我们的球体?这些函数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)
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下相对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)
}
Run Code Online (Sandbox Code Playgroud)
angle我们从和 中创建一个旋转矩阵,axis并将旧的transform球体与计算出的球体相乘以获得新的transform。
这是我创建的小演示:
这种方法有两个主要缺点。
它仅围绕节点坐标原点旋转,并且仅在节点位置为SCNVector3Zero
它既不考虑手势的速度,也不考虑手势停止时球体继续旋转。使用这种方法很难实现类似于表格视图的效果,您可以翻转手指,表格视图会快速滚动然后减慢速度。一种解决方案是使用物理系统。
| 归档时间: |
|
| 查看次数: |
1993 次 |
| 最近记录: |