由于Opengl superbible(OpenGL超级宝典第五版)想想最初接触OpenGL superbible是在大二的某一天,因为参加软件设计大赛不得不使用opengl,在当时主要是为了满足自己的好奇心以及虚荣心。。谈不上对计算机图形学有什么兴趣~~更谈不上对openg有什么想法,只知道此书是讲opengl,好知道一本好书opengl编程指南(红宝书),辗转从图书馆中借出这两本书后,因为要让队伍中其他人员看出我的努力,看出我对项目尽力,用了一周时间将此两本书读完(晚上还来个通宵夜读),现在想想当时自己是多么的SuperBible(SB),看完之后,立马还了两本书,估计让我当时写OpenGL的程序也会来一个#include<whateveryouneed.h>吧。。由于我的这种态度,在本科中唯一一次想要做一个像样的项目的时候,以失败而告终,也害了我们同组的几位组员,每每想起,都感到愧对各位同学。大学四年浑浑噩噩中生活,不知道自己为什么学计算机、不知道为什么自己要读这个专业,当时选择这个专业主要还是因为自己对电脑有一种憧憬,看到电脑那么贵(大学之前根本没摸过电脑)如此神奇,对其充满了向往,刚上大一还是高中时候的好孩子,然后好好学习,C语言学的基础扎实(这也许是我本科唯一一门学的好的课程了)还走狗屎运拿了个奖学金,然后大二就随波逐流、慢慢堕落,大学课程吗,过就万岁,考61分都是浪费,然后慢慢沦落到每年考试挂科数目都已等差数列向上增长。。其中本科我最痛恨的就是图形学,挂科一次、补考一次、重修一次估计就差最后一次大补考了,然后我就发恨以后绝对不能与计算机图形学(我现在最爱的Computer Graphics)发生交集。然后面临大学毕业,上大三下学期,由于我的好胜心作祟)考研究生,定了一个大目标-中科院计算所,虽然我的学习能力自己感觉还可以,如果不是最后自己考试怀里还得揣着一个热豆浆的话,估计能进初试,但是就以我当时连C++构造函数都搞不懂,更别提什么STL、MFC、内存分配等等,估计进了初试也会被毫不留情的cut掉。当我决定愤愤在奋斗一年的时候,一封调剂信来到了我的邮箱(中科院与XX学校联合培养)。中科院授课、中科院导师最后毕业证不一样,然后我就踏上了我的首次火车-北京之行,在我把拉种种关系花了200大洋请师兄、师姐(现在在某国自然科学重点实验室)吃饭(当时导师的最得意门生)后,虽然我知道当时我面试时什么玩意的C++、数据结构问题回答的一团糟,但当我说我了解OpenGL时,我遇到了我研究生对我启发最大的两个人中的一个(自动化所XX博士后),他很坚定的跟我说你以后来这儿做3D吧。。我当时一蒙(心里狂吼,我不想在与Ogl有交集了)但是貌似除了这个我没有能够拿得出手让他们留下的(虽然我知道我能留下)---然后我就阴差阳错的来到了XX实验室。入学之后才发现,一切事情还得靠自己,什么中科院上课,虽然坐在周边的都是我在高中时心目中的名校里的人,但是该睡觉还是睡觉,该翘课还是翘课,唯一一个让我魂牵梦绕的课程,也是几个让我觉着对得起中科院名声的老师-杨力祥,他教授的C++让我受益匪浅,让我这个小白简直就是跟坐火箭一样,虽然在上课的时候做了火箭,但是下课估计又做了自由落体。言归正传吧-当我在研一的时候就认识了另外一个对我影响巨大的人-人如其名(非常猛啊)让我佩服的五体投地,然后给我指引3D的方向,无异于黑暗中的山寨手机。然后读到PBRT,读到Real Time Rendering(我都没看懂)然后心里慢慢的对图形不在抵触(其实我根本就不知道自己喜欢什么,自己需要什么,自己不想放弃计算机,但是又不知道自己该学什么)直到毕业的时候需要凑毕业论文,怎么办,三年没做东西,没学东西,直到研三了才开始有点入门,瞎整呗,然后凭借PBRT我顺利的弄完我的毕业论文,顺利的忽悠毕业。在此我非常感谢,也非常荣幸碰到了那些同样在图形学中的水军(蜀山、飞飞等)还有帮我编译无数代码,对于我的白痴语法问题、编译问题也认真解答的林公子、流星上的pig等人,还有两位博士大笑----当我离开那学校时:此时我还是一只没有飞的菜鸟蜗牛  

    进入正题,中算是入道,兴趣大增最近在看OpenGL超级宝典第五版,就决定把扰了我五年的投影变换矩阵搞清楚,下面大部分是抄的(不要见怪,毛病不是一下子就能改掉的,忘原谅)。

    经过模型与视点变换、光照等变化后,需要进行投影变换,投影变换的目的就是为了将视景体变换为一个单位立方体,这个立方体的对角线顶点分别为(-1,-1,-1)和(1,1,1)

