我添加了UIRotationGestureRecognizer
并希望使用它来旋转用户选择的节点。
目前,它围绕 z-axis 旋转,如下所示:
private var startingRotation: CGFloat = 0
@objc private func handleRotation(_ rotation: UIRotationGestureRecognizer) {
guard let node = sceneView.hitTest(rotation.location(in: sceneView), options: nil).first?.node else {
return
}
if rotation.state == .began {
startingRotation = CGFloat(node.rotation.w)
}
node.rotation = SCNVector4(0, 0, 1, -Float(startingRotation + rotation.rotation))
}
如果自放置节点后相机未移动,则此方法可正常工作。
但是,如果用户移动到节点的一侧,它将不再在相机所面对的轴上旋转。
如何围绕相机轴旋转?
2 回答
我想我理解你的问题,但你对 Xartec 答案的评论让我对我是否真的有点困惑。
重述:
目标是围绕通过从相机的原点“直接”绘制一条线形成的向量旋转对象。这是垂直于相机平面的矢量,在这种情况下是手机屏幕。此向量是摄像机的-Z 轴。
解
基于我对您的目标的理解,这里是您所需要
说明
真正关键的部分是找出你想要旋转的矢量,幸运的是 SceneKit 提供了非常方便的方法。不幸的是,他们没有提供您需要的所有方法。
首先,您需要代表摄像机前部的矢量(摄像机始终朝向前轴)。
SCNNode.localFront
是-Z 轴(0,0,-1),这只是 SceneKit 中的约定。但是你想要在相机的父坐标系中代表 Z 轴的轴。我发现我经常需要这个,我创建了一个扩展来从SCNNode
获取parentFront
。现在我们有了相机的前轴
要将它转换为目标的参考框架,我们使用convertVector(_,from:)来获取一个可以应用旋转的矢量。首次启动场景时,此方法的结果将是框的-Z 轴(如在静态代码中,但是您使用了 Z 轴并取消了角度)。
为了实现一个附加旋转,这是我不清楚你是否需要的部分,我使用了四元数而不是矢量旋转。基本上,我在手势开始时取框的
orientation
并通过四元数乘法应用旋转。这 2 行:这个数学运算也可以用旋转矢量或变换矩阵来完成,但这是我熟悉的方法。
结果
扩展
简而言之,在旋转对象之前应用相机旋转的反转,然后在旋转后移除相机旋转的反转。
我设置了一个小型 SceneKit 示例项目来获取您想要的行为。它在 Objective C 中,但主要部分(handlePan)应该很容易转换为 Swift:https://github.com/Xartec/ScreenSpaceRotationAndPan
它包括平移以及在屏幕空间中旋转,无论节点的方向和位置如何,无论摄像机的旋转和位置如何,以及 childNode 和直接位于 rootNode 下的节点。