3x3矩阵变换链中非均匀缩放引发的旋转异常问题求助
这绝对是变换矩阵的顺序搞反了导致的——不管是局部变换的内部顺序,还是和父变换的组合顺序,这就是非均匀缩放时出现异常的核心原因。我来给你拆解清楚:
1. 局部变换的顺序完全颠倒了
你当前的局部变换顺序是 Rotate → Scale → Translate,但正确的顺序应该是 Scale → Rotate → Translate(对应矩阵组合为 Translate * Rotate * Scale)。
为什么?因为矩阵乘法是右结合的:当你用变换矩阵乘以顶点时,v' = M * v,矩阵最右侧的变换会先被应用。你现在的代码实际执行的顺序是「先平移,再缩放,再旋转」,这完全不符合我们对局部变换的预期——尤其是旋转后再做非均匀缩放,会让物体的缩放方向跟着旋转后的轴走,导致后续子物体继承的坐标系被扭曲,最终出现不对齐、尺寸异常的问题。
2. 父变换与局部变换的组合顺序也错了
你现在是把局部变换结果乘以父的全局变换:output *= parent->getGlobalTransform(),这等价于 output = localTransform * parentTransform。但正确的逻辑应该是先应用父变换,再应用当前物体的局部变换,也就是 output = parentTransform * localTransform。
原因很简单:父变换定义了当前物体所在的坐标系,我们需要先把物体的局部坐标转换到父坐标系中,再应用自己的缩放、旋转、平移。
修正后的代码
把这两个顺序都改过来,你的问题应该就能解决:
maths::mat3 DisplayObject::getGlobalTransform() { // 构建正确的局部变换:先缩放,再旋转,最后平移(矩阵组合为 Translate * Rotate * Scale) maths::mat3 local = maths::mat3::Translate(position); local *= maths::mat3::Rotate(rotation); local *= maths::mat3::Scale(scale); if(parent != nullptr){ // 父变换在前,局部变换在后:先进入父坐标系,再应用自身变换 return parent->getGlobalTransform() * local; } return local; }
额外说明
当父物体有非均匀缩放时,子物体的旋转会受到父坐标系扭曲的影响——这时候你用 GetRotation() 和 GetScale() 从组合矩阵中提取的数值可能会不准确,因为这些方法只适用于均匀缩放的场景。如果后续需要准确提取局部旋转/缩放,你可能需要单独存储每个物体的局部变换参数(而不是从组合矩阵中反推),这样在继承的时候可以基于父的参数重新计算,而不是依赖矩阵分解。
内容的提问来源于stack exchange,提问作者Peter Gilmour

