转:OpenGL的坐标系、投影和几何变换-矩阵压栈思想/矩阵列式存储

OPengl的渲染流程是先全部设置好数据和状态,GL_MODELVIEW是将当前要变换的空间向量和模型视图矩阵当前最顶矩阵(会乘以投影矩阵得最终变换矩阵)关联存储好包括状态设置,提交渲染时候glflush才会提交渲染数据和命令。

glPushMatrix()和glPopMatrix()的配对使用目的是方便得到需要变换的最顶矩阵,同时消除上一次的变换对本次变换的影响。使本次变换是以世界坐标系(或父坐标系)的原点为参考点进行。

glMatrixMode(GL_PROJECTION);                            // 切换到投影变换栈

glLoadIdentity();                                       // 用单位初始化投影变换栈

gluPrespective(30.0, aspect, 1.0, 50.0);                // 压入透视投影矩阵,和当前的单位矩阵相乘作为投影栈顶矩阵

glMatrixMode(GL_MODELVIEW);                             // 切换到模型视图栈,已经存在单位矩阵

glPushMatrix(); // 复制栈顶单位矩阵,当前模型视图栈,存在两个单位矩阵

glTranslatef(0.0, 0.0, -20.0);// 栈顶矩阵右乘平移矩阵,得到平移矩阵1

glPushMatrix();//复制栈顶平移矩阵,存在两个一样的栈顶矩阵

glTranslatef(0.0, 1.0, 0.0);//栈顶矩阵右乘平移矩阵,得到平移矩阵2(包含了平移矩阵1的平移)

myWireCylinder(1.0, 2.0, 12)//绘制物体,该物体顶点向量被右乘P*T2*v变换到裁剪空间,被记录到Opengl绘制状态机中。

矩阵列式存储:OGL矩阵4x4矩阵中,0~3下标为第一列,4~8下标为第二列(刚好是行式矩阵的转置,连续变换乘法顺序相反即可);列式矩阵是当前变换右乘之前变换,连续变换是T*R*S,GLSL中v*M因为运算符重载等价于M*v。

1 坐标系

OpenGL中使用的坐标系有两种,分别为世界坐标系和屏幕坐标系。世界坐标系即OpenGL内部处理时使用的三维坐标系,而屏幕坐标系即为在计算机屏幕上绘图时使用的坐标系。

通常,OpenGL所使用的世界坐标系为右手型

从计算机屏幕的角度来看,x轴正方向为屏幕从左向右,y轴正方向为屏幕从下向上,z轴正方向为屏幕从里向外。而进行旋转操作时需要指定的角度θ的方向则由右手法则来决定,即右手握拳,大拇指直向某个坐标轴的正方向,那么其余四指指向的方向即为该坐标轴上的θ角的正方向(即θ角增加的方向),在上图中用圆弧形箭头标出。

2 投影

将世界坐标系中的物体映射到屏幕坐标系上的方法称为投影。投影的方式包括平行投影和透视投影两种。

平行投影的投影线相互平行,投影的结果与原物体的大小相等,因此广泛地应用于工程制图等方面。

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

2.1 平行投影

OpenGL中使用下面的函数来设置投影方式为平行投影。

glOrtho(xleft, xright, ybottom, ytop, znear, zfar);

各参数的含义如下图所示。

注意,只有位于立方体之内的物体才可见。


2.2 透视投影

OpenGL中使用下面的函数来设置投影方式为透视投影。

gluPerspective(fovy, aspect, znear, zfar);

各参数的含义如下图所示。

fovy为四棱台的顶角,aspect为投影面的纵横比,znear和zfar为四棱台的顶面和底面到视点的距离(注意不是z坐标)。

注意,只有位于四棱台之内的物体才可见。

3 几何变换

OpenGL中可以使用的几何变换有平移、旋转、缩放三种。

glTranslatef(x, y, z);

该函数可以实现平移变换,x、y、z为各坐标轴上的平移量。

glRotatef(θ, x, y, z);

该函数实现旋转变换。θ为旋转角度,x、y、z为旋转轴。旋转方向由右手法则决定(参见第一节“坐标系”)。

glScalef(x, y, z);

该函数实现缩放变换。x、y、z为各轴方向的扩大量。若为负值,则沿着坐标轴的反方向进行缩放。


实际上,几何变换并不是针对坐标系中的某个物体进行变换,而是对整个坐标系进行变换。进行绘图时,世界坐标系上的点将以如下的方式被投影到屏幕坐标系上:

