透视投影(Perspective_Projection)变换推导

透视投影(Perspective_Projection)变换推导
透视投影(Perspective_Projection)变换推导

透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和透视除法两步完成的。

透视投影变换是令很多刚刚进入3D图形领域的开发人员感到迷惑乃至神秘的一个图形技术。其中的理解困难在于步骤繁琐,对一些基础知识过分依赖,一旦对它们中的任何地方感到陌生,立刻导致理解停止不前。

没错,主流的3D APIs如OpenGL、D3D的确把具体的透视投影细节封装起来,比如

gluPerspective(…) 就可以根据输入生成一个透视投影矩阵。而且在大多数情况下不需要了解具体的内幕算法也可以完成任务。但是你不觉得,如果想要成为一个职业的图形程序员或游戏开发者,就应该真正降伏透视投影这个家伙么?我们先从必需的基础知识着手,一步一步深入下去(这些知识在很多地方可以单独找到,但我从来没有在同一个地方全部找到,但是你现在找到了)。

我们首先介绍两个必须掌握的知识。有了它们,我们才不至于在理解透视投影变换的过程中迷失方向(这里会使用到向量几何、矩阵的部分知识,如果你对此不是很熟悉,可以参考

可以找到一组坐标(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)是坐标系下表达一个向量和点的不同表达方式。这里可以看出,虽然都是用代数分量的形式表达向量和点,但表达一个点比一个向量需要额外的信息。如果我写出一个代数分量表达(1, 4, 7),谁知道它是个向量还是个点!

我们现在把(1)(3)写成矩阵的形式:

这里(a,b,c,o)是坐标基矩阵,右边的列向量分别是向量v和点p在基下的坐标。这样,向量和点在同一个基下就有了不同的表达:3D向量的第4个代数分量是0,而3D点的第4个代数分量是1。像这种这种用4个代数分量表示3D几何概念的方式是一种齐次坐标表示。

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

这样,上面的(1, 4, 7)如果写成(1,4,7,0),它就是个向量;如果是(1,4,7,1),它就是个点。

下面是如何在普通坐标 (Ordinary Coordinate)和齐次坐标(Homogeneous Coordinate)之间进行转换:

从普通坐标转换成齐次坐标时,

如果(x,y,z)是个点,则变为(x,y,z,1);

如果(x,y,z)是个向量,则变为 (x,y,z,0)

从齐次坐标转换成普通坐标时,

如果是(x,y,z,1),则知道它是个点,变成(x,y,z);

如果是(x,y,z,0),则知道它是个向量,仍然变成(x,y,z)

以上是通过齐次坐标来区分向量和点的方式。从中可以思考得知,对于平移T、旋转R、缩放S这3个最常见的仿射变换,平移变换只对于点才有意义,因为普通向量没有位置概念,只有大小和方向,这可以通过下面的式子清楚地看出:

而旋转和缩放对于向量和点都有意义,你可以用类似上面齐次表示来检测。从中可以看出,齐次坐标用于仿射变换非常方便。

此外,对于一个普通坐标的点P=(Px, Py, Pz),有对应的一族齐次坐标(wPx, wPy, wPz, w),其中w不等于零。比如,P(1, 4, 7)的齐次坐标有(1, 4, 7, 1)、(2, 8, 14, 2)、(-0.1, -0.4, -0.7, -0.1)等等。因此,如果把一个点从普通坐标变成齐次坐标,给x,y,z乘上同一个非零数w,然后增加第4个分量w;如果把一个齐次坐标转换成普通坐标,把前三个坐标同时除以第4个坐标,然后去掉第4个分量。

由于齐次坐标使用了4个分量来表达3D概念,使得平移变换可以使用矩阵进行,从而如F.S. Hill, JR所说,仿射(线性)变换的进行更加方便。由于图形硬件已经普遍地支持齐次坐标与矩阵乘法,因此更加促进了齐次坐标使用,使得它似乎成为图形学中的一个标准。

简单的线性插值

这是在图形学中普遍使用的基本技巧,我们在很多地方都会用到,比如2D位图的放大、缩小,Tweening变换,以及我们即将看到的透视投影变换等等。基本思想是:给一个x属于[a, b],找到y属于[c, d],使得x与a的距离比上ab长度所得到的比例,等于y与c的距离比上cd长度所得到的比例,用数学表达式描述很容易理解:

这样,从a到b的每一个点都与c到d上的唯一一个点对应。有一个x,就可以求得一个y。

此外,如果x不在[a, b]内,比如x < a或者x > b,则得到的y也是符合y < c或者y > d,比例仍然不变,插值同样适用。

透视投影变换

好,有了上面两个理论知识,我们开始分析这次的主角——透视投影变换。这里我们选择OpenGL的透视投影变换进行分析,其他的 APIs会存在一些差异,但主体思想是相似的,可以类似地推导。经过相机矩阵的变换,顶点被变换到了相机空间。这个时候的多边形也许会被视锥体裁剪,但在这个不规则的体中进行裁剪并非那么容易的事情,所以经过图形学前辈们的精心分析,

裁剪被安排到规则观察体(Canonical View Volume, CVV)中进行,CVV是一个正方体,x, y, z的范围都是[-1,1],多边形裁剪就是用这个规则体完成的。所以,事实上是透视投影变换由两步组成:

1)用透视变换矩阵把顶点从视锥体中变换到裁剪空间的CVV中。

2) CVV裁剪完成后进行透视除法(一会进行解释)。

我们一步一步来,我们先从一个方向考察投影关系。

上图是右手坐标系中顶点在相机空间中的情形。设P(x,z)是经过相机变换之后的点,视锥体由eye——眼睛位置,np——近裁剪平面,fp——远裁剪平面组成。N是眼睛到近裁剪平面的距离,F是眼睛到远裁剪平面的距离。投影面可以选择任何平行于近裁剪平面的平面,这里我们选择近裁剪平面作为投影平面。设P’(x’,z’)是投影之后的点,则有z’ = -N。通过相似三角形性质,我们有关系:

同理,有

这样,我们便得到了P投影后的点P’

从上面可以看出,投影的结果z’始终等于-N,在投影面上。实际上,z’对于投影后的P’已经没有意义了,这个信息点已经没用了。但对于3D图形管线来说,为了便于进行后面的片元操作,例如z缓冲消隐算法,有必要把投影之前的z保存下来,方便后面使用。因此,我们利用这个没用的信息点存储z,处理成:

这个形式最大化地使用了3个信息点,达到了最原始的投影变换的目的,但是它太直白了,有一点蛮干的意味,我感觉我们最终的结果不应该是它,你说呢?我们开始结合CVV进行思考,把它写得在数学上更优雅一致,更易于程序处理。假入能够把上面写成这个形式:

那么我们就可以非常方便的用矩阵以及齐次坐标理论来表达投影变换:

其中

哈,看到了齐次坐标的使用,这对于你来说已经不陌生了吧?这个新的形式不仅达到了上面原始投影变换的目的,而且使用了

齐次坐标理论,使得处理更加规范化。注意在把

变成

的一步我们是使用齐次坐标变普通坐标的规则完成的。这一步在透视投影过程中称为透视除法(Perspective Division),这是透视投影变换的第2步,经过这一步,就丢弃了原始的z值(得到了CVV中对应的z值,后面解释),顶点才算完成了投影。

而在这两步之间的就是CVV裁剪过程,所以裁剪空间使用的是齐次坐标

