|
[code]平移
平移有两个set矩阵的方法setTranslation()和setToTranslation(),试过后发现没有区别;
为了方便debug调试,写了个结构体来转换出矩阵行列值查看:
struct MatrixVector
{
int nM11;
int nM12;
int nM13;
int nM14;
int nM21;
int nM22;
int nM23;
int nM24;
int nM31;
int nM32;
int nM33;
int nM34;
int nM41;
int nM42;
int nM43;
int nM44;
MatrixVector()
{
nM11 = 1;
nM12 = 0;
nM13 = 0;
nM14 = 0;
nM21 = 0;
nM22 = 1;
nM23 = 0;
nM24 = 0;
nM31 = 0;
nM32 = 0;
nM33 = 1;
nM34 = 0;
nM41 = 0;
nM42 = 0;
nM43 = 0;
nM44 = 1;
};
};
MatrixVector ConverMatrix(AcGeMatrix3d matxExp)
{
MatrixVector stuMatrix;
stuMatrix.nM11 = matxExp.entry[0][0];
stuMatrix.nM12 = matxExp.entry[0][1];
stuMatrix.nM13 = matxExp.entry[0][2];
stuMatrix.nM14 = matxExp.entry[0][3];
stuMatrix.nM21 = matxExp.entry[1][0];
stuMatrix.nM22 = matxExp.entry[1][1];
stuMatrix.nM23 = matxExp.entry[1][2];
stuMatrix.nM24 = matxExp.entry[1][3];
stuMatrix.nM31 = matxExp.entry[2][0];
stuMatrix.nM32 = matxExp.entry[2][1];
stuMatrix.nM33 = matxExp.entry[2][2];
stuMatrix.nM34 = matxExp.entry[2][3];
stuMatrix.nM41 = matxExp.entry[3][0];
stuMatrix.nM42 = matxExp.entry[3][1];
stuMatrix.nM43 = matxExp.entry[3][2];
stuMatrix.nM44 = matxExp.entry[3][3];
return stuMatrix;
}
AcGeMatrix3d ConverMatrixVector(MatrixVector stuMatrix)
{
AcGeMatrix3d matxExp;
matxExp.entry[0][0] = stuMatrix.nM11;
matxExp.entry[0][1] = stuMatrix.nM12;
matxExp.entry[0][2] = stuMatrix.nM13;
matxExp.entry[0][3] = stuMatrix.nM14;
matxExp.entry[1][0] = stuMatrix.nM21;
matxExp.entry[1][1] = stuMatrix.nM22;
matxExp.entry[1][2] = stuMatrix.nM23;
matxExp.entry[1][3] = stuMatrix.nM24;
matxExp.entry[2][0] = stuMatrix.nM31;
matxExp.entry[2][1] = stuMatrix.nM32;
matxExp.entry[2][2] = stuMatrix.nM33;
matxExp.entry[2][3] = stuMatrix.nM34;
matxExp.entry[3][0] = stuMatrix.nM41;
matxExp.entry[3][1] = stuMatrix.nM42;
matxExp.entry[3][2] = stuMatrix.nM43;
matxExp.entry[3][3] = stuMatrix.nM44;
return matxExp;
}
下面是测试实例代码:
AcGeMatrix3d matxTran; //平移矩阵
AcGeMatrix3d matxScale;// 缩放矩阵
AcGeMatrix3d matxRota;// 旋转矩阵
matxRota.setToRotation(30,AcGeVector3d::kZAxis);
MatrixVector stuMatrix;
AcGePoint3d ptPos1 = AcGePoint3d(2,2,2);
AcGePoint3d ptPos2 = AcGePoint3d(2,2,2);
AcGeVector3d vecTran = AcGeVector3d(1,2,3);
matxTran.setToTranslation(vecTran);
stuMatrix = ConverMatrix(matxTran);
//此时平移矩阵matxTran
{
1 0 0 1
0 1 0 2
0 0 1 3
0 0 0 1
}
matxScale.setToScaling(3);
stuMatrix = ConverMatrix(matxScale);
//此时缩放矩阵matxScale
{
3 0 0 0
0 3 0 0
0 0 3 0
0 0 0 1
}
ptPos1.transformBy(matxTran);
ptPos1.transformBy(matxScale);
//--------
AcGeMatrix3d matrxTop = matxScale * matxTran; // 先平移再缩放矩阵
ptPos2.transformBy(matrxTop);
// 验证结果ptPos1和ptPos2是一样的等于(9,12,15);
int nTrans = 3;
AcGeMatrix3d matxExp1;
AcGeMatrix3d matxExp2;
matxExp2 = matxExp1.setTranslation(nTrans * AcGeVector3d::kZAxis);
matxExp2 = matxExp1.setToTranslation(nTrans * AcGeVector3d::kZAxis);
//两个函数效果一样,此时matxExp1和matxExp2的值是一样的,都是
{
1 0 0 0
0 1 0 0
0 0 1 3
0 0 0 1
}
实现不同方向X Y Z 上缩放比例不同的情况,例如 X方向缩放1倍,Y方向缩放2倍,Z方向缩放3倍:
MatrixVector stuMatrix;
stuMatrix.nM11 = 1;
stuMatrix.nM22 = 2;
stuMatrix.nM33 = 3;
//X Y Z 方向缩放不同的矩阵
AcGeMatrix3d matxScale = ConverMatrixVector(stuMatrix);
AcGePoint3d ptPos1 = AcGePoint3d(2,2,2);
ptPos1.transformBy(matxScale);
ptPos1 = (2,4,6);
如何把矩阵转换成对应的位移、旋转角度和缩放比例?
AcGeMatrix3d tran = m_matrix;
CHCVec3d transLation;
CHCVec3d scale;
CHCVec4d rotate;
GetMatrixData(rotate,scale,transLation,tran);
bool GetMatrixData(CHCVec4d &rVec4d,CHCVec3d &scale3d,CHCVec3d &trans3d,::AcGeMatrix3d mat)
{
//平移------
trans3d.x = mat.entry[0][3];
trans3d.y = mat.entry[1][3];
trans3d.z = mat.entry[2][3];
//----------------------------------------
::AcGeVector3d vec1(mat.entry[0][0],mat.entry[1][0],mat.entry[2][0]);
::AcGeVector3d vec2(mat.entry[0][1],mat.entry[1][1],mat.entry[2][1]);
::AcGeVector3d vec3(mat.entry[0][2],mat.entry[1][2],mat.entry[2][2]);
//缩放---------------------------------------
scale3d.x = vec1.length();
scale3d.y = vec2.length();
scale3d.z = vec3.length();
//------------------------------------------------
if (scale3d.x != 0)
{
vec1.x = vec1.x/scale3d.x;
vec1.y = vec1.y/scale3d.x;
vec1.z = vec1.z/scale3d.x;
}
if (scale3d.y != 0)
{
vec2.x = vec2.x/scale3d.y;
vec2.y = vec2.y/scale3d.y;
vec2.z = vec2.z/scale3d.y;
}
if (scale3d.z != 0)
{
vec3.x = vec3.x/scale3d.z;
vec3.y = vec3.y/scale3d.z;
vec3.z = vec3.z/scale3d.z;
}
//旋转-------------------------
AcGeMatrix2d mat2d; //旋转矩阵
mat2d.entry[0][0] = vec1.x;
mat2d.entry[1][0] = vec1.y;
mat2d.entry[2][0] = vec1.z;
mat2d.entry[0][1] = vec2.x;
mat2d.entry[1][1] = vec2.y;
mat2d.entry[2][1] = vec2.z;
mat2d.entry[0][2] = vec3.x;
mat2d.entry[1][2] = vec3.y;
mat2d.entry[2][2] = vec3.z;
//-------------------------------------------------
rVec4d = FromRotationMatrix(mat2d);
return true;
}
CHCVec4d FromRotationMatrix (const AcGeMatrix2d& kRot)
{
CHCVec4d quaternion;
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
// article "Quaternion Calculus and Fast Animation".
double fTrace = kRot.entry[0][0]+kRot.entry[1][1]+kRot.entry[2][2];
double fRoot = 0.0;
if ( fTrace > 0.0 )
{
// |w| > 1/2, may as well choose w > 1/2
fRoot = sqrt(fTrace + 1.0f); // 2w
quaternion.w = 0.5f*fRoot;
fRoot = 0.5f/fRoot; // 1/(4w)
quaternion.x = (kRot.entry[2][1]-kRot.entry[1][2])*fRoot;
quaternion.y = (kRot.entry[0][2]-kRot.entry[2][0])*fRoot;
quaternion.z = (kRot.entry[1][0]-kRot.entry[0][1])*fRoot;
}
else
{
// |w| <= 1/2
static size_t s_iNext[3] = { 1, 2, 0 };
size_t i = 0;
if ( kRot.entry[1][1] > kRot.entry[0][0] )
i = 1;
if ( kRot.entry[2][2] > kRot.entry[i][i] )
i = 2;
size_t j = s_iNext[i];
size_t k = s_iNext[j];
fRoot = sqrt(kRot.entry[i][i]-kRot.entry[j][j]-kRot.entry[k][k] + 1.0f);
double* apkQuat[3] = { &quaternion.x, &quaternion.y, &quaternion.z };
*apkQuat[i] = 0.5f*fRoot;
fRoot = 0.5f/fRoot;
quaternion.w = (kRot.entry[k][j]-kRot.entry[j][k])*fRoot;
*apkQuat[j] = (kRot.entry[j][i]+kRot.entry[i][j])*fRoot;
*apkQuat[k] = (kRot.entry[k][i]+kRot.entry[i][k])*fRoot;
}
return quaternion;
}
3、世界坐标变换要先缩放、后旋转、再平移的原因
一个三维场景中的各个模型一般需要各自建模,再通过坐标变换放到一个统一的世界空间的指定位置上。 这个过程在 3D 图形学中称作“世界变换” 。 世界变换有三种,平移、旋转和缩放 (实际还有不常用的扭曲和镜像,它们不是affine变换)。 这三种变换按各种顺序执行,结果是不同的。 可是实际的应用中一般按照 缩放 -> 旋转 -> 平移的顺序进行。 这样做的原因是可以获得最符合常理的变换结果。
比方说,通过世界变换希望获得的结果可能是:
将一个放在原点的物体(比方说可乐罐)移动到(30,50),让它自身倾斜 45 度,
再放大 2 倍。
1
2
而不希望的结果是:
1.和本地坐标轴成角度的缩放(会导致扭曲,像踩扁的可乐罐)。
2.绕自己几何中心以外位置的原点的旋转 (地球公转式) 和缩放。
而颠倒了上述变换顺序就会得到这样不自然的结果。
具体的说:
当缩放在旋转之后进行时,会发生现象1。
当缩放和旋转在平移之后进行时会发生现象2。
这是因为:在物体刚刚放入世界坐标系的时候使用的是本地坐标,也就是本地和全局坐标系的原点和坐标轴都是重合的(当然两者分别使用了左右手坐标系时除外 - 那是BUG),此时所有物体都“把世界坐标系当做自己的本地坐标系”。
而经过了坐标变换之后:
1.缩放变换不改变坐标轴的走向,也不改变原点的位置,所以两个坐标系仍然重合。
2.旋转变换改变坐标轴的走向,但不改变原点的位置,所以两个坐标系坐标轴不再处于相同走向。
3.平移变换不改变坐标轴走向,但改变原点位置,两个坐标系原点不再重合。
这样就可以解释问什么缩放不能在旋转之后,而缩放和旋转都不能在平移之后了。 于是没有问题的顺序只能是 缩放 -> 旋转 -> 平移 。
原文链接:https://blog.csdn.net/m0_37251750/article/details/99674702[/code] |
|