视图--2

用于一般变换的一些函数:

1. void glMatrixMode (GLenum mode) ---在进行变换之前, 程序员必须声明是否需要修改模型视图矩阵或者投影矩阵。这样OPENGL可以根据不同的模式,来对变换进行操作。

mode有三种: GL_MODELVIEW ----当前矩阵为模型视图矩阵
       GL_PROJECTION-------------投影矩阵
       GL_TEXTURE   ---------------纹理矩阵

2. void glLoadIdentity() 把当前矩阵置为4X4单位矩阵。
矩阵有关的操作:

 glLoadMatrixf (const GLfloat *m); 可以自己m矩阵置为当前矩阵。

glMultMatrixf (const GLfloat *m); 将当前矩阵与m矩阵相乘(注意:矩阵不满足交换律)。

为了提供程序运行的效率, 可以使用显示列表存储经常用到的矩阵和它们的转置矩阵。 

 

视图变换和模型变换

因为上面两者是相关联的, 实际上,可以将它们结合为一个单一的模型视图矩阵。

记得在视图变换或模型变换之前,设置glMatrixMode 为GL_MODELVIEW。

一个例子: 以原点为圆心, 绕z轴逆时针45度的旋转和沿x轴的平移。 与先沿x轴平移,再以原点为圆心, 绕z轴逆时针45度的旋转 得到的效果两者是完全不同的。

确定变换的顺序: 每一个glMultMatrixf都是由上一个变换得到的当前模型视图矩阵C的基础上, 乘以该变换函数指定的矩阵M, 得到一个新的当前矩阵 C*M,然后这个矩阵作用与顶点v上, CMv, 按照对顶点来讲, 首先M作用于v,得到Mv, 然后C作用与Mv, 才得到CMv, 这与我们写代码的顺序是相反的。

全局固定坐标系:

在该坐标系下进行的矩阵相乘, 将影响到模型的位置,方向和变换比例,而且必须以与期望的变换顺序相反的方式考虑加在代码中的变换函数的先后顺序。

如: 想对物体先进行绕z轴的逆时针45度旋转,再进行x方向的3单位平移:

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glTranslatef(3, 0, 0);  // translation ==> glMultMatrixf(T); T is tanslation matrix.
  
    glRotatef(45, 0, 0, 1); // rotation  ==> glMultMatrixf(R); R is rotation matrix.
    draw_the_object();

 

局部坐标系的移动:

假想一个与所画物体捆绑在一起的局部坐标系, 所有的变换都相对于这一不断变换的坐标系进行。考虑刚才上面的那个例子:

1. 想象物体和局部坐标系捆绑在一起

2. 平移操作将沿X轴同时移动物体和其局部坐标系

3. 旋转操作使得物体和其局部坐标系同时绕局部坐标原点旋转, 其结果是变换后的物体坐标仍然在局部坐标系的X轴上。

 

模型变换:

平移:glTranslate*();  旋转:glRotate*();放缩:glScale*();或者glMultMatrix×(M), M是相应的变换矩阵。但是最好用前面的那些函数, 它速度更快, 而且OPENGL会自动计算这些矩阵。

glTranslatef (GLfloat x, GLfloat y, GLfloat z);与当前矩阵相乘,使物体沿三个坐标轴发生平移:平移距离大小为x, y, z。

glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); 当前矩阵乘以一个矩阵,该矩阵使得一个物体绕方向为x, y, z 的线, 逆时针方向旋转angle角度。

glScalef (GLfloat x, GLfloat y, GLfloat z);  与当前矩阵相乘, 使得物体沿坐标轴拉伸、缩短以及相对于坐标轴做镜面反射。除非在迫不得已的情况下, 因为变换之间的相互影响, 通常应该尽量避免使用该函数,同时法线向量在经过变换后,必须再次归一化,这样降低了光照计算的性能。

 

视图变换

视图变换操作将改变视点的位置和方向。 与我们人来讲, 我们首先站在什么地方, 然后头朝哪个方向, 我们可以左右歪着头(可以想象一下)。

gluLookAt 的前三个参数是人的位置坐标(比如我在北京和我在上海坐标是不一样的), 中间三个参数是人面朝哪个方向(比如朝东,朝西南),

最后三个参数是头的位置(比如头看作手表的秒针, 头指向3点钟方向, 指向6点钟方向)。

视图变换通常也包括平移和旋转两个过程。

当然要在最终的图像或照片中获得某一场景, 既可以通过移动照相机, 也可以通过将所有的物体对象做反向移动来实现。