,主要原因在于透视除法会损失一些必要的信息(如原始z,第4个-z保留的)从而使裁剪变得更加难以处理,这里我们不讨论CVV裁剪的细节,只关注透视投影变换的两步。

矩阵

就是我们投影矩阵的第一个版本。你一定会问为什么要把z写成

有两个原因:

1)P’的3个代数分量统一地除以分母-z,易于使用齐次坐标变为普通坐标来完成,使得处理更加一致、高效。

2)后面的CVV是一个x,y,z的范围都为[-1,1]的规则体,便于进行多边形裁剪。而我们可以适当的选择系数a和b,使得

这个式子在z = -N的时候值为-1,而在z = -F的时候值为1,从而在z方向上构建CVV。

接下来我们就求出a和b:

这样我们就得到了透视投影矩阵的第一个版本:

使用这个版本的透视投影矩阵可以从z方向上构建CVV,但是x和y方向仍然没有限制在[-1,1]中,我们的透视投影矩阵的下一个版本就要解决这个问题。

为了能在x和y方向把顶点从Frustum情形变成CVV情形,我们开始对x和y进行处理。先来观察我们目前得到的最终变换结果:

我们知道-Nx / z的有效范围是投影平面的左边界值(记为left)和右边界值(记为right),即[left, right],-Ny / z则为[bottom, top]。而现在我们想把-Nx / z属于[left, right]映射到x属于[-1, 1]中,-Ny / z属于[bottom, top]映射到y 属于[-1, 1]中。你想到了什么?哈,就是我们简单的线性插值,你都已经掌握了!我们解决掉它:

则我们得到了最终的投影点:

下面要做的就是从这个新形式出发反推出下一个版本的透视投影矩阵。注意到

经过透视除法的形式,而P’只变化了x和y分量的形式,az+b和-z是不变的,则我们做透视除法的逆处理——给P’每个分量乘上-z,得到

而这个结果又是这么来的:

则我们最终得到:

M 就是最终的透视变换矩阵。相机空间中的顶点,如果在视锥体中,则变换后就在CVV中。如果在视锥体外,变换后就在CVV 外。而CVV本身的规则性对于多边形的裁剪很有利。OpenGL在构建透视投影矩阵的时候就使用了M的形式。注意到M的最后一行不是(0 0 0 1)而是(0 0 -1 0),因此可以看出透视变换不是一种仿射变换,它是非线性的。另外一点你可能已经想到,对于投影面来说,它的宽和高大多数情况下不同,即宽高比不为1,比如640/480。而CVV的宽高是相同的,即宽高比永远是1。这就造成了多边形的失真现象,比如一个投影面上的正方形在CVV的面上可能变成了一个长方形。解决这个问题的方法就是在对多变形进行透视变换、裁剪、透视除法之后,在归一化的设备坐标(Normalized Device Coordinates)上进行的视口(viewport)变换中进行校正,它会把归一化的顶点之间按照和投影面上相同的比例变换到视口中,从而解除透视投影变换带来的失真现象。进行校正前提就是要使投影平面的宽高比和视口的宽高比相同。

便利的投影矩阵生成函数

3D APIs都提供了诸如gluPerspective(fov, aspect, near, far)或者D3DXMatrixPerspectiveFovLH(pOut, fovY, Aspect, zn, zf)这样的函数为用户提供快捷的透视矩阵生成方法。我们还是用OpenGL的相应方法来分析它是如何运作的。

gluPerspective(fov, aspect, near, far)

fov即视野,是视锥体在xz平面或者yz平面的开角角度,具体哪个平面都可以。OpenGL和 D3D都使用yz平面。

aspect即投影平面的宽高比。

near是近裁剪平面的距离

far是远裁剪平面的距离。

上图中左边是在xz平面计算视锥体,右边是在yz平面计算视锥体。可以看到左边的第3步top = right / aspect使用了除法(图形程序员讨厌的东西),而右边第3步right = top x aspect使用了乘法,这也许就是为什么图形APIs采用yz平面的原因吧!

在上一篇文章中我们讨论了透视投影变换的原理,分析了OpenGL所使用的透视投影矩阵的生成方法。正如我们所说,不同的图形API因为左右手坐标系、行向量列向量矩阵以及变换范围等等的不同导致了矩阵的差异,可以有几十个不同的透视投影矩阵,但它们的原理大同小异。这次我们准备讨论一下Direct3D(以下简称D3D)以及J2ME平台上的JSR184(M3G)(以下简称M3G)的透视投影矩阵,主要出于以下几个目的:

(1)我们在写图形引擎的时候需要采用不同的图形API实现,当前主要是OpenGL和D3D。虽然二者的推导极为相似,但D3D的自身特点导致了一些地方仍然需要澄清。

(2) DirectX SDK的手册中有关于透视投影矩阵的一些说明,但并不详细,甚至有一些错误,从而使初学者理解起来变得困难,而这正是本文写作的目的。

(3) M3G是J2ME平台上的3D开发包,采用了OpenGL作为底层标准进行封装。它的透视投影矩阵使用OpenGL的环境但又进行了简化,值得一提。

本文努力让读者清楚地了解D3D与M3G透视投影矩阵的原理,从而能够知道它与OpenGL的一些差别,为构建跨API的图形引擎打好基础。需要指出的一点是为了完全理解本文的内容,请读者先理解上一篇文章《深入探索透视投影变换》的内容,因为OpenGL和它们的透视投影矩阵的原理非常相似,因此这里不会像上一篇文章从基础知识讲起,而是对比它们的差异来推导变换矩阵。我们开始!

OpenGL与D3D的基本差异

前面提到,不同API的基本差异导致了最终变换矩阵的不同,而导致OpenGL和D3D的透视投影矩阵不同的原因有以下几个:

(1) OpenGL默认使用右手坐标系,而D3D 默认使用左手坐标系。

(2) OpenGL使用列向量矩阵乘法而D3D使用行向量矩阵乘法。

(3) OpenGL的CVV的Z范围是[-1, 1],D3D的CVV的Z范围是[0, 1]。

以上这些差异导致了最终OpenGL和D3D的透视投影矩阵的不同。

D3D的透视投影矩阵推导

我们先来看最最基本的透视关系图(上一篇文章开始的时候使用的图):

这里我们考察的是xz平面上的关系,yz平面上的关系同理。这里o是相机位置。np是近裁剪平面,也是投影平面,N是它到相机的距离。fp是远裁剪平面,F 是它到相机的位置。p是需要投影的点,p’是投影之后的点。根据相似三角形定理,我们有

则有

注意到OpenGL使用右手坐标系,因此应该使用-N(请参考上一篇文章的这一步),而D3D使用左手坐标系,因此使用N,这是

二者的不同点之一。这样,我们得到投影之后的点

第三个信息点是变换之后的z在投影平面上的位置,也就是N,它已经没用了,我们把p’写成

从而用第三个没用信息点它来存储z(如果读者对这一点不太了解,请参考上一篇文章)。接下来我们求出a和b,从而在z方向上构建CVV。请注意这里是 OpenGL和D3D的另一个不同点,OpenGL的CVV的z范围是[-1, 1],而D3D的CVV的z范围是[0, 1]。也就是说,D3D 中在近裁剪平面上的点投影之后的点会处于CVV的z=0平面上,而在远裁剪平面上的点投影之后的点会在CVV的z=1平面上。这样我们的计算方程就是

从而我们得到了透视投影矩阵的第一个版本

这个时候第三个分量变换到CVV情形了,CVV的z范围是[0,1]。接下来根据上一篇文章所讲到的,我们要把前两个分量变成CVV 情形,CVV的x和y范围是[-1, 1],如下图所示:

