转自:http://blog.sina.com.cn/s/blog_957b9fdb0100zesv.html

为了说明在三维物体到二维图象之间,需要经过什么样的变换,我们引入了相机(Camera)模拟的方式,假定用相机来拍摄这个世界,那么在相机的取景器中,就存在人眼和现实世界之间的一个变换过程。

   
 第一步:视点变换(如同拍照的时候设置相机的位置)
         在拍照的时候,我们首先要将相机置于三角架上,让它对准三维场景。在OpenGL中调整视点的位置就像是是要放置相机一样,我们称之为视点变换(Viewing Transformation)。
 
         视点变换确定了场景中物体的视点(即相机)的位置和方向,让相机对准要拍摄的物体。缺省时,相机(即视点)定位在世界坐标系的原点,(注意:初始时世界坐标系和当前绘图坐标系位于相同的位置);相机的初始方向都指向Z负轴。
         初始情况下,相机和物体都位于世界坐标系的原点,即相机(视点)与物体是重叠的。试想一下,在用相机拍摄物体时,我们可以保持物体的位置不动,而将相机移离物体,这就相当于视点变换。
 
        视点变换函数gluLookAt():         OpenGL实用库提供了gluLookAt()函数,该函数有三个变量,分别定义了视点的位置、相机瞄准方向的参考点以及相机的向上方向。该函数的原型为:
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble upx,GLdouble upy,GLdouble upz);
      该函数定义了视点矩阵,并用该矩阵乘以当前矩阵。eyex,eyey,eyez定义了视点的位置;centerx、centery和centerz变量指定了参考点的位置,该点通常为相机所瞄准的场景中心轴线上的点;upx、upy、upz变量指定了向上向量的方向。
   
        使用这个函数之后,只设定好了视点(相机)的位置了。

第二步:模型变换(如同拍照时调整三维物体的位置)

       在拍照时,我们也可以保持相机的固定位置,将物体移离相机以将三维物体摆放在场景中的适当位置。在OpenGL中,对物体的显示位置方向的设置就与之类似,我们称之为模型变换(Modeling Transformation)。而显示位置与当前的绘图坐标系密切相关,因为物体总是在当前的绘图坐标系中进行绘制的,因此实际上模型变换可以说就是对当前绘图坐标系位置的变换,这一变换是在世界坐标系下进行的。 
      
      设置物体位置涉及到即对模型进行旋转、平移和缩放。缺省时,物体模型(即绘图坐标系)的中心定位在世界坐标系的中心处。OpenGL在这个坐标系中,有如下三个函数来实现模型变换。
     1、模型平移
 
glTranslate{fd}(TYPE x,TYPE y,TYPE z);
      该函数用指定的x,y,z值沿着(世界坐标系的)x轴、y轴、z轴移动绘图坐标系(也即是按照相同的量值平移物体)。   
       2、模型旋转
 
glRotate{fd}(TYPE angle,TYPE x,TYPE,y,TYPE z);
      该函数中第一个变量angle制定模型旋转的角度,单位为度,后三个变量表示以世界坐标系下的原点(0,0,0)到点(x,y,z)的连线为轴线逆时针旋转绘图坐标系。例如,glRotatef(45.0,0.0,0.0,1.0)的结果是绕z轴旋转45度。
     3、模型缩放
 
glScale{fd}(TYPE x,TYPE y,TYPE z);
     该函数可以对物体沿着x,y,z轴分别进行放大缩小。函数中的三个参数分别是x、y、z轴方向的比例变换因子。缺省时都为1.0,即物体没变化。程序中物体Y轴比例为2.0,其余都为1.0,就是说将立方体变成长方体。
      注意:通常,视点转换操作在模型转换操作之前发出,以便模型转换先对物体发生作用。场景中物体的顶点经过模型转换之后移动到所希望的位置,然后再对场景进行视点定位等操作。模型转换和视点转换共同构成模型视景矩阵。
 
第三步:投影变换(就如同拍照中的选镜头并调焦距)
        在相机和物体都放好后,我们要选择相机镜头并调焦拍照,使三维物体投影在二维胶片上。与之类似,OpenGL中把三维模型投影到二维屏幕上的过程,即OpenGL的投影变换(Projection Transformation)。
 
        为了使显示的物体能以合适的位置、大小和方向显示出来,必须要通过投影来降低维数。事实上,投影变换的目的就是定义一个视景体,使得视景体外多余的部分裁剪掉,最终进入图像的只是视景体内的有关部分。投影包括透视投影(Perspective Projection)和正视投影(Orthographic Projection)两种。
 
       1. 透视投影          
         透视投影符合人们心理习惯,即离视点近的物体大,离视点远的物体小,远到极点即为消失,成为灭点。它的视景体类似于一个顶部和底部都被进行切割过的棱椎,也就是棱台。这个投影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面。
      OpenGL透视投影函数有两个glFrustum()和gluPerspective()。
  
 (1)函数glFrustum():
 
