如何修正满足A*C=B的4x4矩阵桥矩阵C的C++函数
修复满足
A*C=B的矩阵求解函数符号错误问题 我需要实现一个C++函数,给定4x4矩阵A和B,生成满足A*C=B的矩阵C。目前写出的代码数值正确,但符号存在问题,输出结果不符合预期。
现有实现代码
Matrix Matrix::GetBridge(Matrix* theOther) { Matrix aIMat=GetInvert(); if (!theOther) return Identity(); Matrix aResult=*theOther; aResult*=aIMat; return aResult; }
输出结果
Matrix A: 1,0,0,0 0,0.9063,0.4226,0 0,-0.4226,0.9063,0 0,0,0,1 Matrix B: 0,0,-1,0 0,1,0,0 1,0,0,0 0,0,0,1 Matrix C: 0,-0.4226,-0.9063,0 0,0.9063,-0.4226,0 1,0,0,0 0,0,0,1 Matrix B * C: -1,-0,-0,0 0,0.9063,-0.4226,0 0,-0.4226,-0.9063,0 0,0,0,1
可以看到B*C的数值与A一致,但符号不符,且不符合A*C=B的预期。
测试代码
Matrix aM1;aM1.RotateX(25); Matrix aM2;aM2.RotateY(90); Matrix aM3=aM1.GetBridge(&aM2); aM1.Debug("$Matrix A:"); aM2.Debug("$Matrix B:"); aM3.Debug("$Matrix C:"); Matrix aM4=aM2; aM4*=aM3; aM4.Debug("!Matrix B * C:");
逆矩阵实现(供排查)
Matrix& Matrix::Invert() { float aInv[16]; aInv[0]=mData.mm[5]*mData.mm[10]*mData.mm[15]-mData.mm[5]*mData.mm[11]*mData.mm[14]-mData.mm[9]*mData.mm[6]*mData.mm[15]+mData.mm[9]*mData.mm[7]*mData.mm[14]+mData.mm[13]*mData.mm[6]*mData.mm[11]-mData.mm[13]*mData.mm[7]*mData.mm[10]; aInv[4]=-mData.mm[4]*mData.mm[10]*mData.mm[15]+mData.mm[4]*mData.mm[11]*mData.mm[14]+mData.mm[8]*mData.mm[6]*mData.mm[15]-mData.mm[8]*mData.mm[7]*mData.mm[14]-mData.mm[12]*mData.mm[6]*mData.mm[11]+mData.mm[12]*mData.mm[7]*mData.mm[10]; aInv[8]=mData.mm[4]*mData.mm[9]*mData.mm[15]-mData.mm[4]*mData.mm[11]*mData.mm[13]-mData.mm[8]*mData.mm[5]*mData.mm[15]+mData.mm[8]*mData.mm[7]*mData.mm[13]+mData.mm[12]*mData.mm[5]*mData.mm[11]-mData.mm[12]*mData.mm[7]*mData.mm[9]; aInv[12]=-mData.mm[4]*mData.mm[9]*mData.mm[14]+mData.mm[4]*mData.mm[10]*mData.mm[13]+mData.mm[8]*mData.mm[5]*mData.mm[14]-mData.mm[8]*mData.mm[6]*mData.mm[13]-mData.mm[12]*mData.mm[5]*mData.mm[10]+mData.mm[12]*mData.mm[6]*mData.mm[9]; aInv[1]=-mData.mm[1]*mData.mm[10]*mData.mm[15]+mData.mm[1]*mData.mm[11]*mData.mm[14]+mData.mm[9]*mData.mm[2]*mData.mm[15]-mData.mm[9]*mData.mm[3]*mData.mm[14]-mData.mm[13]*mData.mm[2]*mData.mm[11]+mData.mm[13]*mData.mm[3]*mData.mm[10]; aInv[5]=mData.mm[0]*mData.mm[10]*mData.mm[15]-mData.mm[0]*mData.mm[11]*mData.mm[14]-mData.mm[8]*mData.mm[2]*mData.mm[15]+mData.mm[8]*mData.mm[3]*mData.mm[14]+mData.mm[12]*mData.mm[2]*mData.mm[11]-mData.mm[12]*mData.mm[3]*mData.mm[10]; aInv[9]=-mData.mm[0]*mData.mm[9]*mData.mm[15]+mData.mm[0]*mData.mm[11]*mData.mm[13]+mData.mm[8]*mData.mm[1]*mData.mm[15]-mData.mm[8]*mData.mm[3]*mData.mm[13]-mData.mm[12]*mData.mm[1]*mData.mm[11]+mData.mm[12]*mData.mm[3]*mData.mm[9]; aInv[13]=mData.mm[0]*mData.mm[9]*mData.mm[14]-mData.mm[0]*mData.mm[10]*mData.mm[13]-mData.mm[8]*mData.mm[1]*mData.mm[14]+mData.mm[8]*mData.mm[2]*mData.mm[13]+mData.mm[12]*mData.mm[1]*mData.mm[10]-mData.mm[12]*mData.mm[2]*mData.mm[9]; aInv[2]=mData.mm[1]*mData.mm[6]*mData.mm[15]-mData.mm[1]*mData.mm[7]*mData.mm[14]-mData.mm[5]*mData.mm[2]*mData.mm[15]+mData.mm[5]*mData.mm[3]*mData.mm[14]+mData.mm[13]*mData.mm[2]*mData.mm[7]-mData.mm[13]*mData.mm[3]*mData.mm[6]; aInv[6]=-mData.mm[0]*mData.mm[6]*mData.mm[15]+mData.mm[0]*mData.mm[7]*mData.mm[14]+mData.mm[4]*mData.mm[2]*mData.mm[15]-mData.mm[4]*mData.mm[3]*mData.mm[14]-mData.mm[12]*mData.mm[2]*mData.mm[7]+mData.mm[12]*mData.mm[3]*mData.mm[6]; aInv[10]=mData.mm[0]*mData.mm[5]*mData.mm[15]-mData.mm[0]*mData.mm[7]*mData.mm[13]-mData.mm[4]*mData.mm[1]*mData.mm[15]+mData.mm[4]*mData.mm[3]*mData.mm[13]+mData.mm[12]*mData.mm[1]*mData.mm[7]-mData.mm[12]*mData.mm[3]*mData.mm[5]; aInv[14]=-mData.mm[0]*mData.mm[5]*mData.mm[14]+mData.mm[0]*mData.mm[6]*mData.mm[13]+mData.mm[4]*mData.mm[1]*mData.mm[14]-mData.mm[4]*mData.mm[2]*mData.mm[13]-mData.mm[12]*mData.mm[1]*mData.mm[6]+mData.mm[12]*mData.mm[2]*mData.mm[5]; aInv[3]=-mData.mm[1]*mData.mm[6]*mData.mm[11]+mData.mm[1]*mData.mm[7]*mData.mm[10]+mData.mm[5]*mData.mm[2]*mData.mm[11]-mData.mm[5]*mData.mm[3]*mData.mm[10]-mData.mm[9]*mData.mm[2]*mData.mm[7]+mData.mm[9]*mData.mm[3]*mData.mm[6]; aInv[7]=mData.mm[0]*mData.mm[6]*mData.mm[11]-mData.mm[0]*mData.mm[7]*mData.mm[10]-mData.mm[4]*mData.mm[2]*mData.mm[11]+mData.mm[4]*mData.mm[3]*mData.mm[10]+mData.mm[8]*mData.mm[2]*mData.mm[7]-mData.mm[8]*mData.mm[3]*mData.mm[6]; aInv[11]=-mData.mm[0]*mData.mm[5]*mData.mm[11]+mData.mm[0]*mData.mm[7]*mData.mm[9]+mData.mm[4]*mData.mm[1]*mData.mm[11]-mData.mm[4]*mData.mm[3]*mData.mm[9]-mData.mm[8]*mData.mm[1]*mData.mm[7]+mData.mm[8]*mData.mm[3]*mData.mm[5]; aInv[15]=mData.mm[0]*mData.mm[5]*mData.mm[10]-mData.mm[0]*mData.mm[6]*mData.mm[9]-mData.mm[4]*mData.mm[1]*mData.mm[10]+mData.mm[4]*mData.mm[2]*mData.mm[9]+mData.mm[8]*mData.mm[1]*mData.mm[6]-mData.mm[8]*mData.mm[2]*mData.mm[5]; float aDet=mData.mm[0]*aInv[0]+mData.mm[1]*aInv[4]+mData.mm[2]*aInv[8]+ mData.mm[3]*aInv[12]; if (aDet!=0) {aDet=1.0f/aDet;for (int aCount=0;aCount<16;aCount++) mData.mm[aCount]=aInv[aCount]*aDet;} return *this; } inline Matrix GetInvert() {Matrix aMat=*this;aMat.Invert();return aMat;}
注:该逆矩阵函数在其他场景(如坐标转换到局部空间)可正常工作,错误不在此。
修复方案
核心问题是矩阵乘法顺序错误:
要满足A*C=B,正确的推导是在等式两边左乘A⁻¹,得到C = A⁻¹ * B。而原代码计算的是C = B * A⁻¹,这是错误的顺序,导致符号和结果不符合预期。
修改后的GetBridge函数:
Matrix Matrix::GetBridge(Matrix* theOther) { Matrix aIMat = GetInvert(); if (!theOther) return Identity(); Matrix aResult = aIMat; aResult *= *theOther; return aResult; }
验证说明
修改后,应测试A*C是否等于B,即把测试代码中的aM4 = aM2; aM4 *= aM3;改为aM4 = aM1; aM4 *= aM3;,此时输出的aM4应与aM2一致,满足A*C=B的需求。
内容的提问来源于stack exchange,提问作者KiraHoneybee
相关产品推荐
相关产品推荐

