OpenGL取景变换(视图变换)矩阵推导
2017-02-13 15:11
399 查看
OpenGL取景变换(视图变换)矩阵推导
标签(空格分隔): OpenGL VR 游戏开发前言
关于取景变换(视图变换)矩阵的推导本人查过许多资料, 包过关于openGL的和数学方面, 数学方面的资料很严谨, 推导过程环环相扣, 但是数书知识毕竟是理论, 怎么将理论变成实现的代码, 数学知识是不涉及的. 代码原理方面的知识只能查找openGL或图形学相关的资料, 但是这些资料有个缺点就是涉及数学原理的地方不会写的很清楚, 很多东西都是一笔带过, 没有那种环环相扣的严谨性, 所以到最后就发现查了很多资料都发现推导过程是脱节的, 代码不是从数学知识平滑过渡过来的.本文旨在结合数学知识一步一步的推导出取景变换的变换矩阵, 从最基本的向量相乘到最终的代码实现.
使用线性变换推导基本坐标变换公式
先从简单的情况入手, 让两个坐标系的原点相同, 基向量不同, 设世界坐标系W为 {O;i,j,k}, 观察坐标系V为 {O;u,v,n}, 其中观察坐标系的基向量分别为 u⃗ =(xu,yu,zu), v⃗ =(xv,yv,zv), n⃗ =(xn,yn,zn), 从而存在:u=xui+yuj+zukv=xvi+yvj+zvkn=xni+ynj+znk
即:
(u,v,n)=(i,j,k)⎛⎝⎜⎜⎜xuyuzuxvyvzvxnynzn⎞⎠⎟⎟⎟
令:
A=⎛⎝⎜⎜⎜xuyvznxvyvznxnyvzn⎞⎠⎟⎟⎟
则有 V=WA, 由线性代数知识得知, A 称为从 W 到 V 的过渡矩阵. 由上式可以得出 W=VA−1, 即:
(i,j,k)=(u,v,n)A−1
称之为坐标转换公式.
设世界坐标系中W的一点X0坐标为(x0,y0,z0), 现在求这个点在观察坐标系V中的坐标,
由:
WX0=(i,j,k)⎛⎝⎜⎜⎜x0y0z0⎞⎠⎟⎟⎟=(u,v,n)A−1⎛⎝⎜⎜⎜x0y0z0⎞⎠⎟⎟⎟
得出X0在观察坐标系的坐标为A−1⎛⎝⎜⎜⎜x0y0z0⎞⎠⎟⎟⎟, 即:
⎛⎝⎜⎜⎜xuyuzuxvyvzvxnynzn⎞⎠⎟⎟⎟−1⎛⎝⎜⎜⎜x0y0z0⎞⎠⎟⎟⎟
由于A 是正交矩阵(1), 所以有 A−1=AT, 设 B=AT, 则有 W=VB, 其中
B=⎛⎝⎜⎜⎜xuxvxnyuyvynzuzvzn⎞⎠⎟⎟⎟
从而得出X0在V中的坐标为 B⎛⎝⎜⎜⎜x0y0z0⎞⎠⎟⎟⎟, 即:
X0′=⎛⎝⎜⎜⎜xuxvxnyuyvynzuzvzn⎞⎠⎟⎟⎟⎛⎝⎜⎜⎜x0y0z0⎞⎠⎟⎟⎟
引入齐次坐标推导最终矩阵
上面只涉及了线性变换部分, 由于平移不能用线性变换来表示, 所以要引入仿射变换, 首先要做的是将上述坐标转换为齐次坐标, 同时将变换矩阵改升级为4x4的齐次矩阵, X0在V中的坐标可以等价的表示为:X0′=⎛⎝⎜⎜⎜⎜xuxvxn0yuyvyn0zuzvzn00001⎞⎠⎟⎟⎟⎟⎛⎝⎜⎜⎜⎜x0y0z01⎞⎠⎟⎟⎟⎟
而原来的变换矩阵就变成了:
T1=⎛⎝⎜⎜⎜⎜xuxvxn0yuyvyn0zuzvzn00001⎞⎠⎟⎟⎟⎟
有这么一条理论: 在发生坐标系转换时, 如果已知一个点在老坐标系的坐标, 需要求这个点在新坐标系的坐标, 只需要对这个点做 新坐标系发生过的变换 的逆过程 (2).
这个逆过程就是将观察坐标系变换回世界坐标系的过程, 这个过程相对应的矩阵就是取景变换矩阵. 对于任意观察坐标系, 都可以通过先平移再旋转, 从而变换回世界坐标系.
设世界坐标系中的一点 P=(dx,dy,dz) 为观察坐标系的原点, 先将观察坐标系的原点移至世界坐标的原点, 变换矩阵为:
T2=⎛⎝⎜⎜⎜⎜100001000010−dx−dy−dz1⎞⎠⎟⎟⎟⎟
原点重合后, 再应用上面推导过的线性变换就可以与世界坐标系完全重合了, 于是左乘之前的线性变换矩阵 T1, 就得到最终的变换矩阵 T=T1T2, 即:
T=⎛⎝⎜⎜⎜⎜xuxvxn0yuyvyn0zuzvzn00001⎞⎠⎟⎟⎟⎟⎛⎝⎜⎜⎜⎜100001000010−dx−dy−dz1⎞⎠⎟⎟⎟⎟
结果是:
T=⎛⎝⎜⎜⎜⎜xuxvxn0yuyvyn0zuzvzn0−(xudx+yudy+zudz)−(xvdx+yvdy+zvdz)−(xndx+yndy+zndz)1⎞⎠⎟⎟⎟⎟
即:
T=⎛⎝⎜⎜⎜⎜xuxvxn0yuyvyn0zuzvzn0−u⋅P−v⋅P−n⋅P1⎞⎠⎟⎟⎟⎟
OpenGL取景变换矩阵源代码解析
首先简单介绍一下观察坐标系三个基向量的计算, 在代码中一般会传入三个信息:- 观察点: 就是相机的位置.
- 观察中心: 就是观测的中心.
- up向量: 相机向上的大致方向, 是个向量.
利用观察点和观察中心就可以算出观察平面的法向量n(与观测方向相反), 法向量与up向量叉乘就可以得出第三个向量u.
(由于传入的up向量不一定是严格的向上, 可能是斜的, 所以还要用n叉乘u得出矫正后的up向量v)
以下是iOS平台在xcode中看到的OpenGL求取景变换矩阵的代码:
GLK_INLINE GLKMatrix4 GLKMatrix4MakeLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { GLKVector3 ev = { eyeX, eyeY, eyeZ }; // 观察点 GLKVector3 cv = { centerX, centerY, centerZ }; // 观测中心 GLKVector3 uv = { upX, upY, upZ }; // up向量, 可以与观测方向不垂直, 但是不能平行 // 被观察平面的法向量, 与观测方向相反, n对应于OpenGL的z轴 GLKVector3 n = GLKVector3Normalize(GLKVector3Add(ev, GLKVector3Negate(cv))); // 叉乘得到第一根轴, u对应于OpenGL的x轴 GLKVector3 u = GLKVector3Normalize(GLKVector3CrossProduct(uv, n)); // 再次叉乘得到矫正后的up向量, v对应于OpenGL的y轴 GLKVector3 v = GLKVector3CrossProduct(n, u); // 采用了列主序储存(用一个一维数组依次储存了第一列, 第二列, ...), GLKMatrix4 m = { u.v[0], v.v[0], n.v[0], 0.0f, u.v[1], v.v[1], n.v[1], 0.0f, u.v[2], v.v[2], n.v[2], 0.0f, GLKVector3DotProduct(GLKVector3Negate(u), ev), GLKVector3DotProduct(GLKVector3Negate(v), ev), GLKVector3DotProduct(GLKVector3Negate(n), ev), 1.0f }; return m; }
代码注释应该已经很清晰了, 这里再额外解释几个点:
1. GLKVector3Normalize: 功能是把向量归一化, 就是转换成单位向量.
2. GLKVector3DotProduct: 求向量的点乘.
3. GLKVector3Negate: 将向量转成负的.
4. 外部传入的up向量(upX, upY, upZ)不一定与观测方向垂直, 所以要通过叉乘算出.
结语
虽然这里只证明了取景变换的推导过程, 但是这个原理可以推广到OpenGL中所有的坐标变换中去.在OpenGL里, 任何变换都可以用一个齐次矩阵表示, 因为所以的变换都可以分解成多个基本变换(旋转, 缩放, 平移), 每个基本变换都能用一个齐次矩阵表示, 这些矩阵相乘就得到了最终的变换矩阵.
附录:
(1) 正交矩阵: 正交矩阵的定义就是A−1=AT, 其充要条件是其内部的向量全部为单位向量, 且两两相互垂直.
(2) 逆向变换理论: 其实这条理论在高中学二维坐标系转换就学过了, 只是时间久了就忘了, 但是很容易理解. 空间中有一个坐标系I, 对I做一系列的变换T1,T2,⋯,Tn变成II, I和II中分别有一点A和B的坐标为都为(a,b), A经过一系列变换T1,T2,⋯,Tn变成I中一点C, 那么C就会与B重合, 因为B跟随II做了相同的变换. 相反的, 对B做这一系列变换的逆过程, 即做变换T−1n,⋯,T−12,T−11, 得到的II中的一点D会与A完全重合. 所以, 求I中一点A在II中的坐标就相当于求D的坐标, 而D坐标只需用B做逆向变换就可以, 又因为B坐标的数值与A的相等, 所以只要用A的坐标做逆向变换就可以了.
这样说可能很绕, 其实可以简单点理解, 想象坐标转换只是复制了一个立方体, 然后旋转平移到另一个地方, 原来立方体里的所有点都在新立方体里有一个替身, 欲求老立方体中的一个点在新立法体坐标, 只要将它的替身做相逆的变换, 他俩就重合了, 这时替身的坐标就是欲求的.
相关文章推荐
- opengl视图变换 投影变换推导
- OpenGL 入门教程 模型视图投影矩阵 变换光线
- OpenGL实验(二)桌子的坐标系变换 矩阵 视图
- 图形学学习笔记]OpenGL视图矩阵变换
- OpenGL: 视图矩阵的推导
- OpenGL图形管线和坐标变换[转](模型视图矩阵推导)
- OpenGL: 视图矩阵的推导
- opengl入门系列2- 模型视图矩阵变换
- OpenGL(五) 三维变换之模型视图矩阵
- OpenGL矩阵推导——模型视图变化
- OpenGL: 模型视图矩阵变换
- OpenGL矩阵推导——模型视图变化
- OpenGL(五) 三维变换之模型视图矩阵
- OpenGL矩阵推导——模型视图变化(转载需写明作者)
- 理解OpenGL中的模型视图矩阵变换
- OpenGL的视图变换与OSG漫游器
- openGL学习笔记2——视图和模型变换
- OPENGL 变换_视图模型变换与部分透视变换_学习笔记
- OpenGL模型视图变换、投影变换、视口变换
- 推导相机变换矩阵