OpenGl 游戏编程笔记 第三章: OpenGL 状态和图元 (三)
OpenGl 游戏编程笔记 第四章: 变换和矩阵(二)

OpenGl 游戏编程笔记 第四章: 变换和矩阵(一)

皮贝贝 posted @ 2010年4月02日 17:22 in opengl with tags OpenGL game 游戏 , 5888 阅读

OpenGl 游戏编程笔记 第四章: 变换和矩阵(一)

本章你将学到

  • 坐标系转换的基本知识
  • 相机和视景转换
  • OpenGL 的矩阵和矩阵栈
  • 投影
  • 在 OpenGL 中使用自己的矩阵

1 理解坐标系转换

变换有主要有四种:

  • 模型变换 (Modeling transformation)
  • 视点变换 (Viewing transformation)
  • 投影变换 (Projection transformation)
  • 视口变换 (Viewport transformation)

在 3D 编程中, 要注意变换的顺序. 模型视点变换需要在投影变换前执行. 视口变换 可以在任何地方, OpenGL 会自动调整应用.


变换 描述
视点变换(Viewing) 指定相机位置
模型变换(Modeling) 在场景中移动物体
投影变换(Projection) 定义了观看量(焦长)和裁剪机
视口变换(Viewport) 从场景中映射到渲染的2D窗口上
模型视点变换(Modelview) 视点变换+模型变换

1.1 视点坐标 (Eye Coordinates)

值得是基于视点位置的坐标系统, 沿着正 z 轴的方向放置取景器. 向下看可以看到负 z 轴.

1.2 视点变换 (Viewing Transformations)

视点转换用于放置相机的位置和方向. 如前所述, 相机的默认位置是在坐标原点, 朝向负 z 轴.

视点变换必须在任何模型变换(Modeling transformations) 之前指定, 因为在 OpenGL 的 变换中, 变换是按反序来实施应用的. 通过先指定视点变换, 这样你就保证了在模型变换之后被应用.

如何创建一个视点变换呢? 首先需要清除当前的矩阵, 这可以通过 glLoadIdentity() 实现:


void glLoadIdentity();

会将当前矩阵设为单位矩阵.

单位矩阵: 对角线上的元素都是1, 其余都是0. 如 4* 4 的单位矩阵M : 
M(0,0) = M(1,1)=M(2,2)=M(3,3)=1. 任何矩阵 I 与 单位矩阵 M
的乘积等于单位矩阵 M: I * M = M.

初始化完当前矩阵后, 就可以通过多种方式来创建视点矩阵.一种方式是让 视点矩阵等于单位矩阵. 这会将相机定位到默认的位置(视点坐标)上, 在 坐标系的原点,且面对负 z 轴. 还有其他的几种方式:

  • 使用 gluLookAt() 来指定从相机中出来的一条光线.
  • 使用变换和旋转命令: glTranslate() , glRotate() .可以理解为

移动或转动相机前面的物体.

  • 利用变换和旋转函数来为你的坐标系创建自己的扩展.

1.3 模型变换 (Modeling Transformations)

模型变换可以让你通过移动,旋转或改变尺寸来放置一个模型. 有三种操纵物体模型的操作:

  • 变换. 就是顺着指定的向量来移动.
  • 旋转. 根据向量来旋转.
  • 调节尺寸.

指定这些模型变换的顺序对你的场景渲染非常重要, 不同的顺序可能导致不同的效果.

1.4 投影变换 (Projection Transformations)

投影变换定义了观看量和裁剪机. 在模型变换和视点变换之后被应用. 可以理解为对相机 进行调焦. OpenGL 支持两种投影:

  • 立体投影. 看起来和真实世界的物体一样真实. 物体看起来要比真实尺寸小.
  • 正交投影. 物体在屏幕上显示的尺寸是真实尺寸, 不管离相机多远.

1.5 视口变换 (Viewport Transformations)

最后一个变换是视口变换. 视口变换就是将视景体内投影的物体显示在二维的视口平面上. 可以想象为对最终的照片进行放大或缩小.

2 矩阵

2.1 模型视点矩阵 (Modelview matrix)

模型视点矩阵定义了一个可以放置物体的坐标系.

在调用任何变换之前, 你必须指定修饰的是模型视点矩阵还是投影矩阵. 可以通过 glMatrixMode() 来指定:


void glMatrixMode(GLenum mode);

