首页 > 代码库 > OpenGL学习(四) 几何变换

OpenGL学习(四) 几何变换

线性变换

    仿射变换:包括平移、旋转以及比例变换。这种变换能够保持直线建的平行性,并且可逆。

    射影变换:包括透视变换等。由于这些变换都是将三维实体投影到二维空间,所以不可逆。


齐次坐标系

    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;
}

运行并适当点击鼠标改变角度可以得到如下结果:

    wKiom1QD6d-joRcsAAi_0cUfVfo886.gif

    

直接设置矩阵

    void glLoadMatrix<fd>(type* m)

    //将type类型(可取GLfloat或者GLdouble的数组m加载为当前矩阵)

OpenGL学习(四) 几何变换