作者:yurunsun@gmail.com 新浪微博@孙雨润 新浪博客 CSDN博客
日期: 2013-6-12
本章内容:
- 流水线与变换
- 模型变换
- 视图变换
- 投影变换
- 操作矩阵
- 逆变换与模拟变换
1. 流水线与变换
1.1 三维几何流水线
三维几何流水线是将三维点转换成二维点的一系列过程:
三维模型坐标 ---> 三维世界坐标 ---> 三维眼坐标 ---> 三维眼坐标 ---> 二维眼坐标 ---> 二维屏幕坐标
| | | | |
模型变换 视图变换 裁剪 投影 窗口到视口映射
-
场景
场景是在图像中显示的三维空间对象组合,包括空间中所有几何对象与光照
-
视图
视图是用于创建图像的信息集,包括场景空间、场景坐标系、坐标系眼视点、投影操作
-
建模
建模是创建并定义几何体的过程
-
三维模型坐标系 vs 三维世界坐标系
建模过程是将每个对象在其方便并有意义的坐标系中定义好,再经过一系列模型变换将对象变换到统一空间的坐标系。前者是模型坐标系,后者是世界坐标系。
-
三维眼坐标系
从观察点出发的坐标系
1.2 变换简介
OpenGL将模型变换与视图变换组合在一起,共用一个矩阵(模型视图矩阵 GL_MODELVIEW
)。这样做之所以可行是因为两者本身就是相对而言的,将照相机沿Z轴移动5个单位相当于所有物体在世界坐标系下反方向移动5个单位。
-
模型变换
模型变换的目的是设置模型的位置和方向:旋转、移动和缩放
-
视图变换
视图变换相当于把照相机固定在三脚架上并使其对准场景
-
投影变换
投影变换相当于为照相机选择镜头,即确定视野
-
视口变换
投影变换指定了映射的发生机制,视口变换决定了有效屏幕区域的形状。
-
通用变换函数
void glMatrixMode(GLenum mode); // GL_MODELVIEW/GL_PROJECTION/GL_TEXTURE void glLoadIdentity(void); void glLoadMatrixf(const float* m); void glMultMatrixf(const float* m); void glLoadTransposeMatrixf(const float* m); void glMultTransposeMatrixf(const float* m);
OpenGL中矩阵乘法:假设当前矩阵是C,glMultMatrixf等函数指定的矩阵是M,相乘后结果为CM,并存储在之前C中。
OpenGL中的矩阵与C语言中的矩阵行列相反,M[i][j]表示第i列第j行。
2. 视图和模型变换
2.1 变换的顺序
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(N); /* apply transformation N */
glMultMatrixf(M); /* apply transformation M */
glMultMatrixf(L); /* apply transformation L */
glBegin(GL_POINTS);
glVertex3f(v); /* draw transformed vertex v */
glEnd();
模视矩阵按顺序包含了I, N, NM, NML
,定点变换则是N(M(Lv))
,即v首先与L相乘、Lv与M相乘、MLv与N相乘。
例如想将原点的物体变换为倾斜30°、位于x轴5.0处,则需要先旋转,再沿x轴平移。为此调用步骤如下:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(T); /* translation */
glMultMatrixf(R); /* rotation */
draw_the_object();
2.2 模型变换
首先确保处于模视矩阵下:
glMatrixMode(GL_MODELVIEW);
然后使用如下变换函数:
void glTranslatef(float x, float y,float z);
void glRotatef(float angle, float x,float y,float z);
void glScalef(float x, float y, float z);
2.3 视图变换
视图变换用于修改观察点的位置和方向。按照流水线最先进行的是物体的模型变换,那么视图变换函数必须在调用任何模型变换函数之前调用,以确保首先作用于物体的是模型变换(不要confusing)
第一种方法是仍然使用上述模型变换的函数,但是做眼坐标的逆操作。更常用且方便的是使用gluLookAt()
.
2.4 投影变换
首先确保处于投影矩阵下:
glMatrixMode(GL_PROJECTION);
-
透视投影
透视投影显著特征就是近大远小,因为透视投影的视景体是金字塔的平截头体。
void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
创建一个表示透视视图平截头体的矩阵,并与当前矩阵相乘。更常用且方便的是使用
gluPerspective()
. -
正投影
正投影下视景体是一个平行的长方体,物体与照相机的距离不影响看上去的大小,常用于CAD。
void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
与
glFrustum
类似。如果是将二维图像投影到二维屏幕可以使用gluOrtho2D
.
2.5 视口变换
使用glViewPort()
函数能够选择绘图区域,例如对窗口划分,在同一个窗口显示分割屏幕的效果以显示多个视图。
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
3. 矩阵堆栈
假如绘制车身和轮子:绘制车身、记住位置、移动到右前轮、绘制轮子、丢弃移动到右前轮的操作回到车身、移动到左前轮……
变换是以矩阵存储的,因此使用矩阵堆栈可以理想地解决这个问题。
void glPushMatrix();
void glPopMatrix();
-
模视矩阵堆栈
例如上述车身与车轮的例子
-
投影矩阵堆栈
一般情况下不需要对投影矩阵进行组合,因此执行投影变换前需要调用
glLoadIdentity()
。如果要显示一个包含文本的帮助窗口,由于文本在正投影模式下容易定位,因此在显示help窗口时可以暂时把投影矩阵设置成正投影,然后再返回到原来的透视投影。glMatrixMode(GL_PROJECTION); glPushMatrix(); /*save the current projection*/ glLoadIdentity(); glOrtho(...); /*set up for displaying help*/ display_the_help(); glPopMatrix();
4. 逆变换与模拟变换
流水线使用视图与投影矩阵将顶点的世界坐标变换为屏幕坐标,但有时候需要反转这一过程,例如根据鼠标位置返回三维坐标。
int gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
const GLdouble modelMatrix[16],
const GLdouble projMatrix[16],
const GLint viewport[4],
GLdouble *objx, GLdouble *objy, GLdouble *objz);
- 窗口坐标: winx, winy, winz
- 模视矩阵:modelMatrix
- 投影矩阵:projMatrix
- 视口:viewport
- 世界坐标:objx, objy, objz
其中winz表示窗口坐标的z值,即照相机金字塔平截头的zNear ~ zFar, 标准深度下为0~1. 非标准深度下需要使用另一个函数gluUnProject4
int gluProject(GLdouble objx, GLdouble objy, GLdouble objz,
const GLdouble modelMatrix[16],
const GLdouble projMatrix[16],
const GLint viewport[4],
GLdouble *winx, GLdouble *winy, GLdouble *winz);
与gluUnProject
相对的逆操作,根据世界坐标计算屏幕坐标。
- 如果这篇文章对您有帮助,请到CSDN博客留言;
- 转载请注明:来自雨润的技术博客 http://blog.csdn.net/sunyurun