3D仿射变换(TRS)组合计算:无需极分解的实现问询
无需极分解直接组合3D TRS变换的方法
当然可以不用显式构造矩阵做极分解,直接通过向量和四元数运算得到组合后的TRS参数。以下是具体步骤,先明确TRS变换的定义:我们默认每个TRS变换的顺序是先缩放,再旋转,最后平移,即对任意点v,变换公式为:T(v) = r.rotate(s.component_multiply(v)) + t
其中r.rotate(v)表示用四元数r旋转向量v,component_multiply是分量-wise乘法。
1. 计算组合后的平移向量t_total
这一步很直接,先把T0的平移向量t0经过T1的线性变换(缩放+旋转),再加上T1的平移t1:
t_total = r1.rotate( s1.component_multiply(t0) ) + t1
2. 计算组合后的旋转四元数r_total和缩放向量s_total
我们需要从两个变换的线性组合中提取旋转和缩放,核心是利用标准正交基的变换,再通过正交化得到旋转基,同时提取缩放因子:
步骤2.1 计算三个标准基向量的变换结果
取x/y/z轴的单位向量e_x=(1,0,0)、e_y=(0,1,0)、e_z=(0,0,1),分别计算它们经过T0和T1线性变换后的结果:
v_x = r1.rotate( s1.component_multiply( r0.rotate( s0.component_multiply(e_x) ) ) ) v_y = r1.rotate( s1.component_multiply( r0.rotate( s0.component_multiply(e_y) ) ) ) v_z = r1.rotate( s1.component_multiply( r0.rotate( s0.component_multiply(e_z) ) ) )
这三个向量构成了组合线性变换的矩阵列。
步骤2.2 对变换后的基向量做Gram-Schmidt正交化
由于各向异性缩放的存在,v_x/v_y/v_z不一定正交,我们需要将它们正交化得到正交单位基,这就是组合后旋转矩阵的列:
- 处理第一个向量:
u1 = v_x.normalize() # 归一化得到第一个正交基 s_x = v_x.magnitude() # 第一个缩放分量 - 处理第二个向量:
proj_y = v_y.dot(u1) * u1 # 计算v_y在u1上的投影 v_y_ortho = v_y - proj_y # 去除投影得到正交分量 u2 = v_y_ortho.normalize() # 归一化得到第二个正交基 s_y = v_y_ortho.magnitude()# 第二个缩放分量 - 处理第三个向量:
proj_z1 = v_z.dot(u1) * u1 proj_z2 = v_z.dot(u2) * u2 v_z_ortho = v_z - proj_z1 - proj_z2 u3 = v_z_ortho.normalize() s_z = v_z_ortho.magnitude()
步骤2.3 得到最终的旋转和缩放
- 缩放向量
s_total就是(s_x, s_y, s_z) - 正交基
u1/u2/u3构成了组合后的旋转矩阵,将这个矩阵转换为四元数就是r_total
关键说明
- 这种方法本质上是通过Gram-Schmidt正交化完成了极分解中正交部分的计算,避免了显式构造大矩阵和完整的极分解运算,计算量更低。
- 如果两个变换的缩放都是各向同性(即
s0.x=s0.y=s0.z且s1.x=s1.y=s1.z),那么v_x/v_y/v_z会天然正交,此时正交化步骤可以简化为直接归一化,旋转四元数就是r1 * r0(四元数乘法),缩放向量就是s0.component_multiply(s1)。
内容的提问来源于stack exchange,提问作者Xaldew
相关产品推荐
相关产品推荐

