openGL投影矩阵原理及数学推导
- 格式:doc
- 大小:361.00 KB
- 文档页数:7
glm 四元数转换矩阵-概述说明以及解释1.引言1.1 概述四元数(Quaternion)是数学中的一种扩展复数,广泛应用于3D计算机图形学和空间几何运算等领域。
它由一个实部和三个虚部组成,具有一些独特的性质和优点。
在图形学中,四元数被用于表示和计算物体的旋转,相比其他表示旋转的方法,如欧拉角和旋转矩阵,四元数具有更简洁和高效的计算方式。
本文将首先介绍球面线性插值(Spherical Linear Interpolation, 简称SLERP)的概念及其在计算机图形学中的应用。
接下来,我们将详细探讨四元数的定义和性质,包括四元数的运算法则、单位四元数的特点等。
最后,我们将重点讲解四元数与旋转矩阵之间的相互转换关系,包括如何将一个旋转矩阵转换为对应的四元数表示,以及如何从四元数恢复出旋转矩阵。
通过深入理解四元数与旋转矩阵之间的转换关系,我们可以更好地理解和应用四元数在3D图形学中的作用。
对于计算机图形学从业者来说,这是一个非常重要的基础知识。
此外,我们还将展望四元数在虚拟现实、计算机动画等领域的应用前景,并提出相关讨论和建议。
通过阅读本文,读者将能够理解四元数转换矩阵的原理和算法,并能够应用于实际问题中。
无论是从事计算机图形学研究还是从事相关行业工作的人士,本文的内容都将对他们的工作产生积极的影响和帮助。
总结起来,本文旨在为读者提供一份系统而全面的关于glm四元数转换矩阵的学习材料,并希望能够激发更多人对这一领域的兴趣和研究。
1.2文章结构文章结构部分的内容可以写成以下样式:2. 正文2.1 球面线性插值2.2 四元数的定义和性质2.3 四元数到旋转矩阵的转换在正文部分,我们将着重介绍GLM(OpenGL 数学库)中的四元数转换矩阵的相关知识。
首先,我们将会详细讨论球面线性插值算法的原理和应用,以便更好地理解四元数和矩阵之间的转换关系。
接下来,我们将会介绍四元数的定义和性质。
四元数是一种复数的扩展形式,具有独特的性质和运算规则。
OpenGL学习笔记:三维数学基础(⼀)坐标系、向量、矩阵接触OpenGL和计算机图形学有⼀段时间了,⼀直想写⼀点东西,记录⾃⼰的学习历程,或许也能够为有意愿向计算机图形学发展的菜鸟们提供⼀条捷径。
闲话不多说,本章主要介绍计算机图形学中三维数学的⼀些基础知识,主要包括2D、3D笛卡尔坐标系,向量、矩阵的数学和⼏何意义以及公式。
由于篇幅限制,其中的推导过程本⽂不作叙述,感兴趣的读者可以去看《3D数学基础+图形与游戏开发》,已上传,链接地址在本⽂末尾。
⼀、计算机图形学计算机图形学(Computer Graphics)是⼀种使⽤数学算法将⼆维或三维图形转化为计算机显⽰器的栅格形式的科学。
其⼴泛应⽤于游戏、动画、仿真、虚拟现实(VR)、增强现实(AR)等领域。
在数学之中,研究⾃然数和整数的领域称为离散数学,研究实数的领域称作连续数学。
在计算机图形学中,为虚拟世界选择度量单位的关键是选择离散的精度。
⼀种错误的观点认为short、int是离散的,⽽float、double是连续的,⽽事实上,这些数据类型都是离散的。
于是,计算机图形学有如下准则:计算机图形学第⼀准则:近似原则——如果它看上去是对的,它就是对的。
⼆、笛卡尔坐标系2D笛卡尔坐标系是⼀个精确定位点的框架。
2D坐标的标准表⽰法是(x,y),相信⼤家初中都学过。
⼀般,标准的笛卡尔坐标系是x轴向右,y轴向上。
⽽计算机图形学中的屏幕坐标往往是x轴向右,y轴向下。
如图1所⽰。
图1:2D笛卡尔坐标系和2D屏幕坐标系3D笛卡尔坐标系类似,增加了第三个维度,z轴。
3D坐标系分为完全不同的2种坐标系,左⼿坐标系和右⼿坐标系。
判断⽅法为,左⼿坐标系:伸出左⼿,让拇指和⾷指成“L”形,⼤拇指向右,⾷指向上,其余⼿指指向前⽅。
此时,拇指、⾷指和其余三指分别代表x、y、z轴的正⽅向。
右⼿坐标系,相同,只是把左⼿换成右⼿。
如图2所⽰。
图2:左⼿坐标系与右⼿坐标系其中左⼿坐标系⼴泛应⽤于计算机图形学、D3D之中,⽽右⼿坐标系⼴泛应⽤于OpenGL、线性代数、3DSMax之中。
投影矩阵的推导(OpenGL D3D)OpenGL矩阵推导——模型视图变化在三维编程中,模型视图变换是从三维世界到二维屏幕中一个很重要的变换,但是这个变换往往很多人都不太理解,要么是事而非。
而这方面的文章不是太少就是讲的太浅没有真正的理解模型视图变换,本人在这个过程中曾经走过很多歪路,不过好在最终在自己的不懈努力下终于降伏了这只猛虎。
本人就以自己的理解,通过矩阵推导过程一步一步来了解模型视图变化,最后通过两个OpenGl的程序来进一步理解模型视图矩阵。
先从一个基本的模型视图—透视投影变换讲起。
透射投影是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume 以下简称CVV)中,待裁剪完毕后进行透视除法的行为。
透视投影变换是令很多刚刚进入3D图形领域的开发人员感到迷惑乃至神秘的一个图形技术。
其中的理解困难在于步骤繁琐,对一些基础知识过分依赖,一旦对它们中的任何地方感到陌生,立刻导致理解停止不前。
主流的3D APIs 都把透射投影的具体细节进行了封装,从而只需一个函数便可生成一个透射投影矩阵比如gluPerspective(),使得我们不需要了解其算法便可实现三维到二维的转化,然而实事是,一些三维图形或游戏开发人员遇到一些视图矩阵的问题往往会不知所措,比如视景体裁剪。
以下部分内容是从别处那转过来的,主要感谢Twinsen和一个叫丁欧南的高中生。
透视投影变换是在齐次坐标下进行的,而齐次坐标本身就是一个令人迷惑的概念,这里我们先把它理解清楚。
齐次坐标对于一个向量v以及基oabc,可以找到一组坐标(v1,v2,v3),使得v = v1 a + v2 b + v3 c (1)而对于一个点p,则可以找到一组坐标(p1,p2,p3),使得p–o = p1 a + p2 b + p3 c (2)从上面对向量和点的表达,我们可以看出为了在坐标系中表示一个点(如p),我们把点的位置看作是对这个基的原点o所进行的一个位移,即一个向量——p –o(有的书中把这样的向量叫做位置向量——起始于坐标原点的特殊向量),我们在表达这个向量的同时用等价的方式表达出了点p:p = o + p1 a + p2 b + p3 c (3)(1)(3)是坐标系下表达一个向量和点的不同表达方式。
OpenGL空间(坐标系)变换⽹友的《3D图形学的学习策略》⼀⽂使我深受启发,在图形学以及openGL学习⽅⾯给了我很有价值的指导性意见,在此对前辈们的不吝赐教表⽰感激,谢谢你们的⽆私分享。
如⽂章所说,API是⼯具,不是本质,OpenGL/Direct3D的本质是图形学,⽽不是OpenGL/Direct3D的本⾝,API的本⾝只是⼀些Interface⽽已。
最重要的,最根本的是,你要明⽩这些API背后的图形学的原理---因为那才是根本中的根本。
其实很多事情,包括学习也涉及到⽣活,只有抓住了本质,才能体会到其中的真谛。
带着这种希望探究本质的学习⽅法,结合图形学原理,通过阅读书⽬和⽹友们的⽂章,我对OpenGL⼏何空间变换进⾏了总结性的学习。
OpenGL处理管线的⽬的是将对象的三维描述转换为可以显⽰的⼆维图像。
为了完成这个从三维到⼆维的转换,OpenGL 使⽤了多个空间(坐标系),每个空间完成特定的任务,从⼀个空间到另⼀个空间需要进⾏空间转换。
理解OpenGL所使⽤的各种空间以及它们间的变换是⾮常重要的。
如上图所⽰,openGL中使⽤的空间依次是:对象空间、世界空间、视点空间、裁剪空间、归⼀化设备空间、窗⼝空间、屏幕空间。
结合⾃⼰的理解,就每个空间完成的基本任务和空间的变换关系,总结如下。
对象空间。
对象空间中完成的最⼤任务是对象建模,三维对象的属性,包括顶点位置和表⾯法线等是在这个空间内指定的。
这个空间的坐标原点⼀般在对象上,有时候也在其他地⽅,主要是为了建模⽅便。
每⼀个对象都有⼀个⾃⼰的对象空间。
就openGL⽽⾔,我⽬前还没有接触到建⽴很复杂模型的应⽤,建模⼀般在其他地⽅如3DMAX中完成,然后读⼊openGL进⾏处理。
世界空间。
对象空间之后是世界空间,我理解为世界坐标系是固定不变的。
世界空间主要是对三维场景进⾏描述,就是把已经建⽴的各种对象摆放在三维空间中,空间的转换是通过模型变换完成的。
可以通过平移、旋转、⽐例缩放等把对象摆放在需要的位置,就好像买好家具以后设计房间布局⼀样。
OpenGL图形变换OpenGL图形软件包是为三维应用设计的,其中包含了大量的有关三维变换的操作,二维变换则可以看作是三维变换的特例。
OpenGL中常用的变换包括模型视图变换、投影变换和视见区变换。
一、矩阵堆栈在计算机图形学中,所有的变换都是通过矩阵乘法来实现的,即将三维形体顶点构成的齐次坐标矩阵乘以三维变换矩阵就得到了变换后的形体顶点的齐次坐标矩阵,这样只要求出形体的三维变换矩阵,就可以得到变换后的形体。
在OpenGL中,对象的坐标变换也是通过矩阵来实现的。
OpenGL中包含了两个重要的矩阵:模型视图矩阵和投影矩阵,其中模型视图矩阵用于物体的模型视图变换,投影矩阵用于投影变换。
一般来说,在进行矩阵操作之前,需要指定当前操作的矩阵对象,这可以使用函数:glMatrixMode(GLenum mode);定义。
其中当mode取GL_MODELVIEW时,表示对模型视图矩阵进行操作;当mode取GL_PROJECTION时表示对投影矩阵进行操作,并且一旦设置了当前操作矩阵,它就将保持为当前的矩阵对象,直到再次调用函数glMatrixMode修改它为止。
默认情况下,系统处理的当前矩阵是模型视图矩阵。
OpenGL为模型视图矩阵和投影矩阵各维护着一个“矩阵堆栈”,其中堆栈的栈顶矩阵就是当前的模型视图矩阵或投影矩阵。
在调用变换函数的时候,系统自动计算变换函数对应的变换矩阵与当前操作的矩阵堆栈栈顶矩阵的乘积,并置为栈顶矩阵,绘制图形时使用栈顶矩阵作为图形的变换矩阵。
矩阵堆栈主要用来保存和恢复矩阵的状态。
OpenGL中利用函数:void glPushMatrix(void);void glPopMatrix(void);实现矩阵堆栈的操作。
其中函数glPushMatrix将当前矩阵堆栈的栈顶矩阵复制一个,并将其压入当前矩阵堆栈,以保存当前变换矩阵。
函数glPopMatrix用于将当前矩阵堆栈的栈顶矩阵弹出,这样,堆栈中的下一个矩阵变为栈顶矩阵(当前变换矩阵),用来恢复当前变换矩阵原先的状态。
Opengl_10_透视投影1,We have finally reached the item that represents 3D graphics best - the projection from the 3D world on a 2D plane while maintaining the appearance of depth. A good example is a picture of a road or railway-tracks that seem to converge down to a single point far away in the horizon.通过在保留物体深度⽴体感的前提下将3d世界的物体投影到2d平⾯上最优化显⽰3D图形。
2,对图形的透视变换需要提供四个参数:1.屏幕宽⾼⽐:矩形屏幕的宽⾼⽐例是投影的⽬标;2.垂直视野:相机窗⼝看向3d世界的垂直⽅向上的⾓度;3.Z轴近平⾯的位置:近平⾯⽤于将离相机太近的物体裁剪掉;4.Z轴远平⾯的位置:远平⾯⽤于将离相机太远的物体裁剪掉;屏幕宽⾼⽐是⼀个必要的参数,因为我们要在⼀个宽⾼相等的单位化的盒⼦内展⽰所有的坐标系,⽽通常屏幕的宽度是⼤于屏幕的⾼度的,所以需要在⽔平⽅向上的轴线上布置更加密集的坐标点,竖直⽅向上相对稀疏。
这样经过变换,我们就可以在保证看到更宽阔屏幕图像的需求下,根据X轴在单位盒⼦空间内的⽐例,在X⽅向上添加更多的X坐标。
垂直视野(The vertical field of view)让我们可以(放⼤和缩⼩zoom in and out)3D世界。
左边的图⽚中相机的视⾓较⼤⽽在屏幕上物体看上去应该会较⼩;右边的视⾓较⼩⽽物体看上去应该会更⼤。
α > β, L2 > L1这是由于相机的位置导致的效果,有点违背直觉,(同样的物体咋就看上去⼀个⼤⼀个⼩了)。
左边的相机靠近投影屏幕使视⾓变⼤⽽右边的相机远离屏幕视⾓变⼩。
OpenGL中的glLoadIdentity、glTranslatef、glRotatef原理单位矩阵对角线上都是1,其余元素皆为0的矩阵。
在矩阵的乘法中,有一种矩阵起着特殊的作用,如同数的乘法中的1,我们称这种矩阵为单位矩阵.它是个方阵,除左上角到右下角的对角线(称为主对角线)上的元素均为1以外全都为0.OpenGL中的坐标用齐次坐标表示,即(x,y,z)表示成(x',y',z',h),其中x=x'/h; y=y'/h; z=z'/h. 通常h取1. 比如空间中的点(2,3,4),在OpenGL中将表示成(2,3,4,1). 齐次坐标表示方式适合于矩阵运算,也很方便地表示了无穷远的点,比如(1,0,0,0)就表示x轴上无穷远的点,因为1/0是无穷大,这里约定0/0=0.接着要说点矩阵(线性代数)的知识。
OpenGL里面的平移、旋转、缩放等变换均是线性变换,用矩阵相乘来表示。
以平移变换为例,请见官方对glTranslatef 函数的说明。
假设有点(3,3,3),如果把该点沿x轴移动2单位,沿y轴移动3单位,沿z轴移动4单位,那么该点会是(3+2, 3+3, 4+4) = (5,6,7). 用矩阵表示是:左边的矩阵称为平移变换矩阵,若把2、3、4换成x、y、z,则用它乘以一个齐次坐标表示的向量,就可以将该向量平移(x,y,z). 旋转变换和缩放变换都像平移变换一样可用一个矩阵来表示。
这里可以不用理会这些矩阵长什么样,只需清楚它们乘以一个齐次坐标表示的向量,就可以使该向量发生需要的变换。
把平移变换矩阵记为T(x,y,z),旋转变换矩阵记为R(x,y,z,s),表示绕向量(x,y,z)旋转s角度;把向量记为X。
这里只需要知道它们是矩阵就行了,现在要把一个点X,如(3,3,3,1),移动(2,2,2)单位,再绕y轴旋转30度角,用矩阵表示即R(0,1,0,30)*T(2,2,2)*X,可以理解为离X最近的矩阵最先作用。
D3D,OPENGL视点变换矩阵,投影矩阵(clip space)的推导过程此处推导D3D的变换矩阵(采用行向量,行主序存储,右乘矩阵),然后通过调整得出OPENGL中的变换矩阵1. 视点变换矩阵的推导。
根据给定的眼睛位置(position),朝向(orientation)来计算最终的视点变换矩阵。
投影矩阵的计算见Frustum类计算过程大致如下:设Q代表从世界空间坐标系到眼睛空间坐标系的变换矩阵,V代表一个点故VQ=VMT.其中T:从世界空间坐标系到眼睛空间坐标系的平移变换矩阵,M:从世界空间坐标系到眼睛空间坐标系的旋转变换矩阵。
则Q1-代表视点变换矩阵Q1-=MT1-= T1-M1-由于M是正交矩阵,故V=Q1-= T1-M T其中M=[Rx Ry Rz 0], T= [1 0 0 0][Ux Uy Uz 0] [0 1 0 0][Dx Dy Dz 0] [0 0 1 0 ][0 0 0 1] [Tx Ty Tz 1 ]故V=Q1-= [1 0 0 0] * [Rx Ux Dx 0][0 1 0 0] [Ry Uy Dy 0][0 0 1 0] [Rz Uz Dz 0][-Tx –Ty –Tz 1] [0 0 0 1]= [ Rx Ux Dx 0 ][ Ry Uy Dy 0 ][ Rz Uz Dz 0 ][ Wx Wy Wz 1 ]其中W = - Pos* M T对于OPENGL,则有:V=Q1-=M T T1-其中M=[Rx Ux -Dx 0][Ry Uy -Dy 0][Rz Uz -Dz 0][0 0 0 1]T= [1 0 0 Tx][ 0 1 0 Ty][0 0 1 Tz][0 0 0 1 ]故V=Q1 =[Rx Ry Rz Wx][Ux Uy Uz Wy][-Dx –Dy –Dz Wz][0 0 0 1]其中W = -M T* Pos2. 透视投影(perspective projection)矩阵的推导假设(X,Y,Z,1)为一个点,投影后的点为(Xp,Yp,Zp,1)则根据相似三角形原理,有:Xp/X=Yp/Y=N/Z所以:Xp=N*X/ZYp=N*Y/ZZp=N故投影变换可以表示为齐次坐标形式:(Xp,Yp,Zp,1)=(X,Y,Z,Z/N)对于X和Y :在进行上一步变换后,还要进一步做裁剪变换,即将投影后的坐标映射为[-1,1].即:(X*N/Z,Y*N/Z) : ([l,r],[b,t]) ([-1,1],[-1,1])即:(X*N/Z-l)/(r-l)=(s+1)/2由此可以得到:对于Z,变换稍微复杂一些。
视锥体的顶视图视锥体的侧视图[翻译转载]OpenGL 投影矩阵(ProjectionMatrix )构造⽅法OpenGL Projection Matrix原⽂地址:Overview电脑显⽰器是⼀个⼆维平⾯, ⽽OpenGL 渲染出来的场景却是三维的 , 所以必须要投影到⼆维的电脑屏幕上. 可以使⽤ GL_PROJCETION 来进⾏投影. ⾸先,它把顶点数据从 eye coordinates(视点坐标) 转换到 clip coordinates(裁剪坐标). 在将这些坐标除以w 坐标分量来转换到NDC(标准化设备坐标)上因此,我们应该清楚 裁剪(可视平截头体的裁剪) 和 NDC 的转换都包含在了 GL_PROJECTION 矩阵中了. 下⼀段将会说明如何通过l,r,b,t,n,f (左,右,下,上,近和远)这六个边界值来构建透视矩阵.注意 可视平截头体的裁剪(裁剪) 是在 clip coordinates(裁剪坐标) 中, 在除以 w c 前执⾏的.clip coordinates 的 x c ,y c ,z c 会通过 w c 来测试, 如果任何⼀个⼤于w c 或 ⼩于−w c , 那么这个顶点就会被丢弃.−w c <x c ,y c ,z c <w c当有丢弃时,OpenGL 将会重新构建多边形的边.⼀个被平截头体剪裁的三⾓形## Perspective Projection(透视投影)在透视投影中, truncated pyramid frustum (eye coordinates) (截锥体平截头体(视点坐标)) 中 三维的点呗映射到⼀个⽴⽅体(NDC); 三个坐标分量分别映射到[−1,1].x :[l ,r ]=>[−1,1],y :[b ,t ]=>[−1,1],z :[n ,f ]=>[−1,1]注意 eye coordinates 是定义在右⼿坐标中的, 但 NDC 是在左⼿坐标中的. 因此 源点摄像机在 eye space (视觉空间) 中看向 z 轴 负向 ⽽在 NDC 中 看向z 轴 正向. 由于glFrustum() 对由进到远只接受正值, 我们需要在构造 GL_PROJECTION 矩阵时 对他们取反.截锥体平截头体和标准化设备坐标在OpenGL 在, 在 eye space 中的三维点 会被投影到 near plane(projection plane) (近平⾯(投影平⾯)) 上, 下⾯这张图显⽰了如何将 p (x e ,y e ,z e ) 投影到 p (x p ,y p ,z p ) 上.把x_p 映射到x_n把y_p 映射到y_n在顶视图中,x e ,eye space 中的的x 坐标, 通过相似三⾓形的⽐值的映射到 x p ;x px e =−n z ex p =−n ∗x ez e =n ∗x e −z e 在侧视图中,y p 也是通过相似的⽅法计算出来的;y py e =−n z ey p =−n ∗y ez e =n ∗y e −z e 注意x p 和y p 都与z e 有关; 与−z e 成反⽐即除以−z e . 这是构造 GL_PROJECTION 矩阵的第⼀条线索. 在 eye coordinates 与 GL_PROJECTION 矩阵相乘完成变换后, clip coordinates 依然是 . 最终将其除以他的w 分量来得到NDC.(更多细节)x clipy clipz clip w clip =M projection ×x eye y eye z eye w eye ,x ndc y ndc z ndc =x clip /w clip y ndc /w clip z ndc /w clip因此,我们可以⽤ −z e 作为 clip coordinates 的 w 分量. 于是 GL_PROJECTION 矩阵的第四⾏变成了 (0,0,−1,0).\begin{pmatrix}x_{c}\\y_{c}\\ z_{c}\\w_{c}\end{pmatrix} = \begin{pmatrix} .& . & . & .\\ .& . & . &. \\ .& . & .&. \\ 0& 0 & -1 & 0 \end{pmatrix} \times \begin{pmatrix}x_{e}\\y_{e}\\z_{e}\\w_{e}\end{pmatrix}, \therefore w_c = -z_e 接下来,我们通过线性关系把 x_p,y_p 映射到 NDC 中的x_n,y_n 上; [l,r] => [-1,1] 和 [b,t] => [-1,1]x_n = \frac{1-(-1)}{r-l}*x_p + \beta 1 = \frac{2r}{r-l}+ \beta (⽤(r,1)代换(x_p,x_n))\beta = 1-\frac{2r}{r-l} = \frac{r-l}{r-l}-\frac{2r}{r-l} = \frac{r-l-2r}{r-l} = \frac{-r-l}{r-l} = -\frac{r+l}{r-l}\therefore x_n = \frac{2x_p}{r-l} - \frac{r+l}{r-l}y_n = \frac{1-(-1)}{t-b}*y_p + \beta1 = \frac{2t}{t-b}+ \beta (⽤(t,1)代换(y_p,y_n))\beta = 1-\frac{2t}{t-b} = \frac{t-b}{t-b}-\frac{2t}{t-b} = \frac{t-b-2t}{t-b} = \frac{-t-b}{t-b} = -\frac{t+b}{t-b}\therefore y_n = \frac{2y_p}{t-b} - \frac{t+b}{t-b}然后把x_p 和y_p 变量代换到上述式⼦中x_n = \frac{2x_p}{r-l}-\frac{r+l}{r-l} (x_p = \frac{nxe}{-z_e})x_n = \frac{2*\frac{nx_e}{-z_e}}{r-l} - \frac{r+l}{r-l}x_n = \frac{2n*x_e}{(r-l)(-z_e)} - \frac{r+l}{r-l}x_n = \frac{\frac{2n}{r-l}*x_e}{-z_e} - \frac{r+l}{r-l}x_n = \frac{\frac{2n}{r-l}*x_e}{-z_e} + \frac{\frac{r+l}{r-l}*z_e} {-z_e}x_n = (\frac{2n}{r-l}*x_e+\frac{r+l}{r-l}*z_e)/-z_e = x_c / -z_e同理可得y_n = (\frac{2n}{t-b}*y_e+\frac{t+b}{t-b}*z_e)/-z_e = y_c/-z_e注意我们使每个⽅程的两个项都除以-z_e 来表⽰perspective division(透视除法)(x_c/w_c,y_c/w_c ). ⽽且我们之前已经把w_c 设成了-z_e 了, 所以括号内的项已经是 clip coordinates 的 x_c 和y_c 了.于是得到了GL_PROJECTION 矩阵的前两⾏\begin{pmatrix}x_{c}\\y_{c}\\ z_{c}\\w_{c}\end{pmatrix} = \begin{pmatrix} \frac{2n}{r-l}& 0 & \frac{r+l}{r-l} & 0\\ 0& \frac{2n}{t-b} & \frac{t+b}{t-b} &0 \\ .& . & .&. \\ 0& 0 & -1 & 0\end{pmatrix} \times \begin{pmatrix}x_{e}\\y_{e}\\ z_{e}\\w_{e}\end{pmatrix}现在我们只剩GL_PROJECTION 矩阵的第三⾏需要解出了. 但解z_n 并不像其他坐标那样简单,因为 eye space 的z_e 总是被投影到近平⾯的-n 上. 但我们为了 clipping(裁剪)和depth test(深度测试)需要保证z 坐标的唯⼀性.,⽽且还要能够反投影(还原变换). 因为z 并不依赖于x 和y 坐标,我们借⽤w 分量 来找到 z_n 和z_e 之间的关系. 因此我们可以像下⾯这样来指定 GL_PROJECTION 矩阵的第三⾏.\begin{pmatrix}x_{c}\\y_{c}\\ z_{c}\\w_{c}\end{pmatrix} = \begin{pmatrix} \frac{2n}{r-l}& 0 & \frac{r+l}{r-l} & 0\\ 0& \frac{2n}{t-b} & \frac{t+b}{t-b} &0 \\ .& . & A&B \\ 0& 0 & -1 & 0\end{pmatrix} \times \begin{pmatrix}x_{e}\\y_{e}\\ z_{e}\\w_{e}\end{pmatrix}, z_n=z_c/w_c=\frac{Az_e+Bw_e}{-z_e}()()()()在 eye space中, w_e等于1. 因此等式变成z_n = \frac{Az_e+B}{-z_e}我们⽤(z_e,z_n)的关系来找到系数A和B;将(-n,-1)和(-f,1)回代到上式中\left\{\begin{matrix} \frac{-An+B}{n} = -1\\ \frac{-Af+B}{f} = 1 \end{matrix}\right. \rightarrow \left\{\begin{matrix} -An+B = -n \;(1)\\ -Af+B = f \;(2) \end{matrix}\right.重写等式(1);B=An-n \; (1')将B带⼊(2);-Af +(An-n) = f \; (2)$-(f-n)A = f + n A = -\frac{f+n}{f-n}$把A回代到(1)中;(\frac{f+n}{f-n})n + B = -n \; (1)B = -n - (\frac{f+n}{f-n})n = -(1+\frac{f+n}{f-n})n = -(\frac{f-n+f+n}{f-n})n = -\frac{2fn}{f-n}解出A和B后就可以得到Z_e和Z_n的关系;Z_n = \frac{-\frac{f+n}{f-n}z_e - \frac{2fn}{f-n}}{-z_e} \; (3)最终解出了整个 GL_PROJECTION 矩阵\begin{pmatrix} \frac{2n}{r-l}& 0 & \frac{r+l}{r-l} & 0\\ 0& \frac{2n}{t-b} & \frac{t+b}{t-b} &0 \\ 0& 0 & \frac{-{f+n}}{f-n}& \frac{-2fn}{f-n} \\ 0& 0 & -1 & 0 \end{pmatrix}这个投影是⼀种通⽤形式,如果可视平截头体是对称的,即r=-l 和 t=-b,可以对其化简\left\{\begin{matrix} r+l=0\\ r-l=2r \; (宽) \end{matrix}\right. , \left\{\begin{matrix} t+b=0 \\ t-b=2t \;(⾼) \end{matrix}\right.\begin{pmatrix} \frac{n}{r}& 0 & 0 & 0\\ 0& \frac{n}{t} & 0 &0 \\ 0& 0 & \frac{-{f+n}}{f-n}& \frac{-2fn}{f-n} \\ 0& 0 & -1 & 0 \end{pmatrix}在继续之前,请观察⼀下等式(3)中z_e和z_n的关系,你会发现他们并不是线性关系⽽是分式关系,这意味着在近平⾯会有⾮常⾼的精度⽽远平⾯的精度很低.如果[-n,-f]的范围很⼤,就会导致深度精度问题(z-fighting(深度冲突)); 在远平⾯z_e值⼩改动不会影响到z_n的值. 所以n和f的距离应该越⼩越好从⽽减少深度缓冲的精度问题.深度缓冲精度的⽐较Orthographic Projection(正射投影)为正射投影构造 GL_PROJECTION ⽐透视模式下的要简单的多正射视锥和标准化设备坐标(NDC)eye space 中所有的x_e,y_e和z_e分量都线性映射到 NDC. 我们只需要把长⽅体视锥缩放正⽅体,然后把它移动到原点. 让我们来通过线性关系来解出 GL_PROJECTION ⾥的元素吧.把x_e映射到x_nx_n = \frac{1-(-1)}{r-l}*x_e + \beta1 = \frac{2r}{r-l} + \beta \; (⽤(r,1)代换(x_e,x_n))\beta = 1 - \frac{2r}{r-l} = - \frac{r+l}{r-l}\therefore x_n = \frac{2}{r-l}*x_e - \frac{r+l}{r-l}把y_e映射到y_ny_n = \frac{1-(-1)}{t-b}*y_e + \beta1 = \frac{2t}{t-b} + \beta \; (⽤(t,1)代换(y_e,y_n))\beta = 1 - \frac{2t}{t-b} = - \frac{t+b}{t-b}\therefore y_n = \frac{2}{t-b}*y_e - \frac{t+b}{t-b}把z_e映射到z_nz_n = \frac{1-(-1)}{-f-(-n)}*z_e + \beta1 = \frac{2f}{f-n} + \beta \; (⽤(-f,1)代换(z_e,z_n))\beta = 1 - \frac{2f}{f-n} = - \frac{f+n}{f-n}\therefore z_n = \frac{-2}{f-n}*z_e - \frac{f+n}{f-n}由于在正射投影中不再需要w分量, GL_PROJECTION 矩阵的第四⾏保留成(0,0,0,1), 于是可以得到正射投影的 GL_PROJECTION\begin{pmatrix} \frac{2}{r-l}& 0 & 0 & -\frac{r+l}{r-l}\\ 0& \frac{2}{t-b} & 0 &-\frac{t+b}{t-b} \\ 0& 0 & \frac{-2}{f-n}& -\frac{f+n}{f-n} \\ 0& 0 & 0 & 1 \end{pmatrix}同样的,如果视锥是对称的,即r=-l 和 t=-b,可以对其化简\left\{\begin{matrix} r+l=0\\ r-l=2r \; (宽) \end{matrix}\right. , \left\{\begin{matrix} t+b=0 \\ t-b=2t \;(⾼) \end{matrix}\right.\begin{pmatrix} \frac{1}{r}& 0 & 0 & 0\\ 0& \frac{1}{t} & 0 &0 \\ 0& 0 & \frac{-{2}}{f-n}& -\frac{f+n}{f-n} \\ 0& 0 & 0 & 1 \end{pmatrix}Processing math: 26%。
OpenGL的空间变换(下):空间变换通过本⽂的上篇,我们了解到矩阵的基础概念。
并且掌握了矩阵在空间⼏何中的应⽤。
接下来,我们将结合矩阵来了解 OpenGL 的空间变换。
在使⽤ OpenGL 的应⽤程序中,当我们指定了模型的顶点后,顶点依次会变换到不同的 OpenGL 空间中:世界空间模型空间(也称为对象空间)视图空间(也称为视点空间、摄像机空间)裁剪空间标准设备坐标空间窗⼝空间在经过这⼀系列的空间变换之后,顶点才会被显⽰在屏幕上。
世界空间(World Space)世界空间相对于其他坐标空间来说是固定不变的。
所以,它也被⽤作空间变换的参考系。
我们把它的坐标系称为世界坐标系。
在没有特别说明的情况下,我们⽤来描述⼀个⼏何对象(点、向量或坐标)的数值数据,都是基于世界坐标系来设定的。
世界坐标系⽤矩阵来表⽰就是⼀个单位矩阵。
模型空间(Model Space)模型空间,也称为对象空间。
如果把世界空间⽐作现实世界的话,那么模型就好⽐⼀座房⼦或者房⼦⾥的⼀个⼈等等。
假设以⼈的重⼼为原点,正⾯向前的⽅向为 z-轴,头顶的⽅向为 y-轴,左侧⽅向为 x-轴来构建⼀个坐标系。
我们可以⽤这个坐标系来描述这个⼈⾃⾝的模型空间。
这个坐标系也称为模型坐标系(或对象坐标系)。
模型坐标系并不是绝对的,如果以⼈的⿐尖为原点,头顶的⽅向改为 z-轴,正⾯向前的⽅向为 y-轴,右侧⽅向为 z-轴来构建其模型坐标系。
这个模型坐标系同样可以⽤来描述这个⼈⾃⾝的模型空间。
只不过⽤不同坐标系来描述时,描述出来的数据不⼀定相同。
⼀般来说,我们都是基于世界坐标系来描述模型坐标系的。
在这种情况下,世界坐标系可以看作是模型坐标系的⽗坐标系:其中,⿊⾊的坐标系为世界坐标系;灰⾊的坐标系为模型坐标系。
模型变换(模型-世界变换)默认情况下模型坐标系的原点位于世界坐标系的原点,并且坐标轴的⽅向与世界坐标系的坐标轴⼀致。
我们可以通过⼀系列的缩放、旋转和*移,将模型以任意⾓度摆在任意位置上。
实验5 OpenGL模型视图变换一、实验目的:理解掌握OpenGL程序的模型视图变换。
二、实验内容:(1)阅读实验原理,运行示范实验代码,理解掌握OpenGL程序的模型视图变换;(2)根据示范代码,尝试完成实验作业;三、实验原理:在代码中,视图变换必须出现在模型变换之前,但可以在绘图之前的任何时候执行投影变换和视口变换。
1.display()程序中绘图函数潜在的重复性强调了:在指定的视图变换之前,应该使用glLoadIdentity()函数把当前矩阵设置为单位矩阵。
2.在载入单位矩阵之后,使用gluLookAt()函数指定视图变换。
如果程序没有调用gluLookAt(),那么照相机会设定为一个默认的位置和方向。
在默认的情况下,照相机位于原点,指向Z轴负方向,朝上向量为(0,1,0)。
3.一般而言,display()函数包括:视图变换 + 模型变换 + 绘制图形的函数(如glutWireCube())。
display()会在窗口被移动或者原来先遮住这个窗口的东西被一开时,被重复调用,并经过适当变换,保证绘制的图形是按照希望的方式进行绘制。
4.在调用glFrustum()设置投影变换之前,在reshape()函数中有一些准备工作:视口变换 + 投影变换 + 模型视图变换。
由于投影变换,视口变换共同决定了场景是如何映射到计算机的屏幕上的,而且它们都与屏幕的宽度,高度密切相关,因此应该放在reshape()中。
reshape()会在窗口初次创建,移动或改变时被调用。
OpenGL中矩阵坐标之间的关系:物理坐标*模型视图矩阵*投影矩阵*透视除法*规范化设备坐标——〉窗口坐标(1)视图变换函数gluLookAt(0.0,0.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0,)设置照相机的位置。
把照相机放在(0,0,5),镜头瞄准(0,0,0),朝上向量定为(0,1,0)朝上向量为照相机指定了一个唯一的方向。
三维图形的光照、贴图及阴影处理(OpenGL)实验过程:一、在VS6.0中建立新工程。
1、新建一个Win32 Application的工程。
2、向工程项目添加C++源文件。
3、将OpenGL框架复制到文件中。
4、设置OpenGL窗口标题。
二、场景设置。
1、视线处于一具有地板及前、左、右三面墙壁的空间中。
2、空间顶部中央有一光源。
3、空间中央有一地球仪,不断旋转。
三、建立视口结构及视点属性。
1、在坐标系上建立视图结构。
如图。
2、参数设置。
窗口大小:800*600。
视口大小:800*600。
透视深度:0.1~100。
透视角:60°。
视点位置:(0.0, 2.0, 15.0)。
视线方向:z轴负方向。
视点上方向:y轴正方向。
3、调用函数glViewport()、gluPerspective()和gluLookAt()实现。
四、绘制三维图形。
1、开启深度测试模式。
为防止图形重叠时出现层次混乱,必须对绘制图形进行消隐处理。
直接调用函数glEnable(GL_DEPTH_TEST)开启深度测试。
2、绘制地面与墙壁。
调用OpenGL基本几何元素绘制过程glBegin(GL_QUADS)、glBegin(GL_QUAD_STRIP)绘制四个平面,坐标范围为:x: -10~10, y: -2~20, z: -10~10。
坐标系结构如图。
3、绘制地球仪。
设计函数void DrawEarth()实现地球仪的绘制,分别调用OpenGL球面绘制函数gluSphere()绘制地球形状、柱面绘制函数gluCylinder()绘制地轴两头形状。
(1)参数设置。
球面半径:2。
球面细度:水平100,垂直100。
柱面半径:0.05。
柱面高度:1。
柱面细度:水平50,垂直1。
(2)结构如图。
4、绘制模拟光源。
(1)绘制“灯罩”。
调用glBegin(GL_TRIANGLE_STRIP)绘制4个三角形,构成棱椎形灯罩的4个侧面。
(2)绘制“灯泡”。
openGL投影矩阵
概述
显示器是2d的。
3d场景需要转换为2d图像才能显示在屏幕上。
投影矩阵(GL_PROJECTION)用于完成这个工作。
投影矩阵将观察坐标(eye coordinates)转换成裁剪坐标(clip coordinates)。
然后,裁剪坐标被除以w,转换为规范化的设备坐标(NDC)。
需要记住的一点是,裁剪操作和规范化都由投影矩阵(GL_PROJECTION)完成。
下面介绍如何用6个参数(left,right,bottom,top,near,far)构建投影矩阵。
裁剪(clipping)操作是在裁剪坐标上进行的,安排在透视除法执行之前。
裁剪坐标xc,yc,zc同wc比较,若每个分量都落在(-wc,wc)外,那么此坐标将被裁剪掉。
在透视投影中,3d场景中的点(观察坐标)从平截头体中映射到正方体(NDC)中;x坐标从[l,r]映射到[-1,1],y坐标从[b,t]映射到[-1,1],z坐标从[n,f]映射到[-1,1]。
注意到,观察坐标系是右手系,规范设备坐标系是左手系。
这就有,在观察坐标系中,摄像机朝向沿着-z,而在NDC中,方向沿着z。
由于glFrustum()只接受正参数,所以构造投影矩阵的时候要变号。
openGL中,3d场景中,观察坐标系下的点被投影到近投影面。
下图展示了观察坐标系点(xe,ye,ze)投影到近投影面上的点(xp,yp,zp)。
从Top View of Projection看,xe投影到xp,根据等比性质:
从Side View of Projection看,yp计算类似:
注意到,xp和yp依赖于-ze,这一点要引起重视。
在观察坐标被投影矩阵转换为裁剪坐标后,裁剪坐标仍然是同质坐标。
在规范化阶段执行透视除法变为规范设备坐标(NDC)。
因此,可以将wc的值定为-ze。
投影矩阵最后一行为(0,0,-1,0)
下一步,将xp,yp映射到xn,yn,此为线性映射[l,r]=>[-1,1],[b,t]=>[-1,1]:
将xp,yp带入上面结果:
对比(xc/wc,yc/wc)wc=-ze得出上式括号中分别为xc,yc。
由上式的结果可以观察出投影矩阵的第一行、第二行值:
现在只差第三行。
Ze总是映射到-n,但是又需要有区分的z值用于裁剪和深度测试,也需要能够实现逆变换。
我们看到,z是不依赖x或y,可以借助wc来分析zn和ze的关系。
我们设投影矩阵如下:
在观察坐标系中,we等于1,则有:
Ze=-n时,zn=-1;ze=-f时,zn=1,将其带入上式有:
有(1)有:
带入(2)有:
将A带入(1)有:
将A、B带入zn,ze关系式:
最后得到投影矩阵:
当视见体是对称的,有r=-l,t=-b,则:
由(3)式看到,ze和zn成反比,ze去[-f,-n],有图像看出,在近投影面zn有较高精度,在远投影面精度低,当区间[-f,-n]增大时,靠近远投影面的点的zn由于过分靠近而超出计算机最大精度(z-fighting),即ze在较远处的细小差别不能在zn上得到表达,而具有相同的zn值。
所以,区间[-f,-n]应尽可能短,以避免精度问题。
正投影
不存在透视计算,要做的只是将一个长方体映射成正方体。
齐次项w不再需要,第四行写为(0,0,0,1):
当是对称情况时,r=-l,t=-b:。