使用线性插值,我们有:

这里left和right是投影平面的左右范围,top和bottom是投影平面的上下范围。xcvv和ycvv是我们需要算出的在CVV情形中的x和y,也就是我们要计算出的结果。但在算出它们之前,我们先把上面的式子写成:

这里有一个需要注意的地方,如果投影平面在x方向上居中,则

那么第一个式子就可以销掉等号两边的1/2,写成

同理,如果投影平面在y方向上居中,则第二个式子可以写成

则我们现在分两种情况讨论:

(1)投影平面的中心和x-y平面的中心重合(在x和y方向上都居中)

(2)一般情况

我们分别讨论:

(1)特殊情况方程

这组是特殊情况,方程比较简单,但也是使用频率最高的方式(这是D3DXMatrixPerspectiveLH、 D3DXMatrixPerspectiveRH、D3DXMatrixPerspectiveFovLH、 D3DXMatrixPerspectiveFovRH四个方法所使用的情况)。我们导出它:

则我们反推出透视投影矩阵:

其中

而 r-l和t-b可以分别看作是投影平面的宽w和高h。最后那个矩阵就是D3D的透视投影矩阵之一。另外呢,如果我们不知道right、left、top以及bottom这几个参量,也可以根据视野(FOV – Field Of View)参量来求得。下面是两个平面的视野关系图:

其中,两个fov分别是在x-z以及y-z平面上的视野。如果只给了一个视野,也可以通过投影平面的宽高比计算出来:

用一个视野算出w或者h,然后用宽高比算出h或者w。

(2)一般情况的方程

这组方程比较繁琐,但更具一般性(和OpenGL一般矩阵的推导一致,这也是D3DXMatrixPerspectiveOffCenterLH和D3DXMatrixPerspectiveOffCenterRH两个方法所使用的情况)。我们导出它:

我们继续反推出透视投影矩阵:

其中

最后那个矩阵就是D3D的一般透视投影矩阵。

好了,目前为止,我们已经导出了D3D的两个透视投影矩阵。下面我把上一篇导出的OpenGL的透视投影矩阵写出来,大家可以拿它和刚刚导出的D3D的一般性透视投影矩阵做一个对比。

如果仔细观察,可以发现二者在元素的布局上是一个转置的关系,这个就是由它们使用的左右手坐标系以及使用的行列矩阵的差异造成的。而另外在一些元素的细节上也存在着差异,这是由于D3D的CVV的z范围不同造成的。可见在原理相同的情况下,细微的环境差异可以造成非常大的变化,而这就是透视投影矩阵存在诸多不同版本的原因。一般情况的透视投影矩阵也可以使用视野方式来定义,方法和特殊情况相同。

M3G的透视投影矩阵

M3G是对OpenGL进行的一个封装,它的透视投影变换矩阵被放到了类Camera里面。因为它封装了OpenGL,因此环境和OpenGL 相同:右手坐标系、列向量乘法、CVV范围[-1, 1]。它唯一和OpenGL有些差异的地方就在于它只使用投影平面的中心和x-y 平面的中心重合(在x和y方向上都居中)的情况(就是我们上面D3D的第一种特殊情况)。我们用OpenGL透视投影矩阵最终版本来说明(再次提醒,如果读者对此感到迷惑,请参考第一篇文章):

上面是OpenGL透视投影矩阵的最终版本,也是一般性版本,我们要把它变成特殊性,版本,非常简单,和上面D3D的特殊情况一样,我们从对x和y进行插值的那一步来看:

和 D3D的第一种情况一样,销掉两边的1/2,得到:

则我们反推出透视投影矩阵:

最右边那个矩阵就是M3G的透视投影矩阵。仍然可以通过视野参数来设置透视投影矩阵,这里请读者自行推导,方法与上面D3D 的完全相同。

透视投影与正投影相关函数介绍

OpenGL 入门纪录--2 .透视函数glFrustum(), gluPerspective()函数用法和glOrtho()函数用 法 2008-12-24 16:14 在OpenGL中,如果想对模型进行操作,就要对这个模型的状态(当前的矩阵)乘上这个操作对应的一个矩阵. 如果乘以变换矩阵(平移, 缩放, 旋转), 那相乘之后, 模型的位置被变换; 如果乘以投影矩阵(将3D物体投影到2D平面), 相乘后, 模型的投影方式被设置; 如果乘以纹理矩阵(), 模型的纹理方式被设置. 而用来指定乘以什么类型的矩阵, 就是glMatriMode(GLenum mode); glMatrixMode有3种模式: GL_PROJECTION 投影, GL_MODELVIEW 模型视图, GL_TEXTURE 纹理. 所以,在操作投影矩阵以前,需要调用函数: glMatrixMode(GL_PROJECTION); //将当前矩阵指定为投影矩阵 然后把矩阵设为单位矩阵: glLoadIdentity(); 然后调用glFrustum()或gluPerspective(),它们生成的矩阵会与当前的矩阵相乘,生成透视的效果; 1.glFrustum() 这个函数原型为: void glFrustum(GLdouble left, GLdouble Right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); 创建一个透视型的视景体。其操作是创建一个透视投影的矩阵,并且用这个矩阵乘以当前矩阵。这个函数的参数只义近裁剪平面的左下角点和右上角点的三维空间坐标,即(left,bottom,-near)和(right,top,-near);最后一个参数far是远裁剪平面的离视点的距离值,其左下角点和右上角点空间坐标由函数根据透视投影原理自动生成。ne 和far表示离视点的远近,它们总为正值(near/far 必须>0)。 2.gluPerspective()

矩阵投影与最小二乘方法

题目:《神奇的矩阵——矩阵投影与最小二乘方法》 学校:哈尔滨工程大学 姓名:黎文科 联系方式: QQ群:53937814 联系方式: 190356321@https://www.360docs.net/doc/7d3550166.html,

矩阵投影与最小二乘方法 最小二乘法(Least Squares Method,简记为LSE)是一个比较古老的方法,源于天文学和测地学上的应用需要。在早期数理统计方法的发展中,这两门科学起了很大的作用。丹麦统计学家霍尔把它们称为“数理统计学的母亲”。此后近三百年来,它广泛应用于科学实验与工程技术中。美国统计史学家斯蒂格勒( S. M. Stigler)指出, 最小二乘方法是19世纪数理统计学的压倒一切的主题。1815年时,这方法已成为法国、意大利和普鲁士在天文和测地学中的标准工具,到1825年时已在英国普遍使用。 追溯到1801年,意大利天文学家朱赛普·皮亚齐发现了第一颗小行星谷神星。经过40天的跟踪观测后,由于谷神星运行至太阳背后,使得皮亚齐失去了谷神星的位置。随后全世界的科学家利用皮亚齐的观测数据开始寻找谷神星,但是根据大多数人计算的结果来寻找谷神星都没有结果。时年24岁的高斯也计算了谷神星的轨道。奥地利天文学家海因里希·奥尔伯斯根据高斯计算出来的轨道重新发现了谷神星。高斯于其1809年的著作《关于绕日行星运动的理论》中。在此书中声称他自1799年以来就使用最小二乘方法,由此爆发了一场与勒让德的优先权之争。 近代学者经过对原始文献的研究,认为两人可能是独立发明了这个方法,但首先见于书面形式的,以勒让德为早。然而,现今教科书和著作中,多把这个发明权归功于高斯。其原因,除了高斯有更大的名气外,主要可能是因为其正态误差理论对这个方法的重要意义。勒让德在其著作中,对最小二乘方法的优点有所阐述。然而,缺少误差分析。我们不知道,使用这个方法引起的误差如何,就需建立一种误差分析理论。高斯于1823年在误差e 1 ,… , e n 独立同分布的假定下,证明了最小二乘方法的一个最优性质: 在所有无偏的线性估计类中,最小二乘方法是其中方差最小的!在德国10马克的钞票上有高斯像,并配了一条正态曲线。在高斯众多伟大的数学成就中挑选了这一条,亦可见这一成就对世界文明的影响。 现行的最小二乘法是勒让德( A. M. Legendre)于1805年在其著作《计算慧星轨道的新方法》中提出的。它的主要思想就是选择未知参数,使得理论值与观测值之差的平方和达到最小: 2 211 ()()m m i i i H y y ===-=-∑∑理论值观测值

