将 matrix_float3x3 旋转转换为 SceneKit [英] Converting matrix_float3x3 rotation to SceneKit

查看:52
本文介绍了将 matrix_float3x3 旋转转换为 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