opengl 教程(12) 投影矩阵

原帖地址:http://ogldev.atspace.co.uk/www/tutorial12/tutorial12.html

 

     现在我们开始学习如何把三维物体投影到二维平面上,同时保持它的深度。通常的投影包括平行投影和透视投影:平行投影比较简单,就是把顶点垂直的投向投影平面,常用在cad或者机械制图中。另外一种投影是透视投影,这种投影能较好的使二维投影显示立体感,因为人眼观看物体符合透视原理,透视原理也是学美术的人的必修课程。最常见的透视原理表现形式就是三维世界的平行线在透视几何中是相交的,它们的交点叫做灭点,比如我们观察平行的马路,在远处会发觉它们越来越靠近,直至相交在一起。

      本教程我们将产生投影变化矩阵,所谓投影矩阵,就是把视觉空间的frustum(视锥体)投影到一个长方体中,这需要我们提供四个参数:

  1. 投影区域(四边形)的宽高比。
  2. 摄像机观察垂直视角的大小。
  3. 近z平面到视点的距离。
  4. 远z平面到视点距离。 

 

推导投影矩阵的过程见我转贴的另外一篇文章,比本教程原文还要详细:http://www.cnblogs.com/mikewolf2002/archive/2012/11/25/2787265.html

最终的投影矩阵为:

其中ar为投影平面(四边形)的宽高比,alpha为垂直观察视角,NearZ,FarZ为近z和远z平面。

      投影矩阵乘以顶点位置,这时得到的顶点坐标就为裁剪空间,再经过透视除法后,就是所谓的归一化裁剪空间。前面的教程中,我们没有做任何投影变化,直接在裁剪空间定义顶点,进行操作。

      主要变化代码,增加了一个初始化透视矩阵的函数,该函数会根据传入的参数宽高比、垂直视角、近z平面和远z平面值计算出透视矩阵。

void Pipeline::InitPerspectiveProj(Matrix4f& m) const>
{
const float ar = m_persProj.Width / m_persProj.Height;
const float zNear = m_persProj.zNear;
const float zFar = m_persProj.zFar;
const float zRange = zNear - zFar;
const float tanHalfFOV = tanf(ToRadian(m_persProj.FOV / 2.0));
m.m[0][0] = 1.0f / (tanHalfFOV * ar);
m.m[0][1] = 0.0f;
m.m[0][2] = 0.0f;
m.m[0][3] = 0.0f;
m.m[1][0] = 0.0f;
m.m[1][1] = 1.0f / tanHalfFOV;
m.m[1][2] = 0.0f;
m.m[1][3] = 0.0f;
m.m[2][0] = 0.0f;
m.m[2][1] = 0.0f;
m.m[2][2] = (-zNear - zFar) / zRange;
m.m[2][3] = 2.0f * zFar * zNear / zRange;
m.m[3][0] = 0.0f;
m.m[3][1] = 0.0f;
m.m[3][2] = 1.0f;
m.m[3][3] = 0.0f;
}

定义了一个结构来保存透视投影参数。

struct {
    float FOV;
    float Width;
    float Height;
    float zNear;
    float zFar;
} m_persProj;

最终计算变化矩阵时候,会乘上投影矩阵,注意乘的顺序,位置向量在最右边,是列向量:

m_transformation = PersProjTrans * TranslationTrans * RotateTrans * ScaleTrans;

在渲染函数中,我们增加了设置透视矩阵函数的调用

p.SetPerspectiveProj(30.0f, WINDOW_WIDTH, WINDOW_HEIGHT, 1.0f, 1000.0f);

程序执行后的界面如下:

时间: 2024-10-21 19:07:11

opengl 教程(12) 投影矩阵的相关文章

NeHe的OpenGL教程6(Bang翻译Delphi版)-如何用图片进行纹理映射

NeHe的OpenGL教程6(Bang翻译Delphi版)-如何用图片进行纹理映射 在这一课里,我将教会你如何把纹理映射到立方体的六个面,如下图: 将下图放在应用程序data目录下,起名NeHe.bmp program lesson6a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com     注:本单元用到了glaux.dll和glaux.pas,下载地址为:

NeHe的OpenGL教程1(Bang翻译Delphi版)-如何绘制OpenGL窗口

NeHe的OpenGL教程1(Bang翻译Delphi版)-如何绘制OpenGL窗口 在这个教程里,我将教你在Windows环境中创建OpenGL程序.它将显示一个空的OpenGL窗口,可以在窗口和全屏模式下切换,按ESC退出.它是我们以后应用程序的框架.如下图: program lesson1a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com} uses 

NeHe的OpenGL教程2(Bang翻译Delphi版)-如何绘制平面图形

NeHe的OpenGL教程2(Bang翻译Delphi版)-如何绘制平面图形 这一课中,我将教您如何创建三角形和四边形.如下图: program lesson2a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com} uses  Windows,  Messages,  OpenGL; // 全局变量var  h_Rc: HGLRC;               

NeHe的OpenGL教程5(Bang翻译Delphi版)-如何绘制立方体

NeHe的OpenGL教程5(Bang翻译Delphi版)-如何绘制立方体 在这一课里,我们把三角形变为立体的金子塔形状,把四边形变为立方体,如下图: program lesson5a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com} uses  Windows,  Messages,  OpenGL; // 全局变量var  h_Rc: HGLRC;    

NeHe的OpenGL教程4(Bang翻译Delphi版)-如何让图形旋转

NeHe的OpenGL教程4(Bang翻译Delphi版)-如何让图形旋转 在这一课里,我将教会你如何旋转三角形和四边形.左图中的三角形沿Y轴旋转,四边形沿着X轴旋转.如下图 program lesson4a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com} uses  Windows,  Messages,  OpenGL; // 全局变量var  h_Rc

NeHe的OpenGL教程7(Bang翻译Delphi版)-如何使用光源

NeHe的OpenGL教程7(Bang翻译Delphi版)-如何使用光源        在这一课里,我将教会你如何用光源照亮立方体的六个面,如下图: 将下图放在应用程序data目录下,起名NeHe.bmp program lesson7a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com     在这一课里,我将教会你如何用光源照亮立方体的六个面     注:本

ps教程:投影制作

photoshop教程:投影制作,很简单的方法. 原图: 最终效果:  1.打开图片把图抠出来,选中要做投影的图片,然后在图层样式选择投影,确定.  2.然后选择:图层/图层样式/创建图层,把人物跟投影分离.  3.最后生成了一个投影图层,最后就是对投影图层的自由编缉了.

PHP开发框架Yii Framework教程(12) UI 组件 ClipWidget示例

CClipWidget提供了类似录制"宏"的功能,定义在CClipWidget的init和run之间的内容可以存放在Controller的Clip变量中 ,然后重新回放到任意其它位置. CClipWidget封装的是CBaseController的beginClip和 endClip,CBaseController的 beginClip和 endClip的基本用法如下: 首先定义Clip $this->beginClip('clipID'); // ... display the

JAVA提高教程(12)-认识Map之HashMap

Map里面使用率最多的,应该是HashMap吧,我们先来看看这个 1.package collection.lession12; 2. 3.import java.util.HashMap; 4.import java.util.Iterator; 5.import java.util.Map; 6. 7./** 8. * 老紫竹JAVA提高教程(12)-认识Map之HashMap<br> 9. * 基于哈希表的 Map 接口的实现.<br> 10. * 一个映射不能包含重复的键: