深入研究透视投影变换
3D世界变换主要有世界变换、观察变化、投影变换。世界变换做的事情是把坐标从模型空间变换到世界空间,而观察变换是把坐标从世界空间变换到观察空间。3D世界里,所有的物体(包括相机等)都可以认为是3D模型,他们开始创建的时候都是处于自身坐标系内,渲染的时候,我们需要把这些模型从模型空间最终变换到统一的观察空间(相机自身空间)以方便进行裁剪等操作,最后,再经过透视投影变换将坐标变换到统一的立方体空间内。
在这三种变换中,投影变换最麻烦,越是麻烦的事情,越是需要整理一下思路,下面是我在做“将屏幕坐标转换为三维射线”算法研究中的一些想法,记录下来以供将来察看.
投影变换就做一件事:将锥形的观察空间转化为单位立方体空间。
上图是观察空间,其中近裁剪面可以认为是计算机内的一个3D图形显示窗口或者屏幕,经过观察变化后,只有处于此锥形空间内的物体才会最终显示在用户面前。
上图是观察空间的YZ图,我们据此推出坐标之间的关系:
y = ± z * tan(fov/2),x = y*Aspect
上图是投影空间的可见范围,这个空间处于你所见到的屏幕上。实际上将屏幕表面视作投影空间的xoy平面,再加一条垂直屏幕向里(或向外)的z轴(这取决于你的坐标系是左手系还是右手系),这样就构成了我们想要的坐标系。好了,现在我们可以用视口(view port)的大小来描述这个可视范围了。比如说全屏幕640*480的分辨率,原点在屏幕中心,那我们得到的可视区域为一个长方体,它如图(a)所示。
从图(a)变换到图(b)需要经过视口变换,目的是将屏幕坐标(0< SPAN>)变换到[-1,+1]的范围内。下面是将屏幕坐标变换到视口坐标的转换过程
接下来,我们处理视口空间到观察空间的转换。
由于在观察空间内,y = ± z * tan(fov/2),x = y*Aspect
而在投影空间内,x’和y’都属于[-1,+1],因此我们推出从观察空间到投影空间的变换公式,如下:
y’ = y * cot(fov/2) / z, x’ = x * cot(fov/2) /(z* aspect)
我们可以看到,从(x,y)变换到(x’,y’)是一次非线性变换,为了用矩阵来表达这个转换过程,我们就得用w这个分量了,为什么这么有用呢?我们可以想到,在世界变换和观察变换这两个过程内,我们对坐标的操作都是一些平移、旋转、缩放操作,仔细观察这些变换矩阵,我们可以发现这些矩阵的第四列元素均是(0 0 0 1),因此向量与矩阵相乘后,w分量并不会改变。换句话说,只要不是故意,一个w分量等于1的向量,再来到投影变换之前他的w分量仍旧等于1。好的,接下来我们让w’= w*z, 新的w’就记录下了view空间中的z值;同时在x,y分量上我们退而求其次,只要做到y’ = y * cot(fov/2), x’ = x * cot(fov/2) /aspect。那么,在做完线性变换之后,我们再用向量的y除以w,就得到了我们想要的最终的y值。
现在只剩下z分量了。我们所渴望的变换应将z = Znear 变换到z = 0,将z = Zfar变换到z = 1。这个很简单,但是等等,x, y最后还要除以w,你z怎能例外。既然也要除,那么z = Zfar 就不能映射到z = 1了。唔,先映射到z = Zfar试试。于是,有z’ = Zfar*(z-Znear)/(Zfar – Znear)。接下来,看看z’/z的性质。令f(z) = z’/z = Zfar*(z-Znear)/(z*(Zfar – Znear))。
则f’(z) = Zfar * Znear / ( z^2 * (Zfar –Znear )), 显而易见f’(z) > 0。所以除了z = 0是一个奇点,函数f(z)是一个单调增的函数。因此,当Znear≤z≤Zfar时,f(Znear)≤f(z)≤f(Zfar),
即0≤f(z)≤1。
至此,我们可以给出投影变换的表达式了:
x’ = x*cot(fov/2)/aspect
y’ = y*cot(fov/2)
z’ = z*Zfar / ( Zfar – Znear ) – Zfar*Znear / ( Zfar – Znear )
w’ = z
以矩阵表示,则得到变换矩阵如下,
cot(fov/2)/aspect 0 0 0
0 cot(fov/2) 0 0
0 0 Zfar/(Zfar-Znear) 1
0 0 -Zfar*Znear/(Zfar-Znear) 0
做完线性变换之后,再进行所谓的“归一化”,即用w分量去除结果向量。
为了验证这一研究结果,我们可以察看DX9文档,发现投影矩阵就是我们在上面推出的矩阵,因此,我们可以得出结论,经过D3D提供的投影函数,我们可以得到投影矩阵M,为了将观察空间内的坐标变换到投影空间,我们首先要将观察空间内的向量称上矩阵M以执行线性变换,然后再将得到的向量除以w分量,就可以得到最终的投影空间内的向量了。
为了简化上述步骤,Direct manager提供了一个函数TransformCoordinate函数,该函数内部直接将w分量“归一化”为1了。因此,我们只需将观察空间内的向量乘上此投影矩阵就可以得到投影空间内的向量了。
同理,如果我们想从二维的屏幕坐标转化到模型空间内的坐标,就需要执行上述过程的逆过程:视口变换-->投影逆变换-->观察逆变换-->世界逆变换。
分享到:
相关推荐
透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和透视除法两步完成的。
深入理解透视投影变换 讲得很清晰 很好的分析材料
实验内容 1.在世界坐标系中定义一个立方体(由6个面组成),并给定观察点在世界坐标系中的位置(a,b,c)以及观察坐标系的方位角θ,俯仰角φ...2.学习透视投影变换的基本原理。 利使用VC6++ MFC编程,实现透视投影算法。
1.在世界坐标系中定义一个立方体(由6个面组成),并给定观察点在世界坐标系中的位置(a,b,c)以及观察坐标系的方位角θ,俯仰角φ和姿态角α...2.学习透视投影变换的基本原理。 利使用VC6++ MFC编程,实现透视投影算法。
齐次坐标概念&&透视投影变换推导 透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视...
深入探讨透视投影坐标变换,directx坐标变换,游戏开发基础知识
3. 投影平面设为n=0,视点为(0,0,-d)(用户坐标系),编写程序实现物体的一点透视投影,并画出在uov面上的1点透视图。 4. 投影平面为与x轴、z轴有交,视点为(x,0,d)(用户坐标系) ,编写程序实现物体的二点透视投影,...
Opengles 入门教程中的第11章,讲解透视投影变换的示例代码
基于FPGA的透视投影变换算法的设计与实现.
二维图形的投影变换 编程实现多面体的投影变换并在屏幕上绘出得到的二维图形 掌握二维几何坐标变换,理解透视投影和平行投影的概念及程序实现
透视投影是一种中心投影法,在日常生活中,我们观察外界的景物时,常会看到一些明显的透视现象。
利用matlab实现图形变换,图像旋转,透视投影和平行投影
c语言,利用opengl中用自带函数实现平行,透视投影
球面透视投影模型校正鱼眼图像畸变
图形学实验-立方体线框模型透视投影图形学实验-立方体线框模型透视投影图形学实验-立方体线框模型透视投影
计算机图形学实验 立方体线框模型透视投影 的可执行文件,亲测可运行,若需报告可以联系我,期待和各位交流
透视投影例子程序
wpf图像四顶点透视变换,wpf图像四顶点透视变换,wpf图像四顶点透视变换
利用OpenGL中的多视区,分别在四个视区内显示空间四面体的主视图、俯视图、侧视图、透视投影图。
PointCloud透视投影,OpenGL实现读取点云数据并显示,透视投影。