立方体纹理映射

1问题描述与算法思想 1.1纹理映射简介 纹理映射(Texture Mapping)是将纹理空间中的纹理像素映射到屏幕空间中的像素的过程。在三维图形中,纹理映射(Texture Mapping)的方法运用得最广,尤其描述具有真实感的物体。比如绘制一面砖墙,就可以使用一幅具有真实感的图像或者照片作为纹理贴到一个矩形上,这样,一面逼真的砖墙就画好了。如果不用纹理映射的方法,这墙上的每一块砖都要作为一个独立的多边形来绘制。另外,纹理映射能够保证在变换多边形时,多边形上的纹理也会随之变化。例如,用透视投影模式观察墙面时,离视点远的墙壁的砖块的尺寸就会缩小,而离视点近的就会大些,这些是符合视觉规律的。此外,纹理映射也被用在其他一些领域。如飞行仿真中常把一大片植被的图像映射到一些大多边形上用以表示地面,或者用大理石、木材等自然物质的图像作为纹理映射到多边形上表示相应的物体。纹理对象通过一个单独的数字来标识。这允许硬件能够在内存中保存多个纹理,而不是每次使用的时候再加载它们,从而减少了运算量,提高了速度。纹理映射是真实感图像制作的一个重要部分,运用它可以方便的制作出极具真实感的图形而不必花过多时间来考虑物体的表面细节。然而纹理加载的过程可能会影响程序运行速度,当纹理图像非常大时,这种情况尤为明显。如何妥善的管理纹理,减少不必要的开销,是系统优化时必须考虑的一个问题。还好,相关软件提供了纹理对象对象管理技术来解决上述问题。与显示列表一样,纹理对象通过一个单独的数字来标识。 立方体映射(cube-map)纹理是一种特殊类型的纹理,用于环境映射,使用一组图像并把他们作为立方体的面。立方体映射的6个面用正方形并且大小相同的6个子纹理表示。要从立方体纹理中采样的时候,使用的纹理坐标是3维,并且被看做来自原点的方向。方向指向用来读取纹理的立方体映射表面的位置。立方体纹理映射主要思想是通过观察向量和表面的法向量反射来确定采样的纹理坐标。 1.2实验目的 1) 掌握位图纹理读入方法; 2)掌握立方体纹理映射算法。 1.3功能要求 1)建立三维坐标系Oxyz,远点位于屏幕客户区中心,x轴水平向右为正,y轴垂直向上为正,z轴垂直于屏幕指向观察者。 2)设置屏幕背景色为黑色。 3)读入六张构成天空盒的位图作为纹理映射到立方体的可见表面上。 4)按下鼠标左键缩小立方体,按下鼠标右键增大立方体。 5)使用键盘方向旋转纹理立方体。 6)使用动画按钮播放或停止立方体动画。 1.4算法原理(算法思想) 立方体进行纹理映射是纹理对象并不是直接绑定到着色器,而是绑定到一个

透视投影(perspectiveprojection)变换推导

透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和透视除法两步完成的。 透视投影变换是令很多刚刚进入3D图形领域的开发人员感到迷惑乃至神秘的一个图形技术。其中的理解困难在于步骤繁琐,对一些基础知识过分依赖,一旦对它们中的任何地方感到陌生,立刻导致理解停止不前。 没错,主流的3D APIs如OpenGL、D3D的确把具体的透视投影细节封装起来,比如 gluPerspective(…) 就可以根据输入生成一个透视投影矩阵。而且在大多数情况下不需要了解具体的内幕算法也可以完成任务。但是你不觉得,如果想要成为一个职业的图形程序员或游戏开发者,就应该真正降伏透视投影这个家伙么?我们先从必需的基础知识着手,一步一步深入下去(这些知识在很多地方可以单独找到,但我从来没有在同一个地方全部找到,但是你现在找到了)。 我们首先介绍两个必须掌握的知识。有了它们,我们才不至于在理解透视投影变换的过程中迷失方向(这里会使用到向量几何、矩阵的部分知识,如果你对此不是很熟悉,可以参考 可以找到一组坐标(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)是坐标系下表达一个向量和点的不同表达方式。这里可以看出,虽然都是用代数分量的形式表达向量和点,但表达一个点比一个向量需要额外的信息。如果我写出一个代数分量表达(1, 4, 7),谁知道它是个向量还是个点! 我们现在把(1)(3)写成矩阵的形式:

弹塑性矩阵推导

弹塑性矩阵推导

考虑材料的塑性,其增量形式的本构关系可表达为 p d σ=(D -D )d ε (1) 式(1)中,D 为弹性矩阵,p D 为塑性矩阵。 弹性矩阵D 的形式为 422000333242000333224000333000000 000000000K G K G K G K G K G K G K G K G K G G G G ??+--??????-+-???? =??--+?????? ?????? D (2) 体积模量3(12) E K μ= -,剪切模量2(1) E G μ=+。 在应变空间内,塑性矩阵可表达为 1()T f f A ??= ??p D D D σσ (3) 式中, ( )()T T p f f f f A B ????=--????D D σσσσ (4) f 为屈服函数;p σ为塑性应力,p p =σD ε; 1/2(()())T p T p T p f f f f B f f f ωθε??? ???? ??? '=???? ????????? σσ I σσσ (5) [111000]T '=I ;p ω为塑性功;p θ为塑性体应变;p ε为等效塑性应变; κ为反映加载历史的参数。 当p κω=时 当p κθ=时 当p κε=时

对于Drucker-Prager 模型,其屈服条件为 120f I J α== (6) 1x y z I σσσ=++,222222 21()2 x y z xy yz zx J S S S S S S = +++++,α为材料常数。 2 2f J α?''=?I σ (7) 222T x y z xy yz zx S S S S S S '??=??S (8) 22 ()32f K J J αα?'''==+?D D I I σ (9) 222 ( )()(3)92T T T f f A K K G J J ααα??'''===+??D I I σσ (10) 1()T f f A ??= ??p D D D σσ 222 22222 222222112123113211212311321121231131121121121(3)(3)999(9)(9)(9)(T T T T T T K K K G J J K G K G K G J K G J K G J m mn ml S m S m S m mn n nl S n S n S n ml nl l S l S l S l S m S n S l ααααααααβββββββββββββ''= + +''''=++++++=p D I I I I S SS 21121122231122132123123123 1122231231132232 113113113113212113223113)()()S S S S S S m S n S l S S S S S S m S n S l S S S S S ββββββββββββββββββββ?? ? ? ???? ? ? ?????? ?????????? 令4 3 p K G =+,23 q K G =- 弹塑性矩阵可表达为 211212311321121231132 1121231132112112112112112223112213123 123123 112223()(p m q mn q ml S m S m S m q mn p n q nl S n S n S n q ml q nl p l S l S l S l S m S n S l G S S S S S S m S n S l S S G βββββββββββββββββββββββ------------------=-=-----?-?----?-ep p D D D 21231132232 113113113113212 113223 113)()S S S S m S n S l S S S S G S ββββββββββ?? ?? ? ??? ? ? ???? -???----?-?-??? ?

深入探索3D拾取技术

深入探索3D拾取技术 在游戏中,玩家需要通过点击2D屏幕来选择3D物体,这个过程就是拾取(picking)。拾取是3D游戏必不可少的基本操作,它实现了玩家和游戏世界内对象的交互。 虽然拾取技术很基本,但它却迷惑了很多3D初学者。很多朋友都问过我关于拾取的细节问题,这让我觉得很有必要具体探讨一下该技术。其实,拾取之所以让很多开发者感到复杂,主要原因在于它跨域了流水线的多个阶段,并且是逆流水线上行。另外,它是一个2D信息扩展到3D的过程,必须对信息做相应的扩展和额外的计算才能够得到正确的结果。下面我门具体分析一下这个技术。 水流线主要阶段分析 我们来直观地看一下从相机空间到viewport的变换 相机空间中的一个顶点v,经过透视变换后进入了CVV中。这个变换矩阵实际上完成了两个工作: 1)将顶点从3D空间投影到2D的投影平面(Projection Plane)上。 2)将投影平面上的2D投影点通过线性插值变换到齐次裁剪空间CVV中。 这些变换都通过透视矩阵一次完成。我之所以把这一步分解为两步,因为这对于分析拾取很重要。 顶点进入齐次裁剪空间并经过CVV裁剪,最终进行透视除法从4D齐次形式变回成3D形式。然后经过一个线性插值(被封装在视口(viewport)变换中),变换到viewport中,多个点以三角形的形式经过光栅化后被玩家看到。最后一步的点变换可以描述为: 3)将CVV中的点通过线性插值变换到viewport中。