其中(x y z 1)T为该点在世界坐标系中的坐标,(x' y' z' 1)T为该点在屏幕坐标系上的投影的坐标。P为投影变换矩阵,An为几何变换矩阵。在处理变换和投影时,OpenGL先把几何变换矩阵A1、A2、…、An从左侧依次与点坐标矩阵相乘,最后再将投影矩阵从左侧与经过几何变换之后的点坐标相乘,即得到该点的屏幕坐标。也就是说,在OpenGL中进行几何变换的方式为,首先通过glTranslatef、glRotatef、glScalef等函数设置好几何变换矩阵(相当于对坐标系进行了变换),然后再进行绘图,那么图形的投影坐标将受到设置好的几何变换矩阵所影响而显现出几何变换的效果;而并不是首先进行绘图然后再通过几何变换函数对已经存在的图形进行变换。

变换的一般形式如下式所示:

常见的变换矩阵如下。

(1)平移变换

(2)旋转变换

沿x轴旋转

沿y轴旋转

沿z轴旋转

(3)缩放变换

(4)平行投影(投影到xy平面的情况)

(5)透视投影(投影到xy平面的情况。投影中心为z轴上的点(0, 0, R))

在实际编程中,为了保存几何变换和投影变换的操作,OpenGL维护两个栈,即投影变换栈和几何变换栈。栈中保存的元素即为投影变换和几何变换的变换矩阵。使用下面的函数可以在两个栈之间进行切换:

切换当前操作的栈为投影变换栈:glMatrixMode(GL_PROJECTION);

切换当前操作的栈为几何变换栈:glMatrixMode(GL_MODELVIEW);

此外,下面的函数可以清除当前操作的栈中的内容,并向栈中压入一个单位矩阵:

glLoadIdentity();


两个栈之间的关系如下图所示:

一般情况下,我们在进行OpenGL初始化时都要执行下面的命令:

glPushMatrix();                                         // 保存当前坐标系

glPopMatrix();                                          // 恢复当前坐标系

在调用几何变换操作时,OpenGL将该几何变换操作的变换矩阵与当前栈的栈顶元素相乘,得到一个新的矩阵并将其作为几何变换栈的栈顶。


作为例子,我们来看下面的这段程序。

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(30.0, aspect, 1.0, 50.0);

glMatrixMode(GL_MODELVIEW);

glPushMatrix();

glTranslatef(0.0, 0.0, -20.0);

glPushMatrix();

glTranslatef(0.0, 1.0, 0.0);

myWireCylinder(1.0, 2.0, 12);

glTranslatef(0.0, 1.0, 0.0);

glRotatef(-90.0, 1.0, 0.0, 0.0);

glutWireCone(1.0, 2.0, 12, 3);

glPopMatrix();

glTranslatef(0.0, -1.0, 0.0);

myWireCylinder(1.0, 2.0, 12);

glPopMatrix();


下面我们来分析一下该程序执行过程中两个栈的变化情况。图中左侧的栈为透视变换栈,右侧的栈为几何变换栈。黄色表示当前操作栈。I表示单位矩阵,P表示投影变换矩阵,T为平移变换矩阵,R为旋转变换矩阵,S为缩放变换矩阵。


具体到OpenGL的实现,OpenGL和数学中相同采用

右手系,OpenGL把模型变换和视图变换合二为一,即模型视图矩阵。OpenGL和GLM的变换矩阵都是按照列优先存储在内存中,这和C++二维数组不同,其实,GLM中的4x4矩阵是由4个列向量组成的。按照上面的分析,当OpenGL的模型视图矩阵和投影矩阵均为单位阵时, 这时摄像机位于世界坐标系原点看向z负方向,向右方向沿x轴正方向,向上方向沿y正方向,由于投影矩阵为单位阵,这时为正交投影(另一种是透视投影),裁 剪面为xyz的±1,也就是说,对应到最后的显示窗口,x方向向右,y方向向上,z方向垂直屏幕向外,窗口中心对应坐标原点,窗口边缘对应±1,并且z值 小的片断遮挡z值大的片断(正好和离摄像机的远近关系反了,这是因为没有对z坐标进行变号)。对了,OpenGL除了模型视图矩阵和投影矩阵之外,还有文理坐标变换矩阵和颜色变换矩阵。请见OpenGL官方手册文献[8]2.12和2.16。列式存储:

https://blog.csdn.net/blues1021/article/details/51329885

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容

  • 1 前言 一直想沿着图像处理这条线建立一套完整的理论知识体系,同时积累实际应用经验。因此有了从使用AVFounda...
    RichardJieChen阅读 5,635评论 5 12
  • title: OpenGL坐标系date: 2015-3-14tags: OpenGL 坐标系统 想要弄懂几何变换...
    Beatrice7阅读 7,314评论 0 6
  • 1 前言 OpenGL渲染3D模型离不开空间几何的数学理论知识,而本篇文章的目的就是对空间几何进行简单的介绍,并对...
    RichardJieChen阅读 6,849评论 1 11
  • 近来,朕迷恋上喝酒做菜无事high,读书熬夜尽情zuo的生活。但凡遇到美妙的人或物,立刻心生欢喜。重拾敏锐。记得高...
    NikkiLiu阅读 180评论 0 0
  • ✪ 盘面回顾✪ 请点击此处输入图片描述 好久不见,九贱师傅回来了。过去的一周是股市动荡的一周,黑色星期一和红色好几...
    股市投资日历阅读 138评论 0 0