OpenGL学习笔记(二):视图

作者:yurunsun@gmail.com 新浪微博@孙雨润 新浪博客 CSDN博客

日期: 2013-6-12

本章内容:

  1. 流水线与变换
  2. 模型变换
  3. 视图变换
  4. 投影变换
  5. 操作矩阵
  6. 逆变换与模拟变换

1. 流水线与变换

1.1 三维几何流水线

三维几何流水线是将三维点转换成二维点的一系列过程:

三维模型坐标 ---> 三维世界坐标 ---> 三维眼坐标 ---> 三维眼坐标 ---> 二维眼坐标 ---> 二维屏幕坐标
                |               |               |           |               |
            模型变换            视图变换            裁剪          投影          窗口到视口映射
  1. 场景

    场景是在图像中显示的三维空间对象组合,包括空间中所有几何对象与光照

  2. 视图

    视图是用于创建图像的信息集,包括场景空间、场景坐标系、坐标系眼视点、投影操作

  3. 建模

    建模是创建并定义几何体的过程

  4. 三维模型坐标系 vs 三维世界坐标系

    建模过程是将每个对象在其方便并有意义的坐标系中定义好,再经过一系列模型变换将对象变换到统一空间的坐标系。前者是模型坐标系,后者是世界坐标系。

  5. 三维眼坐标系

    从观察点出发的坐标系

1.2 变换简介

OpenGL将模型变换与视图变换组合在一起,共用一个矩阵(模型视图矩阵 GL_MODELVIEW)。这样做之所以可行是因为两者本身就是相对而言的,将照相机沿Z轴移动5个单位相当于所有物体在世界坐标系下反方向移动5个单位。

  1. 模型变换

    模型变换的目的是设置模型的位置和方向:旋转、移动和缩放

  2. 视图变换

    视图变换相当于把照相机固定在三脚架上并使其对准场景

  3. 投影变换

    投影变换相当于为照相机选择镜头,即确定视野

  4. 视口变换

    投影变换指定了映射的发生机制,视口变换决定了有效屏幕区域的形状。

  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);
  1. 透视投影

    透视投影显著特征就是近大远小,因为透视投影的视景体是金字塔的平截头体。

    void glFrustum(GLdouble left, GLdouble right, 
                    GLdouble bottom, GLdouble top,
                    GLdouble near, GLdouble far);
    

    创建一个表示透视视图平截头体的矩阵,并与当前矩阵相乘。更常用且方便的是使用gluPerspective().

  2. 正投影

    正投影下视景体是一个平行的长方体,物体与照相机的距离不影响看上去的大小,常用于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();
  1. 模视矩阵堆栈

    例如上述车身与车轮的例子

  2. 投影矩阵堆栈

    一般情况下不需要对投影矩阵进行组合,因此执行投影变换前需要调用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相对的逆操作,根据世界坐标计算屏幕坐标。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值