分析了这个变换过程之后,我们知道了从相机空间开始实际处理点位置信息的操作,就是上面的三个步骤。这样,我们可以先把顶点从viewport中先变换回投影平面上,也就是我们可以先完成(2)和(3)的逆处理。这里我们不用考虑裁剪和透视除法这些操作,因为反推的时候,处于视口中的点,已经是经过裁剪后留下的有效点了,必定处于CVV内,也必定处于projection plane内!而且从viewport逆变换到projection plane,点一直保持2D形式。 picking的开始是玩家在屏幕上点击一个位置——这实际上是在viewport中进行了点击。我们通过响应玩家的点击事件,得到在viewport中的点击位置,记为P0(Xp0,Yp0)。然后我们把p0从viewport中线性插值到CVV中,得到P1(Xp1,Yp1): 上面的线性插值(如果对线性插值公式不熟悉,请参考《深入探索透视投影变换》一文中的线性插值部分)公式在x方向上计算出了CVV中的P1,y方向的公式同理。接下来我们再把P1从CVV中变换到projection plane中,得到P2(Xp2,Yp2): y方向的计算同理。P2就是viewport中玩家点击的点在projection plane上所对应的位置。目前来看很好。我们已经获得了相机空间中的投影平面上,玩家点击的位置。但目前的点是一个2D点——它处于投影平面上。玩家需要拾取的是一个3D对象,因此我们需要将2D信息拓展到3D中。 向3D世界拓展 将2D的点信息拓展到3D空间进行picking,会使用射线(ray)进行。ray就是一端固定,另一端无限延伸的线性模型。如下图所示:

画法几何与阴影透视_在线作业_1教学内容

画法几何与阴影透视_在线作业_1

画法几何与阴影透视_在线作业_1 一、单选题 1.一般应以()的方向作为主视图的方向。 A. 从物体上面向下投影 B. 最能反映出形体特征的 C. 任意 D. 物体最简单答案B 2.在直立圆柱的水平投影圆内的一个点所标的符号为(b)时点B在圆柱体的()。 A. 下底面 B. 上底面 C. 后半个柱面 D. 前半个柱面答案A 3.要求出物体的阴影,主要是求出物体上()的影。 A. 所有面 B. 阴线 C. 所有棱线 D. 各顶点的答案B 4.在绘制工程图时通常采用的是()投影法。 A. 中心 B. 正 C. 斜 D. 水平答案B 5.在使用丁字尺绘制图线时,丁字尺的尺头应紧靠在图版的()边。 A. 下 B. 右 C. 左 D. 上答案C 6.在圆球的水平投影上有一段斜线,此线段的正面和侧面投影是()。 A. 一个点 B. 一段直线 C. 椭圆的一部分 D. 圆的一部分答案C 7.图形的对称线和中心线是用()线绘制的。 A. 粗实线 B. 点划线 C. 细实线 D. 虚线答案B 8.如果圆平面的影在正面反映圆的实形,此圆平面为()面。 A. 水平 B. 正平 C. 铅垂面 D. 正垂答案B 9.当圆柱体的轴线与侧面垂直,它的()投影是圆。 A. 三个投影 B. W C. V D. H答案B 10.在()的情况下两个圆柱的相贯线为椭圆。 A. 轴线正交且直径相等 B. 轴线非正交且直径相等 C. 轴线正交且直径不相等 D. 轴线非正交且直径不相等答案A

11.在图样上标注圆弧尺寸时起止符号用()。 A. 圆点 B. 45°斜线 C. 箭头 D. ×答案C 12.平面图形为水平面时,它的()面投影反映平面图形的实形。 A. 以上全不对 B. V C. W D. H答案D 13.在图样中比例是指图形与实物相应要素的()之比。 A. 体积之比 B. 大小之比 C. 线性之比 D. 面积之比答案C 14.侧垂线落在起伏不平的铅垂面上的影,它的影线的()投影的形状和承影面的水平截交线成为倒影。 A. H B. 所有 C. W D. V 答案D 15.透视投影是()投影。 A. 正 B. 平行 C. 斜 D. 中心答案D 16.水平线的()投影反映线段的实长。 A. 以上全不对 B. 水平 C. 正面 D. 侧面答案B 17.用正垂面截切圆锥,截交线为椭圆时,椭圆短轴的正面投影在()。 A. 截交线的端点 B. 任意位置 C. 截交线的中点 D. 轴线与截交线的交点答案C 18.圆柱体的截交线有()种。 A. 1 B. 2 C. 3 D. 4 答案C 19.图中所示的长方体与半球相贯,相贯线是由四段()组成的空间曲线。 A. 双曲线 B. 抛物线 C. 折线 D. 圆弧线答案D 20.用正垂面截切圆柱时,截平面与圆柱的轴线成()度角时,它的侧面投影是圆。 A. 45 B. 30 C. 60 D. 90答案A

透视投影详解

