将matrix_float3x3旋转转换为SceneKit

Phi*_*Phi 6 scenekit

我正在尝试使用GameplayKit的GKAgent3D类来移动场景中的SCNNode.我能够使用代理的位置更新SCNNode,但不能轮换.作为代理程序轮换的问题存储为matrix_float3x3,它与SceneKit用于存储旋转信息的任何数据类型都不匹配.

所以我想知道的是,是否有一个简单的函数或方法可以将存储为matrix_float3x3的旋转转换为任何SceneKit数据类型?

Oli*_*erD 6

为了扩展@rickster的答案,这里有一个很好的方法来利用Swift中4x4矩阵的左上角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))
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,要更新代理以匹配节点的方向,您需要写:

agent.rotation = node.simdTransform.upperLeft3x3
Run Code Online (Sandbox Code Playgroud)

或者,如果有问题的节点不在"根"级别(例如,rootNode的直接子节点),您可能希望使用节点的worldTransform:

agent.rotation = node.simdWorldTransform.upperLeft3x3
Run Code Online (Sandbox Code Playgroud)

编辑:如果相关节点附加了动态物理主体,或者正在使用SCNTransaction块进行动画处理,则节点的表示节点将更准确地反映其在屏幕上的当前位置:

agent.position = node.presentation.simdWorldPosition
agent.rotation = node.presentation.simdWorldTransform.upperLeft3x3
Run Code Online (Sandbox Code Playgroud)

编辑:添加上面的代码以进入另一个方向,移动节点以匹配代理.

node.simdTransform = float4x4(rotation: agent3d.rotation, position: agent3d.position)
Run Code Online (Sandbox Code Playgroud)

请注意,如果您将一个物理主体附加到节点,那么应该是这样,kinematic而不是以dynamic这种方式直接修改节点的变换.


ric*_*ter 5

SceneKit将变换矩阵作为SCNMatrix4,并提供从SIMD转换的实用程序matrix_float4x4:init(_ m: float4x4)用于Swift和SCNMatrix4FromMat4用于ObjC/C++.

遗憾的是,我没有看到在SIMD 3x3和4x4矩阵之间进行转换的内置方法,假设3x3是4x4的左上角.(看起来你期望在SIMD库中,所以值得向Apple提交一个bug.)

但是自己提供一个并不太难:只需使用3x3的三个列向量(填充到float4w组件为零的向量)和第四列(0,0,0,1)的标识,从列向量构造一个4x4 .(实现代码留给读者,部分原因是因为我不想用三种语言编写它.)转换float3x3float4x4你可以转换为SCNMatrix4.


编辑:在iOS 11/tvOS 11/macOS 10.13中(为什么他们也只是调用今年的macOS版本11?),SceneKit有一整套并行的API用于float4x4直接使用SIMD类型; 例如simdTransform.但是,您仍需要将3x3转换为4x4矩阵.