我正在尝试使用 GameplayKit 的 GKAgent3D 类来移动场景中的 SCNNode。我能够使用代理的位置更新 SCNNode,但不能轮换。作为代理程序轮换的问题存储为 matrix_float3x3,它与 SceneKit 用于存储旋转信息的任何数据类型都不匹配。
所以我想知道的是,是否有一个简单的函数或方法可以将存储为 matrix_float3x3 的旋转转换为任何 SceneKit 数据类型?
为了扩展 on @rickster 的答案,这是一个很好的方法来利用 Swift 中 4x4 矩阵的 top-left 3x3,利用 iOS 11/tvOS 11/High Sierra 版本的 SceneKit 中扩展的 simd 支持:
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)) } }
然后,要更新代理以匹配节点的方向,您需要写:
agent.rotation = node.simdTransform.upperLeft3x3
或者,如果有问题的节点不在“根”级别(例如,rootNode 的直接子节点),您可能希望使用节点的 worldTransform:
agent.rotation = node.simdWorldTransform.upperLeft3x3
编辑:如果相关节点附加了动态物理主体,或者正在使用 SCNTransaction 块进行动画处理,则节点的表示节点将更准确地反映其在屏幕上的当前位置:
agent.position = node.presentation.simdWorldPosition agent.rotation = node.presentation.simdWorldTransform.upperLeft3x3
编辑:添加上面的代码以进入另一个方向,移动节点以匹配代理。
node.simdTransform = float4x4(rotation: agent3d.rotation, position: agent3d.position)
请注意,如果您有一个连接到节点的物理主体,如果您要以这种方式直接修改节点的变换,则它应该是kinematic而不是dynamic。
kinematic
dynamic
SceneKit 将变换矩阵作为SCNMatrix4,并提供实用程序,用于从 SIMD matrix_float4x4:init(_ m: float4x4)转换为 Swift,SCNMatrix4FromMat4转换为 ObjC/C。
SCNMatrix4
matrix_float4x4
init(_ m: float4x4)
SCNMatrix4FromMat4
遗憾的是,我没有看到在 SIMD 3x3 和 4x4 矩阵之间进行转换的方法,假设 3x3 是 4x4 的左上角。 (好像你期望在 SIMD 库中,所以它值得向 Apple 提交一个错误 about.)
但是自己提供一个并不太难:只需使用 3x3 的三个列向量(填充到float4向量,w组件为零)和第四列(0,0,0,1)的标识,从列向量构造一个 4x4。 (实现代码留给读者,部分是因为我不想写三个 languages.)将float3x3转换为float4x4之后你可以转换为SCNMatrix4。
float4
w
0,0,0,1
float3x3
float4x4
**编辑:**在 iOS 11/tvOS 11/macOS 10.13 中(为什么他们不只是称今年的 macOS 版本 11?),SceneKit 有一整套并行的 API 用于直接使用float4x4等 SIMD 类型; e.g. simdTransform。但是,您仍需要将 3x3 转换为 4x4 矩阵。
simdTransform
2 回答
为了扩展 on @rickster 的答案,这是一个很好的方法来利用 Swift 中 4x4 矩阵的 top-left 3x3,利用 iOS 11/tvOS 11/High Sierra 版本的 SceneKit 中扩展的 simd 支持:
然后,要更新代理以匹配节点的方向,您需要写:
或者,如果有问题的节点不在“根”级别(例如,rootNode 的直接子节点),您可能希望使用节点的 worldTransform:
编辑:如果相关节点附加了动态物理主体,或者正在使用 SCNTransaction 块进行动画处理,则节点的表示节点将更准确地反映其在屏幕上的当前位置:
编辑:添加上面的代码以进入另一个方向,移动节点以匹配代理。
请注意,如果您有一个连接到节点的物理主体,如果您要以这种方式直接修改节点的变换,则它应该是
kinematic
而不是dynamic
。SceneKit 将变换矩阵作为
SCNMatrix4
,并提供实用程序,用于从 SIMDmatrix_float4x4
:init(_ m: float4x4)
转换为 Swift,SCNMatrix4FromMat4
转换为 ObjC/C。遗憾的是,我没有看到在 SIMD 3x3 和 4x4 矩阵之间进行转换的方法,假设 3x3 是 4x4 的左上角。 (好像你期望在 SIMD 库中,所以它值得向 Apple 提交一个错误 about.)
但是自己提供一个并不太难:只需使用 3x3 的三个列向量(填充到
float4
向量,w
组件为零)和第四列(0,0,0,1
)的标识,从列向量构造一个 4x4。 (实现代码留给读者,部分是因为我不想写三个 languages.)将float3x3
转换为float4x4
之后你可以转换为SCNMatrix4
。**编辑:**在 iOS 11/tvOS 11/macOS 10.13 中(为什么他们不只是称今年的 macOS 版本 11?),SceneKit 有一整套并行的 API 用于直接使用
float4x4
等 SIMD 类型; e.g.simdTransform
。但是,您仍需要将 3x3 转换为 4x4 矩阵。