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

AGK语言中带缩放的欧拉角与矩阵互转实现求助

XYZ欧拉角与带缩放矩阵互转的AGK实现方案

核心思路

带缩放的变换矩阵是缩放因子与旋转矩阵的结合,要保证互转一致性,需遵循「先缩放后旋转」的变换顺序(对应矩阵运算为 旋转矩阵 × 缩放矩阵),逆过程则先提取缩放因子,再从归一化后的旋转矩阵计算欧拉角。


1. 欧拉角转带缩放矩阵(AGK Basic版)

基于原有纯旋转矩阵代码,在计算旋转元素后乘以对应缩放因子,直接填充到4x4矩阵中:

Function EulerScaleToMatrix(x#, y#, z#, sx#, sy#, sz#, m as Matrix)
    cx# = Cos(x#) : sx_rot# = Sin(x#)
    cy# = Cos(y#) : sy_rot# = Sin(y#)
    cz# = Cos(z#) : sz_rot# = Sin(z#)
    
    ' 旋转矩阵元素 × 对应缩放因子(行主序存储)
    m.m00 = cy*cz * sx# : m.m01 = -cy*sz_rot# * sx# : m.m02 = sy_rot# * sx#
    m.m10 = (sx_rot#*sy_rot#*cz + cx*sz_rot#) * sy# : m.m11 = (-sx_rot#*sy_rot#*sz_rot# + cx*cz) * sy# : m.m12 = (-sx_rot#*cy) * sy#
    m.m20 = (-cx*sy_rot#*cz + sx_rot#*sz_rot#) * sz# : m.m21 = (cx*sy_rot#*sz_rot# + sx_rot#*cz) * sz# : m.m22 = cx*cy * sz#
    
    ' 平移与齐次部分固定为0/1
    m.m03 = 0 : m.m13 = 0 : m.m23 = 0
    m.m30 = 0 : m.m31 = 0 : m.m32 = 0 : m.m33 = 1
EndFunction

2. 矩阵转欧拉角+缩放(AGK Basic版)

先提取缩放因子,再归一化旋转矩阵,最后用原有欧拉角逻辑计算:

Function MatrixToEulerScale(m as Matrix, x#, y#, z#, sx#, sy#, sz#)
    ' 从矩阵列向量提取缩放因子(行主序下,列对应m.m00/m.m10/m.m20等)
    sx# = Sqr(m.m00*m.m00 + m.m10*m.m10 + m.m20*m.m20)
    sy# = Sqr(m.m01*m.m01 + m.m11*m.m11 + m.m21*m.m21)
    sz# = Sqr(m.m02*m.m02 + m.m12*m.m12 + m.m22*m.m22)
    
    ' 避免除零误差
    if sx# < 0.0001 then sx# = 0.0001
    if sy# < 0.0001 then sy# = 0.0001
    if sz# < 0.0001 then sz# = 0.0001
    
    ' 归一化旋转矩阵(去除缩放影响)
    r00# = m.m00 / sx# : r01# = m.m01 / sy# : r02# = m.m02 / sz#
    r10# = m.m10 / sx# : r11# = m.m11 / sy# : r12# = m.m12 / sz#
    r20# = m.m20 / sx# : r21# = m.m21 / sy# : r22# = m.m22 / sz#
    
    ' 计算XYZ顺序欧拉角,处理万向锁
    y# = Asin(r02#)
    if Abs(Cos(y#)) > 0.0001 then
        x# = Atan2(-r12#, r22#)
        z# = Atan2(-r01#, r00#)
    else
        ' 万向锁时固定Z角为0,计算X角
        x# = Atan2(r21#, r11#)
        z# = 0
    endif
EndFunction

3. AGK C版对应实现

欧拉角转带缩放矩阵

void EulerScaleToMatrix(float x, float y, float z, float sx, float sy, float sz, agk::Matrix& m)
{
    float cx = cosf(x), sx_rot = sinf(x);
    float cy = cosf(y), sy_rot = sinf(y);
    float cz = cosf(z), sz_rot = sinf(z);
    
    // 填充矩阵元素(AGK按行存储)
    m.m[0] = cy * cz * sx;
    m.m[1] = -cy * sz_rot * sx;
    m.m[2] = sy_rot * sx;
    m.m[3] = 0;
    
    m.m[4] = (sx_rot * sy_rot * cz + cx * sz_rot) * sy;
    m.m[5] = (-sx_rot * sy_rot * sz_rot + cx * cz) * sy;
    m.m[6] = (-sx_rot * cy) * sy;
    m.m[7] = 0;
    
    m.m[8] = (-cx * sy_rot * cz + sx_rot * sz_rot) * sz;
    m.m[9] = (cx * sy_rot * sz_rot + sx_rot * cz) * sz;
    m.m[10] = cx * cy * sz;
    m.m[11] = 0;
    
    m.m[12] = 0; m.m[13] = 0; m.m[14] = 0; m.m[15] = 1;
}

矩阵转欧拉角+缩放

void MatrixToEulerScale(const agk::Matrix& m, float& x, float& y, float& z, float& sx, float& sy, float& sz)
{
    // 提取缩放因子
    sx = sqrtf(m.m[0]*m.m[0] + m.m[4]*m.m[4] + m.m[8]*m.m[8]);
    sy = sqrtf(m.m[1]*m.m[1] + m.m[5]*m.m[5] + m.m[9]*m.m[9]);
    sz = sqrtf(m.m[2]*m.m[2] + m.m[6]*m.m[6] + m.m[10]*m.m[10]);
    
    // 避免除零
    if (sx < 0.0001f) sx = 0.0001f;
    if (sy < 0.0001f) sy = 0.0001f;
    if (sz < 0.0001f) sz = 0.0001f;
    
    // 归一化旋转矩阵
    float r00 = m.m[0]/sx, r01 = m.m[1]/sy, r02 = m.m[2]/sz;
    float r10 = m.m[4]/sx, r11 = m.m[5]/sy, r12 = m.m[6]/sz;
    float r20 = m.m[8]/sx, r21 = m.m[9]/sy, r22 = m.m[10]/sz;
    
    // 计算欧拉角
    y = asinf(r02);
    if (fabsf(cosf(y)) > 0.0001f)
    {
        x = atan2f(-r12, r22);
        z = atan2f(-r01, r00);
    }
    else
    {
        x = atan2f(r21, r11);
        z = 0.0f;
    }
}

关键注意事项

  1. 矩阵存储顺序:上述代码假设AGK矩阵为行主序,若实际为列主序,需调整矩阵元素的索引对应关系。
  2. 镜像变换处理:若矩阵行列式为负(存在镜像),需将其中一个缩放因子取反,再归一化旋转矩阵,否则欧拉角计算会出错。
  3. 精度控制:加入0.0001的阈值避免三角函数和除法的精度问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:37:06