为了弄清楚真相,我们开始研究矩阵的相关知识。首先,我们考虑单位矩阵I在绕着坐标轴旋转后所得的旋转矩阵。这里我直接列出了三种情况:
知道了绕着三轴后的旋转矩阵,那么下面就是绕任意向量所得的矩阵了。设M为单位矩阵经向量a旋转后的矩阵,且a = (xa, ya, za),旋转角度为α,则M=
我其实也不明白该如何证明的,不过我们可以编写一个小程序来验证一下:
#include <assert.h> #include <stdio.h> #include <math.h> #include "GLWidget.h" void PrintMatrix( float matrix[16] ) { assert( matrix != 0 ); printf( "%8.2f%8.2f%8.2f%8.2f\n" "%8.2f%8.2f%8.2f%8.2f\n" "%8.2f%8.2f%8.2f%8.2f\n" "%8.2f%8.2f%8.2f%8.2f\n", matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], matrix[7], matrix[8], matrix[9], matrix[10], matrix[11], matrix[12], matrix[13], matrix[14], matrix[15] ); } void MyRotatef( float matrix[16], float angleInDegree, float x, float y, float z ) { assert( matrix != 0 ); // 向量的单位化 float length = sqrt( x * x + y * y + z * z ); assert( !qFuzzyCompare( length, 0.0f ) );// 希望length不为0 x /= length; y /= length; z /= length; float alpha = angleInDegree / 180 * 3.1415926;// 已转换弧度制 float s = sin( alpha ); float c = cos( alpha ); float t = 1.0f - c; #define MATRIX( row, col ) matrix[row * 4 + col] MATRIX( 0, 0 ) = t * x * x + c; MATRIX( 0, 1 ) = t * x * y + s * z; MATRIX( 0, 2 ) = t * x * z - s * y; MATRIX( 0, 3 ) = 0.0f; MATRIX( 1, 0 ) = t * x * y - s * z; MATRIX( 1, 1 ) = t * y * y + c; MATRIX( 1, 2 ) = t * y * z + s * x; MATRIX( 1, 3 ) = 0.0f; MATRIX( 2, 0 ) = t * x * z + s * y; MATRIX( 2, 1 ) = t * y * z - s * x; MATRIX( 2, 2 ) = t * z * z + c; MATRIX( 2, 3 ) = 0.0f; MATRIX( 3, 0 ) = 0.0f; MATRIX( 3, 1 ) = 0.0f; MATRIX( 3, 2 ) = 0.0f; MATRIX( 3, 3 ) = 1.0f; #undef MATRIX } GLWidget::GLWidget( QWidget* pParent ): QGLWidget( pParent ) { setWindowTitle( "Test OpenGL Matrix" ); } void GLWidget::initializeGL( void ) { float angle = 30.0f; float x = 12.0f; float y = 8.0f; float z = 3.0f; float matrix1[16], matrix2[16]; glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); glGetFloatv( GL_MODELVIEW_MATRIX, matrix1 ); glGetFloatv( GL_MODELVIEW_MATRIX, matrix2 ); printf( "The initial identity matrix is:\n" ); PrintMatrix( matrix2 ); printf( "Now perform OpenGL glRotate function.\n" ); glRotatef( angle, x, y, z ); glGetFloatv( GL_MODELVIEW_MATRIX, matrix1 ); PrintMatrix( matrix1 ); printf( "Now perform MyRotate function.\n" ); MyRotatef( matrix2, angle, x, y, z ); PrintMatrix( matrix2 ); } void GLWidget::paintGL( void ) { }
这说明上面的这条公式是正确的。如此一来我们就知道了glRotatef()的原理啦。其实D3DXMatrixRotationAxis()函数也是这样操作的,只不过D3D是左手坐标系,它的矩阵构建方法又会有所不同。