我正在使用默认的Scenekit游戏项目来尝试实现一些轻击控件以使飞船飞来飞去,这是该项目随附的默认控件。我想弄清楚的是如何旋转我的船的鼻子,以面对屏幕上点击的点。我一直在关注我所见过的所有示例,并提出以下建议:
let point:CGPoint = sender.location(in: sender.view)
let deltaY:Float = Float(point.y) - ship.position.y
let deltaX:Float = Float(point.x) - ship.position.x
let degreesToRadians = Float.pi / 180
let angle = atan2(deltaY, deltaX) + (90 * degreesToRadians)
ship.rotation = SCNVector4(0,1,0,angle)
一些注意事项:
rotation
或position
,两个属性的每个点都显示0
。angle
的计算偏移为0度,这就是为什么我在+ (90 * degreesToRadians)
的计算中进行angle
的原因。当我用手指在船上绕圈旋转时会发生什么情况,即船从0deg-90deg旋转了90度弧。万一我不清楚(或正确),无论我在屏幕上的什么位置,它都会在东西方向之间移动。
最后一件事要注意。我的相机锁定在俯视图上,所以我只想旋转Y轴,这是方向和第一个加载位置的快速屏幕截图:
如果您有任何技巧,想法或知识来发送我的方式,那就太好了。这个问题让我难过。
答案 0 :(得分:2)
越来越近,您的失踪只有几步之遥。
首先在视图坐标中转换水龙头的位置,这与您的代码相同,只是名称不同。
let viewPoint = gestureRecognize.location(in: scnView)
由于视图是2D的,而SCNScene是3D的,因此您需要使用scnView.unprojectPoint
转换为场景坐标。
let camera = cameraNode.camera
let distance = camera.zFar - camera.zNear / cameraNode.position.y
let scenePoint = scnView.unprojectPoint(SCNVector3(viewPoint.x, viewPoint.y, CGFloat(distance)))
然后计算角度。在您的情况下,重要的是您要向下看,所以要使用的轴是X和Z。此外,正X在右边,但正Z在向下,这需要考虑。 / p>
let deltaZ = scenePoint.z - ship.position.z
let deltaX = scenePoint.x - ship.position.x
let angle = atan2(deltaZ, deltaX) - .pi / 2
ship.rotation = SCNVector4(0, -1, 0, angle)
那应该做到。同样不是说,如果您将相机旋转了任何角度(不是90度的倍数),则2D-> 3D转换和角度计算将更加复杂,因为它不像将一个轴视为另一个轴那样简单。
编辑-旋转0/360度边界
您需要检查顺时针旋转还是逆时针旋转需要更多的移动并更新角度。
if abs(angle - .pi * 2 - ship.rotation.w) < abs(angle - ship.rotation.w) {
angle -= .pi * 2
}
此外,我认为四元数可能会自动处理此问题,但我对它们不够熟悉,无法发布解决方案。