OpenGL 坐标变换(2)

来源:互联网 发布:mac 登flickr 编辑:程序博客网 时间:2024/04/27 08:10

1.全局把握-OpenGL中的坐标变换

     OpenGL中的点,从用户构造模型的局部坐标系,经过一系列处理最终渲染到屏幕坐标系下,才形成了3D图形。

    这里的主要变换过程如下图所示:

     

       注意:

     1)OpenGL绘制管线,以前是基于固定功能的绘制管线(fixed-function pipeline),OpenGL3.1以后移除了固定功能的绘制管线,取而代之使用着色器来进行绘制。OpenGL绘制管线的历史可以参看新墨西哥大学的图形学课件 。

       与在程序当中使用glTranslate、gluLookAt等函数生成变换矩阵相比,使用着色器方式,利用uniform变量传递变换矩阵到着色器完成坐标变换。典型着色器代码可能如下:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. #version 330  
  2.   
  3. layout(location = 0) in vec4 position;  
  4.   
  5. uniform mat4 cameraToClipMatrix;  
  6. uniform mat4 worldToCameraMatrix;  
  7. uniform mat4 modelToWorldMatrix;  
  8.   
  9. void main()  
  10. {  
  11.     vec4 temp = modelToWorldMatrix * position;  
  12.     temp = worldToCameraMatrix * temp;  
  13.     gl_Position = cameraToClipMatrix * temp;  
  14. }  

    2)在实际当中,根本不存在单独地model,view transformation,而是将这两次变换组合成一个模式变换Model-View transform来执行。

    3)实际上,OpenGL只定义了裁剪坐标系、规范化设备坐标系和屏幕坐标系,而局部坐标系、世界坐标系和照相机坐标系都是为了方便用户设计而自定义的坐标系。用户进行和OpenGL完成的转换如下图所示(来自[2]):

   

   从坐标的角度来看,过程如下所示:

   

2. 从模型坐标系到世界坐标系

     这里强调一下OpenGL默认情况,这对理解变换很重要。

    1)在固定功能绘制管线下,默认情况下OpenGL里model-view 和projection矩阵都是单位阵。如果没有应用任何变换,对象坐标系和世界坐标系是相同的。同时默认情形下,对象坐标系、照相机坐标系和裁剪坐标系3个坐标系是重合的。

   2)默认情况下,OpenGL执行正交投影;照相机位于世界坐标系原点,照相机指向-Z轴方向,照相机正向为+Y轴方向。

    模型坐标系主要用于设计模型,在此阶段我们根本无需关心最终对象显示在屏幕哪个位置。

如下图几个图形的局部坐标系如下:

 

    在OpenGL中缓存对象(buffer object)中保存,以及旧版本中使用的glVertex3f等函数指定的都是局部坐标系中的坐标。

    所谓从模型坐标系转换到世界坐标系,也就是将物体局部坐标转换到世界坐标系下坐标。

   例如下图3个茶壶都在自己的局部坐标系下定义(来自[3]):

    

通过对3个茶壶实施模型转换,将他们转换到世界坐标系下如下图所示:

    

     模型变换包括平移(translation)、旋转(rotation)、缩放(scaling)等等。

    这里并不打算推导出全部变换矩阵,以平移变换为例。我们把点p按照向量d所指示的方向和距离移动到p',则有:

    p' = p+d;

   写成其次坐标形式为:

    

采用分量形式表示平移变换:

    

    利用矩阵乘法表达同样的结果为:p'=Tp,其中:

    

    T矩阵称为平移矩阵。

    实际上,利用上篇里介绍的方法能够很快写出矩阵T,因为变换后x,y,z轴不变,则前3列为单位向量,分别表示x,y,z轴。

    假设之前原点在(0,0,0,1),只是原点移动了d,所以只需改动第四列为移动后原点的位置即可。

   这里以2D平移为例,进行说明。平移之前,世界坐标系和对象坐标系是重合的,经过d(3,2)平移后,对象坐标系平移到图中绿色区域。设对象坐标系下一点,红色点p(1,1),那么平移之后该点在世界坐标系中的位置为p'(4,3),如下图所示:

  

     计算过程如下:

     d=(2,3),则平移矩阵T为:

   

   这个矩阵即上篇中所讲的M矩阵的转置,那么经过变换后,点p'位置为:

  

         对象坐标系中的点(1,1)经过变换后,在对象坐标系坐标是不变的,但是从世界坐标系的角度来解释,即变为了(4,3)。

        注意这里,世界坐标系和对象坐标系在应用任何变换之前是重合的这一点。

        对于其余的变换的推导和应用,可以参考任何一本图形学教材,这里不再展开。

3.从世界坐标系到照相机坐标系

      实际上,照相机的指向的位置、观察正方向(vup)都是在世界坐标系下指定的,如下图所示:

     

       那么为什么要将世界坐标转换到照相机坐标系呢?

       自己总结一个观点。因为最终的成像都要通过照相机模型来进行,我们将世界坐标系中位置转换到照相机坐标系来进行,能够简化数学。实际上这个转换可以理解为,从照相机看到的世界坐标系中场景是什么样子。

        在现实当中,我们通过移动相机来观察物体;注意,OpenGL之中,相机是固定位于(0,0,0)并朝向-Z轴的,我们通过移动场景来完成这个转换。关于这个问题,比较有参考价值的解释就是问答列表Why do we move the world instead of the camera?

        这里举一个例子。比如,一个物体中心位于原点,照相机也位于初始位置原点,方向指向-Z轴。为了对物体的+Z面成像,那么必须将照相机从原点移走,如果照相机仍然指向-Z轴,需要将照相机沿着+Z轴方向后退。假若照相机不移动,我们可以通过将物体沿着-Z轴后退d个单位,则变换矩阵为:

   

    我们要形成的一个观点就是: 场景不动时,移动照相机等价于照相机不动,以逆变换的形式变换场景。

    从世界坐标系变换到照相机坐标系,有多种指定相机的方式。这里只介绍利用gluLookAt函数构造的UVN相机坐标系,具体的模型机矩阵推导过程可以参看我的博客《OpenGL学习脚印: 关于gluLookAt函数的理解》。

4. 从照相机坐标系到裁剪坐标系

    相机坐标系到裁剪坐标系是通过投影完成的。

    投影就是将物体投影到投影平面的过程。因为OpenGL使用的是虚拟相机成像模型,因此也使用了正交投影和透视投影两种方式。

    实际上,投影有很多种类,这里稍微整理下常见的平行投影和透视投影。
     平行投影的投影线相互平行,投影的结果与原物体的大小相等,因此广泛地应用于工程制图等方面。正交投影是平行投影的一种特殊情形,正交投影的投影线垂直于观察平面。

    透视投影的投影线相交于一点,因此投影的结果与原物体的实际大小并不一致,而是会近大远小。因
此透视投影更接近于真实世界的投影方式。
    两者的示意图如下:

   

    OpenGL之中使用glOrtho(xleft, xright, ybottom, ytop, znear, zfar);指定正交投影,参数意义形象表示为下图所示:

   

    OpenGL中使用

    void glFrustum(GLdouble  left,  GLdouble  right,  GLdouble  bottom,  GLdouble  top,  GLdouble  nearVal,  GLdouble  farVal);
    或者使用

   void gluPerspective(GLdouble  fovy,  GLdouble  aspect,  GLdouble  zNear,  GLdouble  zFar);来指定透视投影的视锥。

  形象的表达为:

 

   关于投影矩阵的推导可以参看我翻译的博客《OpenGL学习脚印: 投影矩阵的推导》一文,这里不再展开。

5.从裁剪坐标系到规范化设备坐标系

   这一转换是简单的,只要执行透视除法即可。即将裁剪坐标系下坐标的x,y,z分量除以w分量即可。

6.从规范化设备坐标系到屏幕坐标系

   从规范化设备坐标系到屏幕坐标系的映射,基本上是一个线性映射关系,关于这个变换矩阵的推导,可以参见我翻译的博客《OpenGL学习脚印: OpenGL 坐标变换》。


0 0