线性变换
仿射变换:包括平移、旋转以及比例变换。这种变换能够保持直线建的平行性,并且可逆。
射影变换:包括透视变换等。由于这些变换都是将三维实体投影到二维空间,所以不可逆。
齐次坐标系
OpenGL实际是在四维坐标中定义的,坐标为(x,y,z,w)在三维点空间上显示为(x/w,y/w,z/w),不定义w的话,w默认为1。
故我们用于建模、观察以及投影的所有变换都可由4*4的矩阵直接作用于齐次坐标系中的点和向量得到。
模型-视图变换和投影变换
每个顶点都经过当前模型-视图矩阵和投影矩阵定义的两个变换。一开始这两个矩阵均被设为4*4的单位矩阵。模型-视图矩阵用于对摄影机定位,而投影矩阵指定了投影以及剪裁体,并将顶点映射至一个归一化的坐标系中。
平移
void glTranslate<fd>(type x,type y,type z)
//通过将以参数dx,dy,dz为参数的平移矩阵与当前做右乘来改变当前矩阵,type为GLfloat或GLdouble.
如果我们想所有的顶点沿着z轴负方向平移一个单位,可以这样做
glMatriMode(GL_MODELVIEW); glLoadIdentify(); glTranslatef(0.0,0.0,-1.0);
联级变换
如果没使用glLoadIdentify()则两次平移变换就组合在一起或级联,从而形成一次复合变换。
旋转变换
void glRotate<fd>(type angle,type dx,type dy,type dz)
//形成一个旋转轴为(dx,dy,dz)的旋转矩阵,旋转不动点为原点坐标原点。type为GLfloat或GLdouble。
若要绕着任意固定的点旋转,则可以先将该点平移至原点,然后使用glRotate*()实现所期望的旋转。最后,我们还需要通过一次平移在将该不动点平移回去。
比例变换
void glScale<fd>(type sx,type sy,type sz)
//根据比例因子sx,sy和sz创建一个比例变换矩阵,其不动点位于原点处。type可取GLfloat和GLdouble
一个旋转的立方体:
#include <gl/glut.h>
#include <math.h>
#include <vector>
#include <iostream>
using namespace std;
int axis=0;
float theta[3];
GLfloat vertices[]={
-1.0,-1.0,1.0,
-1.0,1.0,1.0,
1.0,1.0,1.0,
1.0,-1.0,1.0,
-1.0,-1.0,-1.0,
-1.0,1.0,-1.0,
1.0,1.0,-1.0,
1.0,-1.0,-1.0
}; //定义立方体的8个顶点
GLint index[]={
0,3,2,1,
2,3,7,6,
3,0,4,7,
1,2,6,5,
4,5,6,7,
5,4,0,1
}; //定义每个面所需要那几个顶点
GLfloat colors[]={
1.0,0.0,0.0,
0.0,1.0,1.0,
1.0,1.0,0.0,
0.0,1.0,0.0,
0.0,0.0,1.0,
1.0,0.0,1.0,
1.0,1.0,0.0,
0.0,1.0,1.0
}; //定义六个面的颜色
void init()
{
glClearColor(0.0,0.0,0.0,0.0); //指定屏幕背景为黑色
glColor3f(1.0,1.0,1.0); //设置绘制颜色为白色
glShadeModel(GL_FLAT); //设置颜色插值为平面模式
}
void display()
{
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清理屏幕颜色为我们指定的颜色
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3,GL_FLOAT,0,vertices);
glColorPointer(3,GL_FLOAT,0,colors);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(theta[0],1.0,0.0,0.0);
glRotatef(theta[1],0.0,1.0,0.0);
glRotatef(theta[2],0.0,0.0,1.0);
glDrawElements(GL_QUADS,24,GL_UNSIGNED_INT,index);
glFlush(); //强制以上绘图操作执行
}
void reshape(int w,int h)
{
glMatrixMode(GL_PROJECTION); //设置为投影模式
glLoadIdentity();
glOrtho(-2.0,2.0,-2.0,2.0,-2.0,2.0);
glViewport(0,0,(GLsizei)w,(GLsizei)h);
}
void mouse(int button,int state,int x,int y)
{
if (button==GLUT_LEFT_BUTTON && state==GLUT_DOWN)
{
axis=0;
}
if (button==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN)
{
axis=1;
}
if (button==GLUT_RIGHT_BUTTON && state==GLUT_DOWN)
{
axis=2;
}
}
void SpinIdle()
{
theta[axis]+=0.1;
if(theta[axis] >360.0) theta[axis] -=360.0;
glutPostRedisplay();
}
int main(int argc,char**argv)
{
glutInit(&argc,argv); //初始化glut
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); //设置窗口模式为单缓冲和RGB模式
glutInitWindowSize(500,500); //设置窗口大小
init();
glutCreateWindow("test"); //设置窗口标题
glutDisplayFunc(display); //设置绘图回调函数
glutReshapeFunc(reshape); //设置窗口回调函数
glutMouseFunc(mouse);
glutIdleFunc(SpinIdle);
glutMainLoop(); //开始循环,等待响应
return 0;
}运行并适当点击鼠标改变角度可以得到如下结果:
直接设置矩阵
void glLoadMatrix<fd>(type* m)
//将type类型(可取GLfloat或者GLdouble的数组m加载为当前矩阵)
原文地址:http://6996127.blog.51cto.com/6986127/1547326