在 SceneKit 中使用平移手势旋转节点 iOS
Rotate a node using pan gesture in SceneKit iOS
我正在使用以下代码通过平移手势旋转节点。我喜欢只在 y 轴上旋转我的节点。
let translation = gestureRecognize.translation(in: gestureRecognize.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 = 0.0
rotationVector.y = x
rotationVector.z = 0.0
rotationVector.w = anglePan
node.rotation = rotationVector
if(gestureRecognize.state == UIGestureRecognizerState.ended) {
let currentPivot = node.pivot
let changePivot = SCNMatrix4Invert( node.transform)
node.pivot = SCNMatrix4Mult(changePivot, currentPivot)
node.transform = SCNMatrix4Identity
}
这适用于 Euler 设置为 (x: 0, y: 0, z: 0) 的节点。但是我的节点有欧拉(x:-90,y:0,z:0)。对于我上面的欧拉值,代码以错误的角度旋转了对象。如何旋转具有 my/different 欧拉值的节点?[=12=]
旋转矢量应如下所示;
rotation = SCNVector4(x: 0, y: 1, z: 0, w: some_angle_in_radians)
x,y,z 是归一化单位向量
w 以弧度为单位
检查你的数学
let anglePan = (sqrt(pow(x,2)+pow(y,2)))*(Float)(Double.pi)/180.0
可能检查 x,y 的值应该类似于
let anglePan = (sqrt(pow(x*deg2rd,2)+pow(y*deg2rad,2)))
这里是如何做你想做的,这恰好是唯一的方法:
BOOL shouldRotateCube;
- (IBAction)handlePanGesture:(UIPanGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateBegan)
{
shouldRotateCube = TRUE;
} else if (sender.state == UIGestureRecognizerStateChanged && shouldRotateCube
&& fabs([sender translationInView:sender.view].y) > 10.0)
{
shouldRotateCube = FALSE;
[SCNTransaction begin];
[SCNTransaction setCompletionBlock:^{
[SCNTransaction begin];
[SCNTransaction setAnimationDuration:0.15];
SCNVector3 nodeAngles = [node eulerAngles];
[node setEulerAngles:SCNVector3Make(nodeAngles.x + (([sender translationInView:sender.view].y > 0.0) ? degreesToRadians(90) : degreesToRadians(-90)), nodes[i].rotation.y, nodes[i].rotation.z)];
}
[SCNTransaction commit];
}];
[SCNTransaction commit];
}
}
它的工作原理如下:BOOL
用于防止因在设备屏幕上上下滑动手指而导致的多次平移手势调用,因为此特定代码将立方体旋转 90°一个时间。当您开始一个新手势时,它将允许您再次 运行 rotation-related 代码。
translationInView
方法用了两次:一次是为了确保你打算旋转立方体,方法是在旋转立方体之前要求在任一方向上至少保持 10 的距离,第二次是为了确定你是否要旋转立方体正在向上或向下滑动(通过评估翻译值是正数还是负数)。
由于我的立方体只是上下旋转,所以我将 eulerAngles
向量的 (x) 值加上或减去 90° to/from;我将剩余的 eulerAngles
个值放在它们各自的位置。
所有内容都放在 SCNTransaction 中以设置旋转动画并控制旋转动画的持续时间。
我确实尝试过所有其他可用的旋转方法,甚至是 Core Animation 等中的旋转方法——这就是允许您来回旋转立方体等的所有方法,而不会发生奇怪的事情。我有一个使用此代码的应用程序,并且运行良好。如果您无法将其集成到您自己的应用程序中,我很乐意随时将我的应用程序代码转发给您。
我认为你可能把这里需要做的事情复杂化了。
在我的示例中,我创建了一个带有 SCNBox
几何体的 SCNNode
并根据您的示例将其设置为 Euler Angles
:(x: -90, y: 0, z : 0).
您需要做的第一件事是创建一个变量来存储 YAxis 周围的 rotationAngle:
var currentAngleY: Float = 0.0
然后尝试此功能以围绕 YAxis 旋转您的节点(顺便说一下,它工作正常):
/// Rotates An Object On It's YAxis
///
/// - Parameter gesture: UIPanGestureRecognizer
@objc func rotateObject(_ gesture: UIPanGestureRecognizer) {
guard let nodeToRotate = currentNode else { return }
let translation = gesture.translation(in: gesture.view!)
var newAngleY = (Float)(translation.x)*(Float)(Double.pi)/180.0
newAngleY += currentAngleY
nodeToRotate.eulerAngles.y = newAngleY
if(gesture.state == .ended) { currentAngleY = newAngleY }
print(nodeToRotate.eulerAngles)
}
希望对您有所帮助...
我正在使用以下代码通过平移手势旋转节点。我喜欢只在 y 轴上旋转我的节点。
let translation = gestureRecognize.translation(in: gestureRecognize.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 = 0.0
rotationVector.y = x
rotationVector.z = 0.0
rotationVector.w = anglePan
node.rotation = rotationVector
if(gestureRecognize.state == UIGestureRecognizerState.ended) {
let currentPivot = node.pivot
let changePivot = SCNMatrix4Invert( node.transform)
node.pivot = SCNMatrix4Mult(changePivot, currentPivot)
node.transform = SCNMatrix4Identity
}
这适用于 Euler 设置为 (x: 0, y: 0, z: 0) 的节点。但是我的节点有欧拉(x:-90,y:0,z:0)。对于我上面的欧拉值,代码以错误的角度旋转了对象。如何旋转具有 my/different 欧拉值的节点?[=12=]
旋转矢量应如下所示;
rotation = SCNVector4(x: 0, y: 1, z: 0, w: some_angle_in_radians)
x,y,z 是归一化单位向量 w 以弧度为单位
检查你的数学
let anglePan = (sqrt(pow(x,2)+pow(y,2)))*(Float)(Double.pi)/180.0
可能检查 x,y 的值应该类似于
let anglePan = (sqrt(pow(x*deg2rd,2)+pow(y*deg2rad,2)))
这里是如何做你想做的,这恰好是唯一的方法:
BOOL shouldRotateCube;
- (IBAction)handlePanGesture:(UIPanGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateBegan)
{
shouldRotateCube = TRUE;
} else if (sender.state == UIGestureRecognizerStateChanged && shouldRotateCube
&& fabs([sender translationInView:sender.view].y) > 10.0)
{
shouldRotateCube = FALSE;
[SCNTransaction begin];
[SCNTransaction setCompletionBlock:^{
[SCNTransaction begin];
[SCNTransaction setAnimationDuration:0.15];
SCNVector3 nodeAngles = [node eulerAngles];
[node setEulerAngles:SCNVector3Make(nodeAngles.x + (([sender translationInView:sender.view].y > 0.0) ? degreesToRadians(90) : degreesToRadians(-90)), nodes[i].rotation.y, nodes[i].rotation.z)];
}
[SCNTransaction commit];
}];
[SCNTransaction commit];
}
}
它的工作原理如下:BOOL
用于防止因在设备屏幕上上下滑动手指而导致的多次平移手势调用,因为此特定代码将立方体旋转 90°一个时间。当您开始一个新手势时,它将允许您再次 运行 rotation-related 代码。
translationInView
方法用了两次:一次是为了确保你打算旋转立方体,方法是在旋转立方体之前要求在任一方向上至少保持 10 的距离,第二次是为了确定你是否要旋转立方体正在向上或向下滑动(通过评估翻译值是正数还是负数)。
由于我的立方体只是上下旋转,所以我将 eulerAngles
向量的 (x) 值加上或减去 90° to/from;我将剩余的 eulerAngles
个值放在它们各自的位置。
所有内容都放在 SCNTransaction 中以设置旋转动画并控制旋转动画的持续时间。
我确实尝试过所有其他可用的旋转方法,甚至是 Core Animation 等中的旋转方法——这就是允许您来回旋转立方体等的所有方法,而不会发生奇怪的事情。我有一个使用此代码的应用程序,并且运行良好。如果您无法将其集成到您自己的应用程序中,我很乐意随时将我的应用程序代码转发给您。
我认为你可能把这里需要做的事情复杂化了。
在我的示例中,我创建了一个带有 SCNBox
几何体的 SCNNode
并根据您的示例将其设置为 Euler Angles
:(x: -90, y: 0, z : 0).
您需要做的第一件事是创建一个变量来存储 YAxis 周围的 rotationAngle:
var currentAngleY: Float = 0.0
然后尝试此功能以围绕 YAxis 旋转您的节点(顺便说一下,它工作正常):
/// Rotates An Object On It's YAxis
///
/// - Parameter gesture: UIPanGestureRecognizer
@objc func rotateObject(_ gesture: UIPanGestureRecognizer) {
guard let nodeToRotate = currentNode else { return }
let translation = gesture.translation(in: gesture.view!)
var newAngleY = (Float)(translation.x)*(Float)(Double.pi)/180.0
newAngleY += currentAngleY
nodeToRotate.eulerAngles.y = newAngleY
if(gesture.state == .ended) { currentAngleY = newAngleY }
print(nodeToRotate.eulerAngles)
}
希望对您有所帮助...