透视投影 透视投影是用中心投影法将形体投射到投影面上,从而获得的一种较为接近视觉效果的单面投影图。它具消失感、距离感、相同大小的形体呈现出有规律的变化等一系列的透视特性,能逼真地反映形体的空间形象。透视投影也称为透视图,简称透视。在建筑设计过程中,透视图常用来表达设计对象的外貌,帮助设计构思,研究和比较建筑物的空间造型和立面处理,是建筑设计中重要的辅助图样。 透视投影符合人们心理习惯,即离视点近的物体大,离视点远的物体小,远到极点即为消失,成为灭点。它的视景体类似于一个顶部和底部都被切除掉的棱椎,也就是棱台。这个投影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面。 在平行投影中,图形沿平行线变换到投影面上;对透视投影,图形沿收敛于某一点的直线变换到投影面上,此点称为投影中心,相当于观察点,也称为视点。平行投影和透视投影区别在于透视投影的投影中心到投影面之间的距离是有限的,而平行投影的投影中心到投影面之间的距离是无限的。当投影中心在无限远时,投影线互相平行,所以定义平行投影时,给出投影线的方向就可以了,而定义透视投影时,需要指定投影中心的具体位置平行投影保持物体的有关比例不变,这是三维绘图中产生比例图画的方法。物体的各个面的精确视图可以由平行投影得到。另一方面,透视投影不保持相关比例,但能够生成真实感视图。对同样大小的物体,离投影面较远的物体比离投影面较近物体的投影图象要小,产生近大远小的效果. 透视投影的原理和实现 by Goncely 摘要:透视投影是3D渲染的基本概念,也是3D程序设计的基础。掌握透视投影的原理对于深入理解其他3D渲染管线具有重要作用。本文详细介绍了透视投影的原理和算法实

openGL投影矩阵原理及数学推导

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]:

深入探索透视投影变换

深入探索透视投影变换 -Twinsen编写 -本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教 -email: popyy@https://www.360docs.net/doc/7d3550166.html, 透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和透视除法两步完成的。 透视投影变换是令很多刚刚进入3D图形领域的开发人员感到迷惑乃至神秘的一个图形技术。其中的理解困难在于步骤繁琐,对一些基础知识过分依赖,一旦对它们中的任何地方感到陌生,立刻导致理解停止不前。 没错,主流的3D APIs如OpenGL、D3D的确把具体的透视投影细节封装起来,比如 gluPerspective(…)就可以根据输入生成一个透视投影矩阵。而且在大多数情况下不需要了解具体的内幕算法也可以完成任务。但是你不觉得,如果想要成为一个职业的图形程序员或游戏开发者,就应该真正降伏透视投影这个家伙么?我们先从必需的基础知识着手,一步一步深入下去(这些知识在很多地方可以单独找到,但我从来没有在同一个地方全部找到,但是你现在找到了 )。 我们首先介绍两个必须掌握的知识。有了它们,我们才不至于在理解透视投影变换的过程中迷失方向(这里会使用到向量几何、矩阵的部分知识,如果你对此不是很熟悉,可以参考《向量几何在游戏编程中的使用》系列文章)。 齐次坐标表示 透视投影变换是在齐次坐标下进行的,而齐次坐标本身就是一个令人迷惑的概念,这里我们先把它理解清楚。 根据《向量几何在游戏编程中的使用6》中关于基的概念。对于一个向量v以及基oabc, 可以找到一组坐标(v1,v2,v3),使得 v = v1 a + v2 b + v3 c (1)

深度探讨透视投影坐标系.

3d图形程序,就一定会做坐标变换。而谈到坐标变换,就不得不提起投影变换,因为它是所有变换中最不容易弄懂的。但有趣的是,各种关于透视变换的文档却依然是简之又简,甚至还有前后矛盾的地方。看来如此这般光景,想要弄清楚它,非得自己动手不可了。所以在下面的文章里,作者尝试推导一遍这个难缠的透视变换,然后把它套用到DX和PS2lib 的实例中去。 1.一般概念 所谓透视投影变换,就是view 空间到project 空间的带透视性质的坐标变换步骤(这两个空间的定义可以参考其他文档和书籍)。我们首先来考虑它应该具有那些变换性质。很显然,它至少要保证我们在view空间中所有处于可视范围内的点通过变换之后,统统落在project空间的可视区域内。好极了,我们就从这里着手——先来看看两个空间的可视区域。 由于是透视变换,view空间中的可见范围既是常说的视平截体(view frustum)。如图, (图1)它就是由前后两个截面截成的这个棱台。 从view空间的x正半轴看过去是下图这个样子。

(图2)接下来是project空间的可视范围。这个空间应当是处于你所见到的屏幕上。实际上将屏幕表面视作project空间的xoy平面,再加一条垂直屏幕向里(或向外)的z轴(这取决于你的坐标系是左手系还是右手系),这样就构成了我们想要的坐标系。好了,现在我们可以用视口(view port)的大小来描述这个可视范围了。比如说全屏幕640*480的分辨率,原点在屏幕中心,那我们得到的可视区域为一个长方体,它如下图(a)所示。 (图3) 但是,这样会带来一些设备相关性而分散我们的注意力,所以不妨先向DirectX文档学学,将project空间的可视范围定义为x∈[-1,1], y∈[-1,1], z∈[0,1]的一个立方体(上图b)。这实际

投影矩阵的定义

