New*_*alp 16 3d animation scenekit swift
我正在尝试显示一个指向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")
Run Code Online (Sandbox Code Playgroud)
ric*_*ter 16
尝试手动设置和动画相同的属性可能会导致问题.使用byValue
动画会使问题变得更糟 - 连接到当前变换,因此更难跟踪当前变换是否是动画期望开始的变换.
相反,将金字塔的固定方向(其顶点在-z方向上)与动画分开(它围绕它指向的轴旋转).有两种好方法可以做到这一点:
使pyramidNode
另一个节点的子节点获得一次性旋转(围绕x轴的π/ 2),并直接应用旋转动画pyramidNode
.(在这种情况下,金字塔的顶点仍将指向其局部空间的+ y方向,因此您需要围绕该轴而不是z轴旋转.)
使用该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")
Run Code Online (Sandbox Code Playgroud)
一些不相关的更改,以提高代码质量:
CGFloat
在初始化SCNVector
组件时需要显式转换时使用; 使用Float
或Double
特别会打破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
(或者将表达式传递给的任何类型)来使错误消失.当然,这会使你的代码变得难以理解和丑陋,所以一旦你开始工作,你可能会开始逐个删除转换,直到找到完成工作的转换为止.
Gra*_*rks 14
SceneKit包含动画助手,它比CAAnimations更简单,更短.这是ObjC,但是可以解决这个问题:
[pyramidNode runAction:
[SCNAction repeatActionForever:
[SCNAction rotateByX:0 y:0 z:2*M_PI duration:3]]];
Run Code Online (Sandbox Code Playgroud)