为了修饰模型视点矩阵, 你需要指定 mode 为 GL_MODEVIEW. 这会将模型视点 矩阵设置为当前矩阵, 意味着接下来的一些操作都是针对模型视点矩阵的.

mode 还可以取值 GL_PROJECTION, GL_COLOR, GL_TEXTURE. 分别操作 投影矩阵, 颜色矩阵, 纹理矩阵.

我们常常在渲染循环开始, 将模型视点矩阵设为默认的 (0,0,0), 面向负 z 轴. 可以通过 glLoadIdentity() 函数实现, 这个函数将当前的矩阵(模型视点 矩阵)设置为单位矩阵:

 

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

2.2 变换 (Translation)

变换允许我们将一个物体从一个位置移动到另一个位置.主要移动函数是:


void glTranslate{fd}(TYPE x, TYPE y, TYPE z);

 

glTranslate(3.0f, 1.0f, 8.0f);


 

指的是物体顺着 x 轴正方向移动 3 个单位, y 轴正方向移动 1 个单位, z 轴 正方向移动 8 个单位. 新的物体坐标是 (3,1,8).

再如我们希望将一个方块从原点移动到 (5,5,5) 处, 我们可以先将模型视点矩阵设为 单位矩阵, 这样就在 (0,0,0) 点处了, 然后通过变换移动到 (5,5,5) 处, 最后 调用 DrawCube() 来完成绘制方块:

 

glMatrixMode(GL_MODEVIEW);
glLoadIdentity();
glTranslatef(5.0f, 5.0f, 5.0f);
DrawCube();


 

2.3 旋转 (Rotation)

旋转主要是通过函数 glRotate() 来完成的:


void glRotate{fd}(TYPE angle, TYPE x, TYPE y, TYPE z);

这将会围绕向量 (x, y, z) 进行角度 angle 的逆时针方向进行旋转.

如果你希望围绕着 y 轴旋转 135 度:

 

glRotate(135.0f, 0.0f, 1.0f, 0.0f);


 

如果你希望顺时针旋转, 需要将角度设为整数, 如上例, 135 度顺时针旋转:

 

glRotate(-135.0f, 0.0f, 1.0f, 0.0f);


 

不同的旋转顺序导致不同的效果, 因为前一个旋转已经改变了坐标系.

2.4 调整大小

调整大小, 主要是调整物体或坐标系的大小.


void glScale{fd}(GLfloat x, GLfloat y, GLfloat z);

参数x, y, z指的是在每个坐标轴(x,y,z)上的乘积因子.如

 

glScalef(2.0f, 2.0f, 2.0f);


 

假若我们要绘制一个1*1*1大小的方块, 遇到上面一行后,会在屏幕上绘制出一个 2*2*2 的方块.

利用 glScalef() 我们可以对一个物体进行放大或缩小, 当乘积因子大于1.0便是放大, 小于1.0便是缩小. 参数也可以是负数.

2.5 矩阵栈

在 OpenGL 中存在4中矩阵栈:

  • 模型视点矩阵栈
  • 投影矩阵栈
  • 颜色矩阵栈
  • 纹理矩阵栈

矩阵栈的作用. 模型视点矩阵栈可以让我们可以保存当前的转换矩阵状态, 然后可以通过从矩阵栈中恢复从而不必 再重新计算. 投影矩阵栈, 颜色矩阵栈和纹理矩阵栈可以做其他的事.

矩阵栈的操作主要有保存或恢复. 通过函数 glPushMatrix() 将当前的矩阵压入矩阵栈中. 函数 glPopMatrix() 从栈中取出一个矩阵, 并恢复之:


void glPushMatrix();
void glPopMatrix();

矩阵栈的信息获取. 可以通过 glGet() 的 GL_MAX_MODELVIEW_STACK_DEPTH, GL_MAX_PROJECTION_STACK_DEPTH, GL_MAX_COLOR_STACK_DEPTH, GL_MAX_TEXTURE_STACK_DEPTH 来获知相应矩阵栈的深度信息. 一般来说, 模型视点 矩阵栈的最小深度是 32, 其他的矩阵栈的最小深度是 2.

当矩阵栈中有足够多的矩阵时, glPushMatrix() 会引发 GL_STACK_OVERFLOW 错误. 当矩阵中只有一个矩阵时, glPopMatrix() 会引发 GL_STACK_UNDERFLOW 错误.


 

Date: 2010-04-02 09:15:44

HTML generated by org-mode 6.30c in emacs 23

 

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter