opengl es 2.0 3.0 MVP矩阵计算

转载 2015年11月13日 14:21:18

从2.0开始,opengl es不再提供glRotate()等函数,因此MVP矩阵需要我们自己计算,并赋值给GLSL。
1) 先来看下opengl所用的矩阵的基本知识:
Opengl 使用的是列矩阵,即顶点向量等是用列向量的齐次坐标表示的。
另外其矩阵存储方式是“列主序(column-major order)/列优先”
线性代数意义的同一个矩阵,在d3d 和 opengl 中却有不同的存储顺序

01
02
03
04
05
06
07
08
09
10
11
12
线代:a11,a12,a13,a14
           a21,a22,a23,a24
           a31,a32,a33,a34
           a41,a42,a43,a44
     d3d :  a11,a12,a13,a14
           a21,a22,a23,a24
           a31,a32,a33,a34
           a41,a42,a43,a44
     gl: a11,a21,a31,a41
         a12,a22,a32,a42
         a13,a23,a33,a43
         a14,a24,a34,a44

矩阵x顶点(记住顺序!!矩阵左乘顶点,顶点用列向量表示)= 变换后的顶点
MatrixXVect-300x71
这里有粗略的介绍

gl_anglestoaxes01
下面来分析一下:
如上图,3个元素集(m0, m1, m2),(m4, m5, m6)和(m8, m9, m10) 是用作欧拉变换和仿射变换,例如1.0中提供的函数glRotate(),缩放glScalef().

注意这三个元素集实际上指得是3个正交坐标系:
(m0, m1, m2): +X 轴,向左的向量(left vector)(相对屏幕自己),默认为(1,0,0)
(m4, m5, m6) : +Y轴,向上的向量(up vector),默认为(0,1,0)
(m8, m9, m10): +Z轴,向前的向量,默认为(0,0,1).

因为使用的是左乘,所以变换的顺序是相对于乘法是逆向的,即最后的变换出现在矩阵相乘之前,最先的变换在最后出现。:
gl_transform05
TransformedVector = TranslationMatrix * RotationMatrix * ScaleMatrix * OriginalVector;
这行代码最先执行缩放,接着旋转,最后才是平移。
用GLSL表示:

mat4 transform = projectionMat* viewMat * modeMat;
vec4 out_vec = transform * in_vec;

因为model矩阵变换比较简单。所以在这里不再讲解,主要讲解View(又叫相机)矩阵和投影(projection)矩阵的构建

2)View 矩阵(相机矩阵)
先来看下1.0和1.1里面提供的函数
函数原型
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);
该函数定义一个视图矩阵,并与当前矩阵相乘。
第一组eyex, eyey,eyez 相机在世界坐标的位置
第二组centerx,centery,centerz 相机镜头对准的物体在世界坐标的位置
第三组upx,upy,upz 相机向上的方向在世界坐标中的方向
你把相机想象成为你自己的脑袋:
第一组数据就是脑袋的位置
第二组数据就是眼睛看的物体的位置
第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体)。
gl_lookattoaxes01
如图,P1为点(centerx,centery,centerz),P2为点(eyex,eyey,eyez),u’为给定的向上向量(upx,upy,upz).
先求出朝向向量(Lookat Vertor)为P2 – P1.用伪代码表示(下同)
Vertor3 lookat = (eyex-centerx,eyey-centery,eyez-centerz);
朝向坐标(Forward axis)只要将朝向向量转为单位向量(Vectors Normalizing)

Vertex3 forward = lookat.normalize();
左坐标由给定的向上向量与朝向向量的叉乘计算得出。
Vertex3 left = (upx,upy,upz)xforward;
向上坐标由朝向坐标与左坐标的叉乘计算得出:
Vertex3 up = forward x left;
注意left,up计算后都需要进行归一化计算;

VIEWER

eyecamera
我们要把一个世界坐标系点K(Kx, Ky, Kz),表示成(U,V,N)坐标系的点(假设此时,已经经过平移操作,摄像机在世界坐标系的原点),则其公式为:
Px Ux*kx + Uy* ky + Uz*Kz
py = Vx*kx + Vy* ky + Vz*Kz
px Nx*kx + Ny* ky + Nz*Kz
于是我们构建出矩阵
|leftx lefty leftx|
|upx upy upy |
|forwardx forwardy forwardz|
加上eye的平移:
CAMERA

3,投影矩阵 Projection Matrix

gl_frustumclip

投影变换矩阵用来完成从眼睛坐标系向裁剪坐标系的变换,然后裁剪坐标系再除以系数w,变换到单位换设备坐标系(NDC)

值得注意的是 在裁剪坐标中, xc, ycand zc 与wc比较. 如果改坐标 小于-wc, 或大于wc, 则该顶点将被抛弃.

gl_projectionmatrix_eq27

1)透视矩阵

gl_projectionmatrix01

在透视投影情况下,视景体空间是眼睛坐标系下形成的一个台柱,这个台柱最终映射到单位化的NDC坐标系上,即:x坐标由[l,r]到[-1,1],y坐标由[b, t]到[-1,1],x坐标由[n, f]到[-1,1]。

同时我们应该注意一点:视觉坐标系是右手坐标系,但是NDC坐标系是左手坐标系。那么,相机是位于原点,向Z轴负方向观察(在视觉空间中),但是,在NDC空间中变成了Z轴正方向。

在OpenGL中,三维视觉空间中一点(xe,ye,ze)被投影在近平面上(xp, yp, zp)上,如下图。

gl_projectionmatrix03gl_projectionmatrix04

从截锥体上方看, 视野空间(eye space)里的X轴xe 被映射到 xp,可利用相似三角形比例算出:

gl_projectionmatrix_eq01 同理gl_projectionmatrix_eq02

可见xp和yp的计算都依赖于ze,他们都反比-ze。这是构建投影矩阵的第一条线索。在视野坐标通过右乘投影矩阵的变换后(Projection Matrix),裁剪空间仍然是齐次坐标,它最后通过除以自己的-w变成NDC坐标

gl_transform08gl_transform12

所以我们将w变量设置为-ze。于是GL_PROJECTION矩阵的第四行就是(0,0, -1, 0)。

gl_projectionmatrix_eq03

接着,将裁剪空间中的xp和yp轴线性关系映射到NDC坐标系, [l, r] ⇒ [-1, 1] and [b, t] ⇒ [-1, 1]。可以推导出:

mapXptoXn

根据两点求直线方程

两点式:(x-x1)/(x2-x1)=(y-y1)/(y2-y1) 求解。举X计算为例:

加(r,1)(l,-1)带入上式

(Xp-r)/(r-l)=(Xn -1)/2

Xn = 2(Xp-r)/(r-l) +1

Xn = (2Xp-r-l)/(r-l)

然后将裁剪空间中的xp和yp使用视觉空间中的xe和ye代替:

xpyp

由前面我们将w设置为-ze可知道,上面两个方程的分母就是裁剪空间中的坐标xc和yc。于是有下面的透视矩阵:

gl_projectionmatrix_eq08

至此,我们只需要求解第三行了,求解Zn和Ze变换关系和求解x、y略有不同,因为视觉空间中的ze总是会投影到-n的近裁剪平面上。但是,我们需要的z值必须满足唯一性,以便为了裁剪和深度测试,此外还必须满足可逆变换条件。因为很显然,我们知道z的变换,不依赖x和y,所以,我们将GL_PROJECT矩阵假设为如下表示:

gl_projectionmatrix_eq10

在视觉坐标系中We=1,于是:

gl_projectionmatrix_eq11

为了计算A和B,我们使用(ze, zn) 、(-near, -1)和 (-fargl_projectionmatrix_eq13, 1)的关系, 带入上面方程:

gl_projectionmatrix_eq12

gl_projectionmatrix_eq13

gl_projectionmatrix_eq14

gl_projectionmatrix_eq15

求出AB,于是:ze 和zn的方程变成

gl_projectionmatrix_eq17

于是完整的透视投影矩阵就出来了:

gl_projectionmatrix_eq16

通常我们所设置的视景体空间都是对称的:l =-r, b=-t。所以上面的投影矩阵就简化为下面的对称投影变换矩阵

gl_projectionmatrix_eq20

最后,我们再看看ze和zn的关系式:
,可见他俩并非是线性关系,就是说在近平面处精确度高,在远平面处精度低。所以如果[-n,-f]设置过大就会面临精确度问题。ze在远平面的小变化无法影响Zn的值 ,所以n 和f之间的距离尽量小以减少这种深度缓冲精确度问题(the depth buffer precision problem).

gl_projectionmatrix07

2)正交矩阵

gl_projectionmatrix02

zhengjiao

因为w对应正交投影无意义,所以第四行保持(0,0,0,1),因此矩阵为

gl_projectionmatrix_eq24

如果r=-l,t=-b,将进一步简化矩阵:

gl_projectionmatrix_eq25

备注:
向量归一化分两步:
1 计算出向量的模,即长度
2 将它的各个分量(xy or xyz)除以它的模
|a| = sqrt((ax * ax) + (ay * ay) + (az * az))
x = ax/|a|
y = ay/|a|
z = az/|a|

