swift - SceneKit – 旋转和动画 SCNNode

标签 swift animation 3d scenekit

我正在尝试显示一个金字塔,该金字塔指向 z 轴,然后也围绕 z 旋转。 因为我的相机在 z 轴上,所以我希望从上方看到金字塔。我设法旋转金字塔以这样查看它,但是当我添加动画时它似乎在多个轴上旋转。

这是我的代码:

// The following create the pyramid and place it how I want
let pyramid = SCNPyramid(width: 1.0, height: 1.0, length: 1.0)
let pyramidNode = SCNNode(geometry: pyramid)
pyramidNode.position = SCNVector3(x: 0, y: 0, z: 0)
pyramidNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: Float(M_PI / 2))
scene.rootNode.addChildNode(pyramidNode)

// But the animation seems to rotate aroun 2 axis and not just z
var spin = CABasicAnimation(keyPath: "rotation")
spin.byValue = NSValue(SCNVector4: SCNVector4(x: 0, y: 0, z: 1, w: 2*Float(M_PI)))
spin.duration = 3
spin.repeatCount = HUGE
pyramidNode.addAnimation(spin, forKey: "spin around")

最佳答案

尝试手动设置和动画相同的属性可能会导致问题。使用 byValue 动画会使问题变得更糟——连接到当前转换,因此更难跟踪当前转换是否是动画期望的开始。

相反,将金字塔的固定方向(它的顶点在 -z 方向)与动画(它围绕它指向的轴旋转)分开。有两种好方法可以做到这一点:

  1. 使 pyramidNode 成为获得一次性旋转(围绕 x 轴的 π/2)的另一个节点的子节点,并将旋转动画直接应用于 pyramidNode。 (在这种情况下,金字塔的顶点仍将指向其局部空间的 +y 方向,因此您需要围绕该轴而不是 z 轴旋转。)

  2. 使用 pivot 属性转换 pyramidNode 内容的局部空间,并使 pyramidNode 相对于其包含空间进行动画处理.

下面是一些代码来展示第二种方法:

let pyramid = SCNPyramid(width: 1.0, height: 1.0, length: 1.0)
let pyramidNode = SCNNode(geometry: pyramid)
pyramidNode.position = SCNVector3(x: 0, y: 0, z: 0)
// Point the pyramid in the -z direction
pyramidNode.pivot = SCNMatrix4MakeRotation(CGFloat(M_PI_2), 1, 0, 0)
scene.rootNode.addChildNode(pyramidNode)

let spin = CABasicAnimation(keyPath: "rotation")
// Use from-to to explicitly make a full rotation around z
spin.fromValue = NSValue(SCNVector4: SCNVector4(x: 0, y: 0, z: 1, w: 0))
spin.toValue = NSValue(SCNVector4: SCNVector4(x: 0, y: 0, z: 1, w: CGFloat(2 * M_PI)))
spin.duration = 3
spin.repeatCount = .infinity
pyramidNode.addAnimation(spin, forKey: "spin around")

一些不相关的更改以提高代码质量:

  • 当需要显式转换以初始化SCNVector 组件时使用CGFloat;专门使用 FloatDouble 会在 32 位或 64 位架构上中断。
  • 使用 .infinity 代替传统的 BSD 数学常量 HUGE。此类型推断出 spin.repeatCount 的类型,并使用为所有浮点类型定义的常量值。
  • 使用 M_PI_2 表示 π/2 的精度。
  • 为动画使用 let 而不是 var,因为我们从不为 spin 分配不同的值。

关于 CGFloat 错误业务的更多信息:在 Swift 中,数字文字没有类型,直到它们所在的表达式需要一个类型。这就是为什么你可以做 spin.duration = 3 这样的事情——即使 duration 是一个浮点值,Swift 允许你传递一个“整数文字”。但是如果你这样做 let d = 3; spin.duration = d 你得到一个错误。为什么?因为变量/常量具有显式类型,而 Swift 不进行隐式类型转换。 3 是无类型的,但是当它被分配给 d 时,类型推断默认选择 Int 因为您没有指定任何其他内容。

如果您看到类型转换错误,您的代码可能混合了文字、常量和/或从函数返回的值。您可以通过将表达式中的所有内容转换为 CGFloat(或者您将该表达式传递给的任何类型)来消除错误。当然,这会使您的代码变得难以阅读和丑陋,所以一旦您开始使用它,您可能会开始一次一个地删除转换,直到找到可以完成工作的那个。

关于swift - SceneKit – 旋转和动画 SCNNode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25295614/

相关文章:

matrix - 转换 2D 图像以模拟 3D 平面上的 3D 投影

ios - SceneKit:如何从 3D 模型中识别和访问人脸?

swift - SceneKit切换场景内存泄漏

ios - 在应用程序中获取当前使用的语言

css - 如何将自动播放(自动移动/自动滑动)添加到 csslider?

Swift:沿路径部分移动 UIImage

ios - 如何查询类并检查键是否为空或值

swift - 在 switch 语句中使用 UIColor

html - CSS3加载动画继承自之前的div

3D 网站和应用程序