OpenGL中的变换矩阵的实现
OpenGL中的变换矩阵是一个4x4的数阵,使用一个包含16个元素的一维数组表示。其中,前4个元素表示矩阵的第一列,接下来的4个元素表示矩阵的第2列。即OpenGL中的矩阵运算是使用列主序矩阵的,前三列各表示xyz三个轴的方向向量,第4列表示位移变换。
自定义变换矩阵
1.为矩阵开辟存储空间
//M3DMatrix44f表示使用math3d.h中定义的一个包含16个元素的一维数组
M3DMatrix44f transformationMatrix;
2.创建矩阵
//这里创建一个绕y轴旋转的旋转矩阵
m3dRotationMatrix44(transformationMatrix, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);
3.指定位移向量
//指定位移向量,变换矩阵的第四列
transformationMatrix[12] = 0.0f;
transformationMatrix[13] = 0.0f;
transformationMatrix[14] = -2.5f;
4.利用创建好的矩阵变换物体的各个顶点
//m3dTransformVector3:math3d.h中定义的函数,执行顶点的变换操作
//transformedVertex:变换后的顶点坐标,包含3个元素的一维数组
//objectVertex:原始顶点坐标,包含3个元素的一维数组
//mTransform:变换矩阵
m3dTransformVector3(transformedVertex, objectVertex, mTransform);
5.示例
// Transform.cpp
#include "../../shared/gltools.h"
#include "../../shared/math3d.h" // 3D Math Library
#include <math.h>
//定义一个圆环面
// Draw a torus (doughnut), using the current 1D texture for light shading
void DrawTorus(M3DMatrix44f mTransform)
{
GLfloat majorRadius = 0.35f;//内环半径+环半径
GLfloat minorRadius = 0.15f;//环半径
GLint numMajor = 40;
GLint numMinor = 20;
M3DVector3f objectVertex; // Vertex in object/eye space
M3DVector3f transformedVertex; // New Transformed vertex
double majorStep = 2.0f*M3D_PI / numMajor;
double minorStep = 2.0f*M3D_PI / numMinor;
int i, j;
for (i=0; i<numMajor; ++i)
{
double a0 = i * majorStep;
double a1 = a0 + majorStep;
GLfloat x0 = (GLfloat) cos(a0);
GLfloat y0 = (GLfloat) sin(a0);
GLfloat x1 = (GLfloat) cos(a1);
GLfloat y1 = (GLfloat) sin(a1);
glBegin(GL_TRIANGLE_STRIP);
for (j=0; j<=numMinor; ++j)
{
double b = j * minorStep;
GLfloat c = (GLfloat) cos(b);
GLfloat r = minorRadius * c + majorRadius;
GLfloat z = minorRadius * (GLfloat) sin(b);
// First point
objectVertex[0] = x0*r;
objectVertex[1] = y0*r;
objectVertex[2] = z;
m3dTransformVector3(transformedVertex, objectVertex, mTransform);
glVertex3fv(transformedVertex);
// Second point
objectVertex[0] = x1*r;
objectVertex[1] = y1*r;
objectVertex[2] = z;
m3dTransformVector3(transformedVertex, objectVertex, mTransform);
glVertex3fv(transformedVertex);
}
glEnd();
}
}
// Called to draw scene
void RenderScene(void)
{
M3DMatrix44f transformationMatrix; // 为旋转矩阵开辟空间,M3DMatrix44f是在math3d.h中定义的一个包含16个元素的一维数组。
static GLfloat yRot = 0.0f; // Rotation angle for animation
yRot += 0.5f;
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 创建一个旋转矩阵,绕y轴旋转,创建之后的矩阵存储在transformationMatrix中
m3dRotationMatrix44(transformationMatrix, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);
//指定位移向量,变换矩阵的第四列
transformationMatrix[12] = 0.0f;
transformationMatrix[13] = 0.0f;
transformationMatrix[14] = -2.5f;
//画一个圆环面,根据创建的旋转矩阵,变换圆环面上的各个顶点
DrawTorus(transformationMatrix);
// Do the buffer Swap
glutSwapBuffers();
}
// This function does any needed initialization on the rendering
// context.
void SetupRC()
{
// 设置蓝色背景
glClearColor(0.0f, 0.0f, .50f, 1.0f );
// 以线框方式画所有的物体
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
///
// Called by GLUT library when idle (window not being
// resized or moved)
void TimerFunction(int value)
{
// Redraw the scene with new coordinates
glutPostRedisplay();
//没33ms调用刷新调用一次RenderScene方法,刷新屏幕
glutTimerFunc(33,TimerFunction, 1);
}
void ChangeSize(int w, int h)
{
GLfloat fAspect;
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
h = 1;
glViewport(0, 0, w, h);
fAspect = (GLfloat)w / (GLfloat)h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the clipping volume
gluPerspective(35.0f, fAspect, 1.0f, 50.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800,600);
glutCreateWindow("Manual Transformations Demo");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
SetupRC();
glutTimerFunc(33, TimerFunction, 1);
glutMainLoop();
return 0;
}
拓展:变换的叠加
1.glut中封装的矩阵变换
![]()
2.math3d.h中定义的矩阵变换函数:m3dMatrixMultiply()
![]()
3.OpenGL中自己的矩阵乘法函数:glMultMatrix(),这个函数接受一个矩阵,并把它与当前加载的矩阵相乘,然后把结果存储在矩阵堆栈的顶部。
总结
虽然自定义变换矩阵很灵活,但是这么干是非常低效的。因为我们math3d.h中的函数完成的矩阵变换,是由CPU执行计算的,而不是让OpenGL的专用硬件为我们完成这些工作。