视锥就是场景中的一个三维空间,它的位置由视口的摄像机来决定。这个空间的形状决定了摄像机空间中的模型将被如何投影到屏幕上。透视投影是最常用的一种投影类型,使用这种投影,会使近处的对象看起来比远处的大一些。对于透视投影,视锥可以被初始化成金字塔形,将摄像机放在顶端。这个金字塔再经过前、后两个剪切面的分割,位于这两个面之间的部分就是视锥。只有位于视锥内的对象才可见。 视锥由凹视野( 在上图中,变量 投影矩阵是一个典型的缩放和透视矩阵。投影变换将视锥变换成一个直平行六面体的形状。因为视锥的近处比远处小,这样就会对靠近摄像机的对象起到放大的作用,也就将透视应用到了场景当中。 在视锥中,摄像机与空间原点间的距离被定义为变量 视矩阵将摄像机放置在场景的原点。又因为投影矩阵需要将摄像机放在 将两个矩阵相乘,得到下面的矩阵: 下图显示了透视变换如何将一个视锥变换成一个新的坐标空间。注意:锥形体变成了直平行六面体,原点从场景的右上角移到了中心。 在透视变换中,

这个矩阵基于一定的距离(这个距离是从摄像机到邻近的剪切面)对对象进行平移和旋转,但是它没有考虑到视野( 在这个矩阵中, 在程序中,使用视野角度来定义x和y缩放系数比使用视口的水平和垂直尺寸(在摄像机空间中)并不方便多少。下面两式使用了视口的尺寸,并且与上面的公式相等: 在这些公式中,Zn表示邻近的剪切面的位置,变量Vw和Vh表示视口的高和宽。这两个参数与 D3DVIEWPORT2结构中的dwWidth和dwHeight成员相关。 不管你使用那个公式,将同世界和视变换一样,可以调用下面的 D3DMATRIX ProjectionMatrix(const float near_plane,// distance to near clipping plane const float far_plane,// distance to far clipping plane const float fov_horiz,// horizontal field of view angle, in radians const float fov_vert)// vertical field of view angle, in radians { float h, w, Q; w = (float)cot(fov_horiz*0.5); h = (float)cot(fov_vert*0.5); Q = far_plane/(far_plane - near_plane); D3DMATRIX ret = ZeroMatrix(); ret(0, 0) = w; ret(1, 1) = h; ret(2, 2) = Q; ret(3, 2) = -Q*near_plane; ret(2, 3) = 1; return ret; } // end of ProjectionMatrix()

深入探索透视投影矩阵.

-Twinsen 编写 - 本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教 -email: 透视投影是 3D 固定流水线的重要组成部分,是将相机空间中的点从视锥 体 (frustum) 变换到规则观察体 (Canonical View Volume) 中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和透视除法两步完成的。 透视投影变换是令很多刚刚进入 3D 图形领域的开发人员感到迷惑乃至神秘的一个图形技术。其中的理解困难在于步骤繁琐,对一些基础知识过分依赖,一旦对它们中的任何地方感到陌生,立刻导致理解停止不前。 没错,主流的 3D APIs 如 OpenGL 、 D3D 的确把具体的透视投影细节封装起来,比如 gluPerspective(…) 就可以根据输入生成一个透视投影矩阵。而且在大多数情况下不需要了解具体的内幕算法也可以完成任务。但是你不觉得,如果想要成为一个职业的图形程序员或游戏开发者,就应该真正降伏透视投影这个家伙么?我们先从必需的基础知识着手,一步一步深入下去(这些知识在很多地方可以单独找到,但我从来没有在同一个地方全部找到,但是你现在找到了)。 我们首先介绍两个必须掌握的知识。有了它们,我们才不至于在理解透视投影变换的过程中迷失方向(这里会使用到向量几何、矩阵的部分知识,如果你对此不是很熟悉,可以参考《向量几何在游戏编程中的使用》系列文章)。 齐次坐标表示 透视投影变换是在齐次坐标下进行的,而齐次坐标本身就是一个令人迷惑的概念,这里我们先把它理解清楚。 根据《向量几何在游戏编程中的使用 6 》中关于基的概念。对于一个向量 v 以及基 oabc ,

投影矩阵的计算过程

投影矩阵的计算过程3d模型经过世界坐标变换、相机坐标变换后,下一步需要投影变换。投影变换的目的就是要把相机空间转换到标准视图空间,在这个空间的坐标都是正规化的,也就是坐标范围都在[-1,1]之间,之所以转换到这个空间是为了后续操作更方便。下面的讨论都是以列向量来表示,这样在变换操作时,采用的是矩阵左乘法,如果采用的是行向量的话,那就相反,矩阵右乘法即是向量在左边乘以变换矩阵。采用哪种表示并不影响结果,只需要把该种表示下得出的变换矩阵转置一下,就是采用另外一种表示模式需要的结果。常见的投影有两种,正交投影和透视投影,正交投影相对来说更简单,所以先来看看正交投影。最简单的正交变换矩阵 1 0 0 0 0 1 0 0 0 0 0 1 这个正交变换是不可逆变换,变换后x和y保留,z变成了0,在实际应用中,更常见的情况是限定x、y、z在一定的范围内的进行投影变换,比如x[l,r],y[b,t],z[n,f]。那么要把这段空间中的点变换到-1和1之间,只要完成两个变换,首先把坐标轴移到中心,然后进行缩放就可以了。采用列向量的话,那就是缩放矩阵乘以平移矩阵。2/(r-l) 0 0 0 1 0 0 -(r+l)/2 2/(r-l) 0 0 -(r+l)/(r-l) 0 2/(t-b) 0 0 x 0 1 0 -(b+t)/2 = 0 2/(t-b) 0 -(t+b)/(t-b) 0 0 2/(f-n) 0 0 0 1 -(n+f)/2 0 0 2/(f-n) -(f+n)/(f-n) 0 0 0 1 0 0 0 1 0 0 0 1 透视投影类比于我们人眼系统,看一个物体,会有远小近大的效果。在转换到相机空间后,相机是这个空间的原点,和正交投影体是一个长方体或者立方体不同,透视投影体是一个锥体被近平面截取掉头部剩下的空间。假定仍然采用上面的坐标表示。在透视投影下,空间上面的任何一点P投影到近平面上某点q,通过三角几何学我们可以得到qx=px*n/pz ,y点同理。假定直接投影到近平面,则该矩阵很简单,用Ma表示下面的矩阵1 0 0 0 0 1 0 0 0 0 1 0 0 0 1/n 0 则齐次空间某点(x,y,z ,1)被该矩阵转换后变成了(x ,y z, z/n) ,除以z/n,则变成了(nx/z,ny/z,n ,1) 正好吻合上面的公式。 undefined 但是我们知道投影变换需要把坐标变换到-1和1之间,假定先不考虑z轴的变换,在x轴和y轴上面经过上述变换后,已经投影在近平面了,假设近平面xy在[l,r] 和[b,t]之间了,因此只需要和上面的正交投影一样,进行平移和缩放操作就可以了,平移矩阵Mb为 1 0 0 -(l+r)/2 0 1 0 -(t+p)/2 0 0 1 -(f+n)/2 0 0 0 1 以及缩放矩阵Mc 2/(r-l) 0 0 0 0 2/(t-b) 0 0 0 0 2/(f-n) 0 0 0 0 1 McXMbXMa 得到的矩阵为2/(r-l) 0 -(r+l)/(n*(r-l))0 0 2/(t-b) -(t+b)/(n*(t-b)) 0 0 0 j k 0 0 1/n 0 j k 为未知数,这个矩阵也可以同时乘以n,则变为2n/(r-l) 0 -(r+l)/(r-l) 0 0 2n/(t-b) -(t+b)/(t-b) 0 0 0 j k 0 0 1 0 为了求解J k,我们需要把z变换到-1 和1 因此当z=n时为-1,z=f时为1 (j*n+k)/n= j+k/n=-1; 同理j+k/f=1; 得到k=2f*n/(n-f) j=-(n+f)/(n-f) 代入上面的矩阵,就得出通用的正交变换矩阵。而且在一般情况下r=-l ,b=-t 因此上述矩阵可以简化为n/r 0 0 0 0 n/t 0 0 0 0 -(n+f)/(n-f) 2f*n/(n-f) 0 0 1 0 n/r 和n/t可以进一步简化成水平半视角和垂直半视角的三角函数来表示,而水平视角和垂直视角和透视窗口的宽高比有是成正比的,最终上面两行可以用宽高

深入探索正交投影变换

深入探索正交投影变换 之前我们在《深入探索透视投影变换》以及《深入探索透视投影变换(续)》中研究了OpenGL、D3D以及M3G的透视投影变换的原理以及生成方法。这些方法在当前的主流图形API 中得到了普遍使用。但关于投影应用,还有一类经常使用的投影方式需要我们深入理解——正交投影,我们在本篇文章里面研究它(这里假设读者已经看过前两篇文章,并理解了绝大多数的理论,因为正交投影比透视投影的推导关系简单得多,因此我们的推导会非常得快,如果读者有任何的不解,请参考前两篇文章或者通过email联系我)。 在具体研究之前我觉得有必要把平面投影的分类简单介绍一下,目的是为了让大家有一个总体的认识,从而更好的理解这个知识体系。请看下图: 平面投影分为平行投影和透视投影两种类型,后者我们在前两篇文章中介绍了。平行投影则是具有矩形观察体的投影方式(透视投影则是视锥观察体),它不会根据物体离视点的远近缩放物体(透视投影则会)。平行投影可以分成侧投影和正交投影两种类型。这两种类型如何区分呢?我们继续看图吧: 上图中,v是投影平面,n是它的法线。p和q是平面外两点,p’和q’分别是它们在平面上的投影点。q的投影方向向量为Q = 单位化(q’-q),而p的投影方向向量为P = 单

位化(p’-p),其中Q不平行于n而P平行于n,则q的投影叫做侧投影,而p的投影叫做正交投影。正交投影是我们今天的研究对象。 实际上上面对平面投影的分类还可以继续向下细分,比如透视投影可以分为一灭点、二灭点以及三灭点透视投影。侧投影则可以继续分为散点侧投、斜二轴侧投等等。而正交投影则可以分成轴侧投影以及多视点正交投影等等。如果读者对此感兴趣,可以参考相关的图形学教程。 接下来我们研究正交投影。分别介绍OpenGL、D3D以及M3G的。我们的环境约定(左右手坐标系、行列向量乘法、CVV范围)仍然尊重相应API自己的设置。 OpenGL正交投影变换 下图是OpenGL的右手坐标系中观察空间的情形,我们看到的是正交投影的矩形观察体,原点是相机位置,n是近裁剪平面到相机平面的距离,f是远裁剪平面到相机平面的距离。p是观察体中的一个点,p’是它投影之后的点。 投影之后我们有关系: 因为是正交投影,没有统一的投影射线目标点,因此投影之后的x和y不会变,而z 则永远地变成了-n,跑到了投影平面上(我们让投影平面和近裁剪平面重合),它已经没用了,则我们用这个没用的信息保存z(为了之后片元操作的时候用),写为:

透视投影矩阵推导

在上一篇文章中我们讨论了透视投影变换的原理,分析了 OPe nGL 所使用的透视 投影矩阵的生成方法。正如我们所说,不同的图形APl 因为左右手坐标系、行向 量列向量矩阵以及变换范围等等的不同导致了矩阵的差异,可以有几十个不同的 透视投影矩阵,但它们的原理大同小异。这次我们准备讨论一下 DireCt3D (以 下简称D3D 以及J2ME 平台上的JSR184(M3G (以下简称M3G 的透视投影矩 阵,主要出于以下几个目的: (1) 我们在写图形引擎的时候需要采用不同的图形 API 实现,当前主要 是OPenGL 和D3D 虽然二者的推导极为相似,但 D3D 的自身特点导致了一些地 方仍然需要澄清。 (2) DireCtX SDK 的手册中有关于透视投影矩阵的一些说明,但并不详 细,甚至有一些错误,从而使初学者理解起来变得困难, 而这正是本文写作的目 的。 (3) M3G 是J2ME 平台上的3D 开发包,采用了 OPenG!作为底层标准进 行封装。它的透视投影矩阵使用 OPe nG 啲环境但又进行了简化,值得一提。 本文努力让读者清楚地了解D3D 与 M3G 透视投影矩阵的原理,从而能够知道它与 OPenG 啲一些差别,为构建跨 API 的图形引擎打好基础。需要指出的一点是为 了完全理解本文的内容,请读者先理解上一篇文章 《深入探索透视投影变换》的 内容,因为OPenGL 和它们的透视投影矩阵的原理非常相似,因此这里不会像上 一篇文章从基础知识讲起,而是对比它们的差异来推导变换矩阵。我们开始! OPenGL ? D3D 的基本差异 前面提到,不同API 的基本差异导致了最终变换矩阵的不同,而导致 OPenGL 和 D3D 的透视投影矩阵不同的原因有以下几个: (1) OPe nGL 默认使用右手坐标系,而 D3D 默认使用左手坐标系 OPerLGL ri^iUxandeci CoOrdinate system DmD handed coordinate SyStem

推导相机变换矩阵

推导相机变换矩阵 -潘宏 -2009.12.31 -本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教 -email: popyy@https://www.360docs.net/doc/7d3550166.html, 一些网友写信给我希望能够了解固定流水线中世界空间到相机空间变换矩阵的具体推导过程。其实之前我在《向量几何在游戏编程中的使用6》中已经简单的把相机变换作为一个使用基理论的例子进行了说明,但可能仍然不够具体。这篇文章中,我会尽力阐述相机变换的整个来龙去脉。希望能够对正在学习固定流水线的朋友们有所帮助。这里我们仍然会在推导相机变换之前介绍几个理论知识,目的是为了更好的理解推导过程。我们马上开始! 什么是相机变换? 在流水线中,当物体从模型坐标通过世界矩阵变换到世界空间之后,它将通过相机变换从世界空间变换到相机空间。下图的固定流水线中,蓝色框中的部分就是这个过程。 其实,所谓的相机空间,就是以相机作为坐标原点的一个参考系,所以,从世界空间变换到相机空间,就是把物体从世界坐标系,变换到相机为原点的相机坐标系,如下图所示。

左半部分是小人在世界空间中的位置,右半部分是小人变换到相机空间后的位置。这样的一个变换可以有很多种方式来实现:欧拉相机系统、UVN系统、Two Points & A Twist等等。这里我们讨论最为广泛的UVN系统构建相机矩阵,如果读者对其他方法感兴趣,可以查找相关的资料。我们仍然讨论OpenGL的相机矩阵的推导,其他API可以类似的推导。 坐标转换公式 我们在《向量几何在游戏编程中的使用6》中提到了正交矩阵,这是在基理论基础上的一个概念(如果对基理论不是很熟悉,请参考《向量几何在游戏编程中的使用6》)。正交矩阵所有列(行)向量构成了一个标准正交基(它的列向量都是互相正交,并且长度为1),因此,可以把正交矩阵看成是对一个坐标系的描述。同时,我们知道:同一个向量,在不同的基下面的坐标是不同的。因此,可以用正交矩阵来代表坐标系(也可以看作基)从而写出在统一的参考系(全局坐标系)下同一个向量在不同基中的坐标。 上面的式子表示,参考系中向量v在基Q中的坐标是v’,在基R中的坐标是v’’(注意这里的环境下基矩阵是用列向量表示的,这样相乘之后的结果表示的是基向量的线性组合)。如下图,黑色基表示的是参考系,红色是基Q,蓝色是基R,v是参考系中的一个向量。

透视投影矩阵推导

在上一篇文章中我们讨论了透视投影变换的原理,分析了OpenGL所使用的透视投影矩阵的生成方法。正如我们所说,不同的图形API因为左右手坐标系、行向量列向量矩阵以及变换范围等等的不同导致了矩阵的差异,可以有几十个不同的透视投影矩阵,但它们的原理大同小异。这次我们准备讨论一下Direct3D(以下简称D3D)以及J2ME平台上的JSR184(M3G)(以下简称M3G)的透视投影矩阵,主要出于以下几个目的: (1) 我们在写图形引擎的时候需要采用不同的图形API实现,当前主要是OpenGL和D3D。虽然二者的推导极为相似,但D3D的自身特点导致了一些地方仍然需要澄清。 (2) DirectX SDK的手册中有关于透视投影矩阵的一些说明,但并不详细,甚至有一些错误,从而使初学者理解起来变得困难,而这正是本文写作的目的。 (3) M3G是J2ME平台上的3D开发包,采用了OpenGL作为底层标准进行封装。它的透视投影矩阵使用OpenGL的环境但又进行了简化,值得一提。 本文努力让读者清楚地了解D3D与M3G透视投影矩阵的原理,从而能够知道它与OpenGL的一些差别,为构建跨API的图形引擎打好基础。需要指出的一点是为了完全理解本文的内容,请读者先理解上一篇文章《深入探索透视投影变换》的内容,因为OpenGL和它们的透视投影矩阵的原理非常相似,因此这里不会像上一篇文章从基础知识讲起,而是对比它们的差异来推导变换矩阵。我们开始! OpenGL与D3D的基本差异 前面提到,不同API的基本差异导致了最终变换矩阵的不同,而导致OpenGL和D3D的透视投影矩阵不同的原因有以下几个: (1) OpenGL默认使用右手坐标系,而D3D 默认使用左手坐标系。

相关文档
最新文档