最后注意的是: 必须在执行模型变换函数之前调用视图变换函数,以保证场景中的物体先做模型变换,再做视图变换,这样可以使得模型变换首先对物体起作用。

视图变换的几种操作方法:

1. 使用一个或多个模型变换函数。

2. 使用OPENGL实用子程序库的函数gluLookAt()定义的一条视线。该程序封装了一系列的旋转和平移。

3. 创建用户自己的实用子程序库,在子程序中封装各种旋转和平移函数。

我们这里讲一下gluLookAt这个函数:

void APIENTRY gluLookAt (
    GLdouble eyex, 
    GLdouble eyey, 
    GLdouble eyez, 
    GLdouble centerx, 
    GLdouble centery, 
    GLdouble centerz, 
    GLdouble upx, 
    GLdouble upy, 
    GLdouble upz);

前三个指定视点的位置, 中间三个定义一个相机指定的参考点, 后三个指定哪一个方向上。

视点的默认位置和方向: 原点和沿z轴的负向。

上面的参考点是指你视野的中心, 后三个方向可以这样理解, 假如你眼睛看物体,头正摆,方向向量为 (0, 1, 0),当把方向向量改为(1, 0, 0), 则相当于你把头歪摆着看到的物体。

投影变换:

投影矩阵也用于场景中的顶点变换。

首先要调用:

 glLoadIdentity();
 glMatrixMode(GL_PROJECTION);

投影变换的目的是为了定义一个视图体, 视图体决定是正交投影还是透视投影, 还有可以对物体的那些部分进行裁剪。

透视投影: 距离照相机越远的物体,在图像上显的越小。视图体是一个棱锥的平台体, 透视 就是把处在视图体内的物体向角锥的顶点投影,投影到远截面。

函数glFrustum() 定义了一个平截台体,该函数实现透视投影矩阵的计算并将计算得到的矩阵左乘于当前投影矩阵。一个视图体由六个面组成: 前后两个截面以及四个侧面, 位于这些裁剪面外的物体,将被去掉,不画在平面上。

void glFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);

(left, bottom, -zNear) 和 (right, top, -zFar)是近裁剪面的左下角和右上角的坐标值。 zNear 和 zFar 始终为正值。

平台体在三维空间中,有一个默认的方向, 可以通过对投影矩阵的旋转和平移来改变这一方向。但是通常没必要这样做。

如果希望得到两倍于屏幕的分辨率, 可以将同一个图像画四次, 每一次用平截台体覆盖整个屏幕时, 只用到四分之一的图像,。在每一部分图像经过渲染之后,可以读取所有的像素点数据,来组成更高分辨率的图像了。

但是有一个更加直观的函数:

    /*void APIENTRY gluPerspective(
        GLdouble fovy,  // fovy :  在x-z平面内视区的角度,其值必须在【0,180】度
        GLdouble aspect, // 长宽比,是平截台的宽度和高度之比。
        GLdouble zNear,  //  视点到近截面的距离
        GLdouble zFar);*/ // 视点到远截面的距离

对于透视投影和其他变换实质上是没有单位的。然而唯一一点要注意的是: 所有的测量单位应该一致, 最后按照一定的比例画出图像。

 

正交投影也有的平台截面图体是长方体, 可以用

glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); 参数的意义和上面那个函数是一样的。

视区变换:

视区变换是与选择照片尺寸这一任务相对应的。视区就是用来绘制图像窗口中的一个矩形区域。这个视区是以窗口坐标来度量的,他反映了相对于窗口左下角的屏幕像素的位置。该视区内所有的顶点的变换都是根据模型视图矩阵和投影矩阵进行的。

glViewport (GLint x, GLint y, GLsizei width, GLsizei height); x, y 是相对于左下角的坐标, width 和 height 是定义视区的宽度和高度。

通常视区的长宽比应该和视图体的长宽比相等, 否则将投影到视区时,图像将会发生扭曲。

 

在视区变换之间,对深度z坐标进行变换, 利用函数glDepthRange() 可以将z坐标的值通过缩放操作变换到期望的范围之内。opengl在处理z坐标时, 

认为其值变化范围在【0,1】 ,

glDepthRange (GLclampd zNear, GLclampd zFar);

zNear : 表示存储在深度缓存中的最小值.

zFar :表示最大值.

在透视投影的情况下, 变换后的深度坐标需要对其做透视除法, 及将这些值除以w坐标.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值