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; } }
关键注意事项
- 矩阵存储顺序:上述代码假设AGK矩阵为行主序,若实际为列主序,需调整矩阵元素的索引对应关系。
- 镜像变换处理:若矩阵行列式为负(存在镜像),需将其中一个缩放因子取反,再归一化旋转矩阵,否则欧拉角计算会出错。
- 精度控制:加入
0.0001的阈值避免三角函数和除法的精度问题。
内容的提问来源于stack exchange,提问作者Peter Kennedy
相关产品推荐
相关产品推荐

