将 matrix_float3x3 旋转转换为 SceneKit [英] Converting matrix_float3x3 rotation to SceneKit
问题描述
我正在尝试使用 GameplayKit 的 GKAgent3D 类在场景中移动 SCNNode.我能够使用代理的位置更新 SCNNode,但不能使用旋转.问题是代理的旋转存储为 matrix_float3x3,它与 SceneKit 用于存储旋转信息的任何数据类型都不匹配.
I was experimenting with GameplayKit’s GKAgent3D class to move a SCNNode within a scene. I was able to update the SCNNode with the agent’s position, but not rotation. The issue being the agent’s rotation is stored as a matrix_float3x3, which doesn’t match any of data types SceneKit uses for storing rotational information.
那么我想知道是否有一个简单的函数或方法可以将存储为 matrix_float3x3 的旋转转换为任何 SceneKit 数据类型?
So what I’d like to know is if there’s a simple function or method that could convert a rotation stored as matrix_float3x3 to any SceneKit data types?
推荐答案
为了扩展 @rickster 的答案,这里有一个很好的方法来利用 Swift 中 4x4 矩阵的左上角 3x3,利用扩展的 simd支持 iOS 11/tvOS 11/High Sierra 版本的 SceneKit:
To expand on @rickster 's answer, here's a nice way to take the top-left 3x3 of a 4x4 matrix in Swift, taking advantage of the expanded simd support in the iOS 11/ tvOS 11/ High Sierra version of SceneKit:
extension float4 {
var xyz: float3 {
return float3(x, y, z)
}
init(_ vec3: float3, _ w: Float) {
self = float4(vec3.x, vec3.y, vec3.z, w)
}
}
extension float4x4 {
var upperLeft3x3: float3x3 {
let (a,b,c,_) = columns
return float3x3(a.xyz, b.xyz, c.xyz)
}
init(rotation: float3x3, position: float3) {
let (a,b,c) = rotation.columns
self = float4x4(float4(a, 0),
float4(b, 0),
float4(c, 0),
float4(position, 1))
}
}
然后,要更新您的代理以匹配您节点的方向,您可以编写:
Then, to update your agent to match your node's orientation, you'd write:
agent.rotation = node.simdTransform.upperLeft3x3
或者,如果有问题的节点不在根"级别(如 rootNode 的直接子节点),您可能需要使用节点的 worldTransform:
Or, if the node in question is not at the "root" level (as in, a direct child of the rootNode), you might want to use the node's worldTransform:
agent.rotation = node.simdWorldTransform.upperLeft3x3
如果有问题的节点附加了动态物理体,或者正在使用 SCNTransaction 块进行动画处理,则该节点的呈现节点将更准确地反映其在屏幕上的当前位置:
If the node in question has a dynamic physics body attached, or is being animated with an SCNTransaction block, the node's presentation node will more accurately reflect its current position on screen:
agent.position = node.presentation.simdWorldPosition
agent.rotation = node.presentation.simdWorldTransform.upperLeft3x3
添加了上面的代码,用于向另一个方向移动,移动节点以匹配代理.
added code above for going in the other direction, moving the node to match the agent.
node.simdTransform = float4x4(rotation: agent3d.rotation, position: agent3d.position)
请注意,如果您有一个附加到节点的物理体,如果您要直接修改节点的变换,它应该是 kinematic
而不是 dynamic
这样.
Note that if you have a physics body attached to the node, it should be kinematic
rather than dynamic
if you're going to be directly modifying the node's transform in this way.
这篇关于将 matrix_float3x3 旋转转换为 SceneKit的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!