void glFrustum(GLdouble left,GLdouble Right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far);
      它创建一个透视视景体。其操作是创建一个透视投影矩阵,并且用这个矩阵乘以当前矩阵(三维物体的各个顶点坐标组成的矩阵)。这个函数的参数只定义近裁剪平面的左下角点和右上角点的三维空间坐标,即(left,bottom,-near)和(right,top,-near);最后一个参数far是远裁剪平面的Z负值,其左下角点和右上角点空间坐标由函数根据透视投影原理自动生成。near和far表示离视点的远近,它们总为正值。该函数形成的视景体如图三所示。
图三、透视投影视景体
  (2)透视函数gluPerspective()是:
void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear, GLdouble zFar);
      它也创建一个对称透视视景体,但它的参数定义于前面的不同,参数fovy定义视野在X-Z平面的角度,范围是[0.0, 180.0];参数aspect是投影平面宽度与高度的比率;参数zNear和Far分别是远近裁剪面沿Z负轴到视点的距离,它们总为正值。
图四、透视投影视景体
       以上两个函数缺省时,视点都在原点,视线沿Z轴指向负方向。
 
      2.正射投影
     正射投影,又叫平行投影。这种投影的视景体是一个矩形的平行管道,也就是一个长方体,如图五所示。正射投影的最大一个特点是无论物体距离相机多远,投影后的物体大小尺寸不变。这种投影通常用在建筑蓝图绘制和计算机辅助设计等方面,这些行业要求投影后的物体尺寸及相互间的角度不变,以便施工或制造时物体比例大小正确。
     图五、正射投影视景体
       OpenGL正射投影函数也有两个, glOrtho()和gluOrtho2D()     (1)glOrtho():
 
void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top, GLdouble near,GLdouble far)
       它创建一个平行视景体。实际上这个函数的操作是创建一个正射投影矩阵,并且用这个矩阵乘以当前矩阵。其中近裁剪平面是一个矩形,矩形左下角点三维空间坐标是(left,bottom,-near),右上角点是(right,top,-near);远裁剪平面也是一个矩形,左下角点空间坐标是(left,bottom,-far),右上角点是(right,top,-far)。所有的near和far值同时为正或同时为负。如果没有其他变换,正射投影的方向平行于Z轴,且视点朝向Z负轴。这意味着物体在视点前面时far和near都为负值,物体在视点后面时far和near都为正值。
  (2)gluOrtho2D():
void gluOrtho2D(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)
     它是一个特殊的正射投影函数,主要用于二维图像到二维屏幕上的投影。它的near和far缺省值分别为-1.0和1.0,所有二维物体的Z坐标都为0.0。因此它的裁剪面是一个左下角点为(left,bottom)、右上角点为(right,top)的矩形。
 
 第四步:视口变换(即着拍照过程中的冲洗底片)
 
       我们知道,冲洗底片就决定二维相片的大小,是2寸是5寸还是10寸。它相当与OpenGL中的视口变换(Viewport Transformation),即在屏幕窗口内可以定义一个矩形,称为视口(Viewport),规定屏幕上场景的范围和尺寸,类似于照片的画布。视景体投影后的图形就在视口内显示,类似于拍摄的图像在画布上显示。  
      在计算机图形学中,视口变换就是将经过几何变换、投影变换和裁剪变换后的物体显示于屏幕窗口内指定的区域内,这个区域通常为矩形,称为视口。
 
      OpenGL中视口变换的相关函数是:
 
glViewport(GLint x,GLint y,GLsizei width, GLsizei height);
      这个函数定义一个视口。函数参数(x, y)是视口在屏幕窗口坐标系中的左下角点坐标,参数width和height分别是视口的宽度和高度。缺省时,参数值即(0, 0, winWidth, winHeight) 指的是屏幕窗口的实际尺寸大小。所有这些值都是以象素为单位,全为整型数。
 
 
       通过上面的几个步骤,一个三维空间里的物体就可以用相应的二维平面物体绘制表示了,也就能在二维的电脑屏幕上正确显示了。总的来说,三维物体的显示过程如下:

图二、三维物体的显示过程

