1.右手规则: 以右手握住Z轴,当右手的4个手指(最下面的一节)从正向X轴以PI/2角度转向正向Y轴时(即手掌与拳面形成的直角),大拇指的的指向就是Z轴的正向.
2.无论相对左手坐标系DirectX或右手坐标系OpenGL,空间中某点作同种几何变换,结果值相等.即几何变换结果与坐标系统无关,几何变换的描述也与坐标系统无关.数学标准为右手坐标系.
3.无论DirectX的行主模式或OpenGL的列主模式(平移阵列处于行上还是列上),一个变换矩阵表达的变换是数学语义的,与距阵表达方式无关,用DirectX或OpenGL距阵作变换,结果值一定相等.即行主或列主矩阵描述同一个几何变换,则矩阵的数学语义必然相同.矩阵的数学语义以列主为标准,即平移阵列位于最后一列.
4.矩阵相乘算规则是:用左矩阵的每一行(第i行)的元素去依次乘以右矩阵的第一列(第j列)的对应元素,得到(i,j)元素.在遍历左矩阵每一行中,遍历右矩阵每一列。即左阵出行,右阵出列。
故,在OpenGL列主矩阵下,点是列向量表达,空间变换为M*V
在DirectX行主矩阵下,点是行向量表达,空间变换为V*M
当作空间连续变换时,OpenGL中最后调用的空间变换函数才是最先起作用的,DirectX中反之.
5.变换先作用于或后作用于顶点是客观观念,左乘右乘是实现手段,OpenGL右乘为先作用,DX左乘为先作用.
6.在顶点作用乘法式中,离顶点近的矩阵在世界坐标系上先作用于顶点,离顶点远的矩阵在自身坐标系上先作用于顶点.
pre,post均相对顶点而言,以顶点为参照点.左手坐标系,顶点在左,右手坐标系,顶点在右.
7.Sample
quaternion_type quat;
quat.set_axis_angle(vec3_type(8.0f, -11.2f, -231.0f), 0.271f);
quat.normalize4();
vec3_type vRc(23.3f, 17.4f, 43.9f);
vec3_type vTrans(10.0f, 10.0f, 10.0f);
D3DXVECTOR3 vOut1(11.0f, 45.0f, 99.0f);
vec3_type vOut2(11.0f, 45.0f, 99.0f);
// DirectX Transform ///////////////////////////////////////////////////////////////////////////////
D3DXMATRIX mat;
D3DXMatrixTransformation(&mat, NULL, NULL, NULL, (D3DXVECTOR3*)&vRc, (D3DXQUATERNION*)(&quat), (D3DXVECTOR3*)&vTrans);
D3DXVec3TransformCoord(&vOut1, &vOut1, &mat);
std::cout << vOut1.x << ", " << vOut1.y << ", " << vOut1.z << std::endl;
// Math Transform ///////////////////////////////////////////////////////////////////////////////////////
matrix_type matRes, matRotate, matTrans1, matTrans2, matTrans3;
matRotate.makeRotate(quat);
matTrans1.makeTranslate(-vRc.x, -vRc.y, -vRc.z);
matTrans2.makeTranslate(vRc);
matTrans3.makeTranslate(vTrans);
matRes = matTrans3 * matTrans2 * matRotate * matTrans1;
matRes.transformVector(vOut2);
std::cout << vOut2.x << ", " << vOut2.y << ", " << vOut2.z << std::endl;
matrix_type proj, modl; // 标准数学矩阵
glGetFloatv(GL_MODELVIEW_MATRIX, modl);
glGetFloatv(GL_PROJECTION_MATRIX, proj);
clip = modl * proj; // Note: (M * N)^T = (N^T) * (M^T)
clip.transpose(); // OpenGL数组内存存储方式为列主,需要转置,得proj * modl最终矩阵.
// v1,v2为原始3D点
vec3_type v1(5.0f, 12.5f, -1.0f);
vec3_type v2(33.0f, 41.0f, -1024.0f);
// v3,v4为经过终极矩阵变换后的齐次坐标
vec4_type v3 = clip.transformVertex4(v1);
vec4_type v4 = clip.transformVertex4(v2);
// 作齐次计算后得: q(x/w, y/w, z/w),值域均为[-1, 1],canonical view colume.
// 若-1.0f为近平面则,必有z/w = -1.0f, 若-1024.0为远平面则必有z/w = 1.0f,即near_z = -1.0f, far_z = 1.0f
// 结果z轴与原有OpenGL的z轴方向相逆,又OpenGL以正值输入near,far.
// 将q直接映射到viewport屏幕象素上为
PixelX = (q.x + 1.0f) * viewport_width * 0.5f;
PixelY = (q.y + 1.0f) * viewport_height * 0.5f;
书之理论,未经编码实不可信!
Don't show me the theory, show me your code!