1:齐次坐标;

    “齐次坐标表示是计算机图形学的重要手段之一,它既能够用来明确区分向量和点,同时也更易于进行仿射(线性)几何变换”-F.S. Hill, JR

    (1)为什么要引入齐次坐标?

          我想当然的以为引入齐次坐标主要是为了在进行平移变换时也能很好的用矩阵运算来计算(到此为止)。在计算机图形学中,在没有引进齐次坐标时,向量与点的坐标都是一一个三元组来表示(x,y,z)表示。设坐标系的三个基为 x、y、z,那么向量V(v1,v2,v3)就可以通过以下公式表示V = v1X + v2y + v3z来表示。对于坐标系中的一个点,可以看成是原点所进行的一个位移。P(p1,p2,p3)可以写成如下形式P = o + p1x + p2y + p3z如果向量与点的坐标同时写成矩阵形式得:

          1                                        1

1表示向量基,右边的为向量与点在同一向量基下的不同坐标表示,由此可以得出向量与点在同一基下有了不同的表示。向量的齐次坐标的第四个分量为0,而点的齐次坐标的第四个分量为1。(I finally understand why CG import homogeneous coordinates….)

以前以为图形学中引入齐次坐标的主要原因是为了能够是平移变换也能像缩放、旋转变换那样通过一个矩阵与一个点的坐标相乘得到。由齐次坐标可以得到,当坐标表示一个点(第四个分量不为0)时,此时对其进行平移操作才会改变坐标值,当坐标表示一个向量(第四个分量为0)时此时对其进行平移操作并不能改变坐标值。通过向量的几何意义也很容易得到,向量只表示了一个方向与大小,并没有位置这个概念,读者可以自行导出。

     "After shading rendering system perform projection,which transforms the view volumn into a unit cube with its extreme points at (-1, –1, –1) and (1, 1, 1).The unit cube is called canonical view volume.”

    上段话摘自Real-Time-Rendering,可以看出投影变换的主要任务就是使用透视投影矩阵将顶点从视锥体中变换到canonical view volume(CCV 规则观察体中),然后进行裁剪,然后在进行透视除法变换坐标。

pro

    我们可以通过两步来进行这个变换:

    (1):将投影点投影到投影平面(近平面)

    (2):将投影点变换到CCV中(x、y、z都变换到(-1,1)区间中去。

      一下做如下嘉定(视锥体的近平面为left、right、top、bottom)分别用(l,r,t,b‘)表示。

 

2

    对于视锥体的近平面为-n,远裁剪面位-f(f>n),对于点P(x,y,z)通过第一次变换后得到的坐标为q(x’,y’,z’)其中z'=-n;上图中的右图(根据相似三角形)中可以得出:1从而得出x’ = –nx/z, y’ = –ny/z;这样得到投影后的点的坐标为:q(-nx/z, –ny/z, –n),由此可以看出所有点投影后z坐标都为-n,此时对于投影点已经没有什么意义,但是对于计算机图形学的其他算法而言,z还有很大作用(如z缓冲算法),在此,可以利用这个点存储z,此时q点的坐标可以处理成为q(-nx/z, –ny/z, z),因为此点坐标是有原有点p通过变化的来,原有点p的齐次坐标为p(x, y, z, 1),q点的齐次坐标为(-nx/z, –ny/z, z, 1) ,结合CVV在对其进行进一步的处理将q点的几次坐标写成如下形式:q(-nx/z,-ny/z, (az+b)/(-z),1)(因为z值主要是zbuffer使用,第三个坐标值只要单调性相同就行,当z=-n时此时(az+b)/(-z)=-1,当z=-f时,(az+b)/(-z)= 1),此时点q的齐次坐标可以表示为q(nx, ny, az+b, –z)(哇咔咔,看到齐次坐标的魅力了吗)。此时变换矩阵可以写为1,我们根据1求得:1

然后在对x、y进行变换,此时得到的p的坐标是(-nx/z, –ny/z, (az+b)/(-z),1),将p点的x、y(第一、第二)坐标分量变换到CVV的(-1,1)上的坐标为p'(x’、y’)(不要弄混)此时建立线性系统(就是方程组)为1,求的:1,对于透视投影矩阵M,我们得到:M P = p’即:1[22]

此时透视投影矩阵就出来了大笑:1

OpenGL超级宝典中的代码如下:

void m3dMakePerspectiveMatrix(M3DMatrix44f mProjection, float fFov, float fAspect, float zMin, float zMax)
{
	m3dLoadIdentity44(mProjection); 

	float yMax = zMin * tanf(fFov * 0.5f);
	float yMin = -yMax;
	float xMin = yMin * fAspect;
	float xMax = -xMin;

	mProjection[0] = (2.0f * zMin) / (xMax - xMin);
	mProjection[5] = (2.0f * zMin) / (yMax - yMin);
	mProjection[8] = (xMax + xMin) / (xMax - xMin);
	mProjection[9] = (yMax + yMin) / (yMax - yMin);
	mProjection[10] = -((zMax + zMin) / (zMax - zMin));
	mProjection[11] = -1.0f;
	mProjection[14] = -((2.0f * (zMax*zMin))/(zMax - zMin));
	mProjection[15] = 0.0f;
}
   就此告一段落吧。。通过这种方式,可以参考一下Real Timer Rendering推导一下平行投影的投影矩阵推导过程。很多都是从网上借鉴而来,往作者不要见怪。

posted on 2011-10-13 13:09  cg_ghost  阅读(2801)  评论(0编辑  收藏  举报