【opengl】OpenGL中三维物体显示在二维屏幕上显示的变换过程的更多相关文章

  1. VC、OpenGL、ArcGIS Engine开发的二维三维结合的GIS系统

    一.前言 众所周知,二维GIS技术发展了近四十年,伴随着计算机软硬件以及关系型数据库的飞速发展,二维GIS技术已日臻完善.在对地理信息的分析功能上有着无可比拟的优势.一些宏观的地理信息,一维的地理信息 ...

  2. JAVA中生成、解析二维码图片的方法

    JAVA中生成.解析二维码的方法并不复杂,使用google的zxing包就可以实现.下面的方法包含了生成二维码.在中间附加logo.添加文字功能,并有解析二维码的方法. 一.下载zxing的架包,并导 ...

  3. 在iOS中使用ZBar扫描二维码

    最近在做的项目中需要用到二维码扫描功能,之前在Android中使用过ZXing识别二维码,ZXing也有对应的iOS版本,经过了解,ZBar也是一个常用的二维码识别软件,并分别提供了iOS和Andro ...

  4. MVC5中使用jQuery Post 二维数组和一维数组到Action

    很久没有写了,最近在做一个MVC项目,这是我做的第一个MVC项目.之前可以说多MVC一点都不了解,今天把昨天遇到的一个问题记录下来.MVC大神就请飘过吧,跟我遇到同样问题的可以进来看看.遇到的第一个问 ...

  5. C#/VB.NET 在Word中添加条码、二维码

    本文介绍如何通过C# 和VB.NET代码实现在Word文档中添加条码和二维码.代码中将分为在Word正文段落中.页眉页脚中等情况来添加. 使用工具:Free Spire.Office for .NET ...

  6. 2022-08-14-esp32把玩记-③_轻轻松松显示个二维码(esp32+ssd1306显示图片)

    layout: post cid: 9 title: esp32把玩记-③ 轻轻松松显示个二维码(esp32+ssd1306显示图片) slug: 9 date: 2022/08/14 09:22:0 ...

  7. 寻路优化(二)——二维地图上theta*算法的设计探索

    这篇文章是基于上一篇文章的研究上进行的,使得路径更加的平滑和自然,特此记录.有错误欢迎大家批评指正.如需转载请注明出处,http://www.cnblogs.com/Leonhard-/p/68660 ...

  8. 寻路优化(一)——二维地图上A*启发函数的设计探索

    工作中需要优化A*算法,研究了一天,最后取得了不错的效果.看网上的朋友还没有相关的研究,特此记录一下.有错误欢迎大家批评指正.如需转载请注明出处,http://www.cnblogs.com/Leon ...

  9. 怎样在屏幕上显示多个alv

    本文解说怎样在屏幕上显示多个alv. 实现这种需求关键是下面几点(举例:在屏幕上显示4个alv): 1.须要定义4个alv control 2.由于有4个alv control,于是就须要定义4个容器 ...

随机推荐

  1. NET,ASP.NET,C#,WinFrom之间的联系与区别

    1:C#是编程语言(静态,强类型).类似中文.德文.英文这样. 2:.NET是一个平台(可承载多个编程语言,比如C# C++.net J# VB.Net),       但是都是运行在.net Fra ...

  2. 如何使用JAVA语言抓取某个网页中的邮箱地址

    现实生活中咱们常常在浏览网页时看到自己需要的信息,但由于信息过于庞大而又不能逐个保存下来. 接下来,咱们就以获取邮箱地址为例,使用java语言抓取网页中的邮箱地址 实现思路如下: 1.使用Java.n ...

  3. mysql 调用存储过程及例子

    存储过程如同一门程序设计语言,同样包含了数据类型.流程控制.输入和输出和它自己的函数库. --------------------基本语法-------------------- 一.创建存储过程 c ...

  4. EL表达式(Expression Language)

    语法: ${Expression} 来取代难以维护的Java脚本元素,或笨拙的jsp:useBean和jsp:getProperty; 尤其重要的是,表达式语言支持下面的功能: 1.精确地访问存储对象 ...

  5. 用C++写一个简单的订阅者

    打开一个终端,进入到beginner_tutorials包下面: cd ~/catkin_ws/src/beginner_tutorials 建立文件src/listener.cpp: vim src ...

  6. 使用Docker官方的Django包【转】

    官方Django docker,并没有安装Django 所以需要 在requirements.txt中配置Django 具体安装流程可以参考:http://www.logme.cn/blog/51/u ...

  7. Python 错误和异常

    1.Python异常类 Python是面向对象语言,所以程序抛出的异常也是类.常见的Python异常有以下几个,大家只要大致扫一眼,有个映像,等到编程的时候,相信大家肯定会不只一次跟他们照面(除非你不 ...

  8. JSP与Servlet的中文乱码处理

    注:百度来的,改了改... jsp页面的的头要设置好 <%@ page language="java" contentType="text/html; charse ...

  9. android数据库持久化框架

    android数据库持久化框架

  10. 57. Spring 自定义properties升级篇【从零开始学Spring Boot】

    之前在两篇文章中都有简单介绍或者提到过 自定义属性的用法: 25.Spring Boot使用自定义的properties[从零开始学Spring Boot] 51. spring boot属性文件之多 ...