最近在编写三维显示程序的过程中,遇到了OpenGL视图方面的相关内容,对于一些基本变换的操作感到迷惑,于是重新回顾了《openGl 编程指南》第三章关于视图的相关内容。现在将自己理解的内容总结如下。
一、OpenGl 在渲染场景的过程中有四个基本的变换:
1、视图变换--主要作用是确定相机的姿态,更形象点来讲是将相机固定到三角架上,对准要拍摄的物体。
2、模型变换--主要是用来绘制物体,确定物体的姿态和位置。 相当于人在照相时,摆好pose.
注意,一般而言,视图变换和模型变换可以相互转化,比如,相机平移(0,0,1)想当于人平移(0,0,-1)因此OpenGL 引入了GL_MODELVIEW变量来统一管理模型和视图变换。
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); // 吧当前矩阵设置为单位矩阵,很重要,因为绝大部分的变换都是把当前矩阵与指定的矩阵相 //乘,如果没有加载单位矩阵来清除当前矩阵,他所进行的变换实际上是把当前的变换与上一 //次变换相组合
glLookAt(0,0,0,0,0,0,0,0,0)// 相机位置
glTranslate(0,0,0);
glScale(0,0,0);
draw_object();
3、投影变换--主要作用是进行透视变换,形象点解释是为相机选择镜头。分为透视投影和正交投影。
glMatrxiMode(GL_PROJECTION)
glLoadIdentity();//
/**********透视投影************/
gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far);
或者
glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
/*********正交投影************/
glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
4、视口变换--将投影后的物体坐标最终对应到窗口坐标系中。
glViewport(GLint x, GLint y, GLsizei width GLdizei height);
注意此处中 width 和 height 的比例应该和透视投影中的aspect 相同,否则得到的的物体会发生变形。
二、全局固定坐标系和局部移动坐标系
其实是对同意中坐标转换的不同的理解,主要是在物体的绘制过程中。
glMatrixMode(GL_MODELVIEW)
glLoadIdentity();
glMultiMatrix(T);
glMultiMatix(R);
draw_the_object();
从全局度固定坐标系的角度来理解,对于上述的矩阵变化是从下往上: 绘制物体,先绕全局原点进行旋转,然后绕全局的坐标系进行平移。
从局部移动坐标系的角度来理解, 对于上述的矩阵变化是从上往下: 绘制物体,先进行平移(局部坐标原点开始与全局坐标原点重合,随着物体平移),然后绕着局部坐标系原点进行旋转。
另一种情况:
glMultiMatix(R);
glMultiMatrix(T);
注意,假设采用局部移动坐标系,先进行旋转,此时原点仍然重合,但是坐标轴已经发生变化。
3、关于矩阵操作
对于视图矩阵,投影矩阵,和视口矩阵都分别有一个对应的矩阵堆栈,具体选择哪种矩阵堆栈使用glMatrixMode(GL_PROJECTION)操作,表示下面的矩阵是影响投影矩阵。
通常情况下,发挥作用的是矩阵堆栈的的最顶部的矩阵。但是在实际操作过程中,通常需要进行分层次创建。比如在绘制汽车时,先绘制车体(此时位于车体坐标系)然后绘制左前轮,绘制玩左前轮后通常是回到车体坐标系,然后绘制右前轮。 此时需要先保存车体坐标系。
为了实现这种操作openGL 采用了glPushMatrix() 和glPopMatrix()两个矩阵堆栈的操作。
glPushMatrix()复制一份当前矩阵(注意,当前矩阵就是堆栈最顶部的矩阵)并将当前矩阵下压一级,也就是说此时的矩阵堆栈中,最顶的两级中的矩阵是相同的。
glPopMatrix() 将最顶部的矩阵弹出并销毁。
for(int i=0; i<5; i++)
{
glPushMatrix();//最顶的两级相同
glRotatef(R);// 最顶部的矩阵发生变化
glTranlatef(T);
draw_bolt();
glPopMatrix(); //恢复初始的坐标系
}
四、基本的框架
void init(void);//初始化
void dispaly(void); { //绘制物体
//模型变换
glTranslatef(T);
glRotatef(R);
draw_object();
}
void reshape(int w, int h) { //
//视口变换
glViewport(0,0, (GLsizei)w, (GLsizei)h);
//投影变换
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glPerspective();
//视图模型变换
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLookAt() //有时候也放到reshape 的开头
}