两个向量a和b的叉积写作a×b(有时也被写成a∧b,避免和字母x混淆)。向量积可以被定义为:
|向量a×向量b|=|a||b|sinθ在这里θ表示两向量之间的角夹角(0° ≤ θ ≤ 180°),它位于这两个矢量所定义的平面上。
这个定义有一个问题,就是同时有两个单位向量都垂直于和:若满足垂直的条件,那么也满足。

一个简单的确定满足“右手定则”的结果向量的方向的方法是这样的:若坐标系是满足右手定则的,当右手的四指从a以不超过180度的转角转向b时,竖起的大拇指指向是c的方向。
向量积|c|=|a×b|=|a| |b|sin<a,b>
即c的长度在数值上等于以a,b,夹角为θ组成的平行四边形的面积。
c的方向垂直于a与b所决定的平面,c的指向按右手规则从a转向b来确定。
a×b=(aybz-azby)i+(azbx-axbz)j+(axby-aybx)k,为了帮助记忆,利用三阶行列式,写成
b×a= -a×b右手规则
vertorcross

OpenGL2.0 和 OpenGL3.0 的不同与共同点

OpenGL2.0 和 OpenGL3.0 的不同与共同点 在OpenGL2.0中vertex shader 中 可以不指定 version 如果不指定 version 对于iOS来说...
  • jeffasd
  • jeffasd
  • 2017年09月08日 10:56
  • 585

android studio | openGL es 3.0增强现实(AR)开发 (3) OpenGL es3.0基本知识介绍

1.OpenGL ES (为 OpenGL for Embedded System 的缩写) 为适用于嵌入式系统的一个免费二维和三维图形库。OpenGL ES的历史版本信息 OpenGL ES 1.x...
  • yywan1314520
  • yywan1314520
  • 2016年08月02日 16:32
  • 2492

OpenGL ES 在 iPad Air 上无法正常运行 - 2.0 和 3.0 到底有多大差异?

OpenGL ES 在 iPad Air 上无法正常运行 - 2.0 和 3.0 到底有多大差异?
  • sleks
  • sleks
  • 2014年01月14日 09:16
  • 2798

详解MVP矩阵之ViewMatrix

ViewMatrix用于直接将World坐标系下的坐标转换到Camera坐标系下。已知相机的坐标系,还有相机在世界空间下的坐标.就可以求出ViewMatrix,下面进行具体推导。令UVN为相机坐标系下...
  • qp120291570
  • qp120291570
  • 2016年03月28日 21:15
  • 9476

详解MVP矩阵之齐次坐标和ModelMatrix

其次坐标(Homogeneous Coordinates)其次坐标这个概念在第一次看real-time rendering 这本书的时候就有提起到,但当时看的一头雾水,只知道其次坐标在某些计算中比较方...
  • qp120291570
  • qp120291570
  • 2016年03月27日 21:07
  • 4082

MVP矩阵的作用

参考网址:http://www.toymaker.info/Games/html/matrices.html MVP矩阵的作用 Direct3D需要3个矩阵才能将3D几何物体渲染到2D屏幕上。 ...
  • wodownload2
  • wodownload2
  • 2016年08月22日 14:28
  • 211

MVP矩阵顶点变换

Shader "Custom/test1" { SubShader { pass { CGPROGRAM #pra...
  • Fatestay_DC
  • Fatestay_DC
  • 2016年04月15日 09:50
  • 574

详解MVP矩阵之ProjectionMatrix

简介透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通...
  • qp120291570
  • qp120291570
  • 2016年09月29日 21:39
  • 3862

关于Opengl各种矩阵变换(MVPW)的自我理解

关于Opengl各种矩阵变换的理解 OpenGL的矩阵变换一直比较迷糊,貌似懂了又貌似不懂,今天貌似懂了过几天又貌似忘记怎么回事了,还是没有理解透彻,因此痛下决心,一定要把这个事情弄懂。经过几天的反...
  • L_Andy
  • L_Andy
  • 2015年01月06日 12:27
  • 1189

OpenGL ES2.0教程(3):初识MVP

http://cn.cocos2d-x.org/tutorial/show?id=1349 OpenGL ES2.0教程(3):初识MVP 子龙山人2014-08-19 10:04:28861...
  • wanglang3081
  • wanglang3081
  • 2014年08月27日 22:21
  • 1316
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:opengl es 2.0 3.0 MVP矩阵计算
举报原因:
原因补充:

(最多只允许输入30个字)