You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARKit中如何从4x4变换矩阵获取欧拉角(Swift实现)

在Swift中从4x4变换矩阵提取欧拉角(Pitch/Yaw/Roll)

嘿,我刚好在3D开发里常碰到这个需求,这就给你讲清楚怎么实现!首先得明确:欧拉角的计算完全依赖于旋转顺序(比如最常用的Z-Y-X顺序,对应Yaw-Pitch-Roll的旋转逻辑,很多3D框架默认用这个),不同顺序算出来的角度结果会不一样,下面我就以Z-Y-X顺序为例来写代码,这也是最符合你需求的场景。

核心思路

4x4变换矩阵的左上角3x3子矩阵就是旋转矩阵,我们只需要从这个3x3矩阵里提取角度就行。针对Z-Y-X顺序的旋转,三个欧拉角的定义如下:

  • Yaw(偏航):绕Z轴的旋转角度
  • Pitch(俯仰):绕Y轴的旋转角度
  • Roll(翻滚):绕X轴的旋转角度

代码实现

首先我们可以给SIMD矩阵加个扩展,方便提取旋转矩阵部分,然后写一个计算欧拉角的函数:

import simd

// 定义欧拉角的元组类型,方便返回结果
typealias EulerAngles = (pitch: Float, yaw: Float, roll: Float)

// 给4x4矩阵加扩展,提取左上角的3x3旋转矩阵
extension simd_float4x4 {
    var rotationMatrix: simd_float3x3 {
        simd_float3x3(
            columns: (
                simd_float3(columns.0.x, columns.0.y, columns.0.z),
                simd_float3(columns.1.x, columns.1.y, columns.1.z),
                simd_float3(columns.2.x, columns.2.y, columns.2.z)
            )
        )
    }
}

// 从4x4变换矩阵计算欧拉角(Z-Y-X顺序)
func calculateEulerAngles(from transformMatrix: simd_float4x4) -> EulerAngles {
    let rotationMatrix = transformMatrix.rotationMatrix
    
    // 计算Yaw(Z轴旋转,范围:-π 到 π)
    let yaw = atan2(rotationMatrix[1][0], rotationMatrix[0][0])
    
    // 计算Pitch(Y轴旋转,范围:-π/2 到 π/2),同时处理万向锁问题
    let sinPitch = -rotationMatrix[2][0]
    var pitch: Float
    var roll: Float
    
    if abs(sinPitch) > 0.9999 {
        // 接近万向锁状态(Pitch接近±90度),直接计算Pitch,Roll设为0避免异常
        pitch = .pi / 2 * sinPitch.sign
        roll = 0
    } else {
        pitch = asin(sinPitch)
        // 计算Roll(X轴旋转,范围:-π 到 π)
        roll = atan2(rotationMatrix[2][1], rotationMatrix[2][2])
    }
    
    return (pitch: pitch, yaw: yaw, roll: roll)
}

示例用法

假设你已经有了transform的4x4矩阵,直接调用函数即可,要是需要转成角度(而不是弧度),记得乘以180 / .pi:

// 替换成你的transform矩阵
let targetTransform: simd_float4x4 = ...

let angles = calculateEulerAngles(from: targetTransform)

// 输出弧度值
print("Pitch: \(angles.pitch), Yaw: \(angles.yaw), Roll: \(angles.roll)")

// 转成角度输出
print("Pitch: \(angles.pitch * 180 / .pi)°")
print("Yaw: \(angles.yaw * 180 / .pi)°")
print("Roll: \(angles.roll * 180 / .pi)°")

注意事项

  1. 万向锁问题:当Pitch角度接近±90度时,Yaw和Roll会出现耦合,这时候其中一个角度会失去自由度,代码里已经做了特殊处理避免计算异常。
  2. 旋转顺序:如果你的项目用的不是Z-Y-X顺序(比如X-Y-Z),需要调整矩阵元素的索引来计算,不同顺序的公式不一样,别直接套代码哦!
  3. 弧度 vs 角度:Swift里的三角函数返回的都是弧度,要是需要显示角度,一定要做转换。

内容的提问来源于stack exchange,提问作者Calonca

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:17:38