Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >透视投影的原理和实现

透视投影的原理和实现

作者头像
用户1148525
发布于 2019-06-11 03:22:30
发布于 2019-06-11 03:22:30
5.3K0
举报

透视投影的原理和实现

by Goncely

:透视投影是3D渲染的基本概念,也是3D程序设计的基础。掌握透视投影的原理对于深入理解其他3D渲染管线具有重要作用。本文详细介绍了透视投影的原理和算法实现,包括透视投影的标准模型、一般模型和屏幕坐标变换等,并通过VC实现了一个演示程序。

1 概述

在计算机三维图像中,投影可以看作是一种将三维坐标变换为二维坐标的方法,常用到的有正交投影和透视投影。正交投影多用于三维健模,透视投影则由于和人的视觉系统相似,多用于在二维平面中对三维世界的呈现。

透视投影(Perspective Projection)是为了获得接近真实三维物体的视觉效果而在二维的纸或者画布平面上绘图或者渲染的一种方法,也称为透视图[1] 。它具有消失感、距离感、相同大小的形体呈现出有规律的变化等一系列的透视特性,能逼真地反映形体的空间形象。透视投影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面。

2 透视投影的原理

基本的透视投影模型由视点E和视平面P两部分构成(要求E不在平面P上)。视点可以认为是观察者的位置,也是观察三维世界的角度。视平面就是渲染三维对象透视图的二维平面。如图1所示。对于世界中的任一点X,构造一条起点为E并经过X点的射线R,R与平面P的交点Xp即是X点的透视投影结果。三维世界的物体可以看作是由点集合 { Xi} 构成的,这样依次构造起点为E,并经过点Xi的射线Ri,这些射线与视平面P的交点集合便是三维世界在当前视点的透视图,如图2所示。

图1 透视投影的基本模型[2]

_

图2 透视图成像原理[6]

基本透视投影模型对视点E的位置和视平面P的大小都没有限制,只要视点不在视平面上即可。P无限大只适用于理论分析,实际情况总是限定P为一定大小的矩形平面,透视结果位于P之外的透视结果将被裁减。可以想象视平面为透明的玻璃窗,视点为玻璃窗前的观察者,观察者透过玻璃窗看到的外部世界,便等同于外部世界在玻璃窗上的透视投影(总感觉不是很恰当,但想不出更好的比喻了)。

当限定P的大小后,视点E的可视区间(或叫视景体)退化为一棱椎体,如图3所示。该棱椎体仍然是一个无限区域,其中视点E为棱椎体的顶点,视平面P为棱椎体的横截面。实际应用中,往往取位于两个横截面中间的棱台为可视区域(如图4所示),完全位于棱台之外的物体将被剔除,位于棱台边界的物体将被裁减。该棱台也被称为视椎体,它是计算机图形学中经常用到的一个投影模型。

图3 有限视平面的可视区间[3]

图4 透视投影的视椎体模型[3]

3 透视投影的标准模型

设视点E位于原点,视平面P垂直于Z轴,且四边分别平行于x轴和y轴,如图5所示,我们将该模型称为透视投影的标准模型,其中视椎体的近截面离视点的距离为n,远截面离视点的距离为f,且一般取近截面为视平面。下面推导透视投影标准模型的变换方程。

图5 透视投影的标准模型[4]

设位于视椎体内的任意一点X (x, y, z) 在视平面的透视投影为Xp (xp, yp, zp),从点X和Xp做z轴的垂线,并分别在X-Z平面和Y-Z平面投影,图6是在X-Z平面上的投影结果。

图6 透视投影的相似三角形[6]

根据三角形相似原理 , 可得 :

xp/n = x/z, yp/n = y/z

解上式得 :

xp = x*n/z, yp = y*n/z, zp = n.

上式便是透视投影的变换公式,非常简单,不是吗?需要说明的是,由于透视点始终位于视平面,所以zp恒等于n,实际计算的时候可以不考虑zp。另外还可以从照相机模型来考虑透视投影。将视点E想象为一个虚拟的照相机,视平面想象为胶片,那么图5 也是一个标准的照相机模型。

PS:上述讨论都是基于矩形视平面来考虑的,其实我们可以取视平面为任意形状,比如圆形,此时视景体变为一个圆锥体,当然现在好像还没有圆形的显示装置。另外,我还曾考虑将视平面取为凹面或凸面,此时的投影结果应该是哈哈镜效果吧(纯属想象,没有验证)。还可以想象将视平面放在E的另外一面,这时的投影图像是倒置的,但是不是更接近人的视觉成像模型?另外还可以考虑有两个甚至更多视点的透视投影,总之充分发挥你的相像,或许能得到意想不到的结果。

4 透视投影的一般模型

令世界坐标系的x轴指向屏幕的右方,y轴指向屏幕的上方,z轴指向屏幕外(右手坐标系)。我们在讨论标准模型的时候,曾假设E的坐标为原点,其实视点E除了有位置属性外,还有姿态属性,通常用[L U D]表示(D3D中用的是[R U D]表示),其中L表示视点的左向(Left),U表示上方(Up),D表示朝向(Direction)。在标准模型中,有L=[-1,0,0]T , U=[0,1,0]T , D=[0,0,-1]T 。

透视投影的一般模型研究视点E在任意位置,任意姿态下透视图的生成算法。思路很简单,先将一般模型变换为标准模型,然后使用标准模型的透视投影公式便能计算透视结果。下面研究一般模型变换为标准模型的数学公式。

设一般模型中的点X,其对应在标准模型中的点为Y,那么当视点位于E,姿态为R时,X和Y有如下关系:

X = E+RY

反过来有:

Y = R-1 (X-E)

通常取R为正交阵,即R-1 =RT ,故有

Y = RT (X-E)

把上式改写成齐次矩阵(Homogeneous matrix )的形式有:

式中Hview 便是透视投影从一般模型到标准模型的变换矩阵。

5 转换为屏幕坐标

对于透视投影的标准模型,视平面的坐标模型如图 7 所示,它的坐标原点位于视平面的中心, x 轴正向水平向右, y 轴正向垂直向上。要把透视投影的结果在计算机屏幕上显示的话,需要对透视图进行坐标变换,将其从视平面坐标系转换到屏幕坐标系。

图7 视平面坐标模型

计算机屏幕的坐标模型如图 8 所示,它的原点位于屏幕的坐上角, y 轴正向垂直向下。设视平面的宽度为 Wp ,高度为 Hp ;屏幕的宽度为 Ws ,高度为 Hs 。

图8 屏幕坐标模型[5]

令视平面坐标系中的点( xp, yp )对应于屏幕坐标系中的点( xs, ys ),它们的变换关系如下:

xs = a*xp + b;

ys = c*yp + d

由图 7 和图 8 可知,视平面中的( 0, 0 )点对应于屏幕坐标系中的中心点( 0.5*Ws-0.5, 0.5*Hs-0.5 )( PS :由于屏幕坐标系是离散坐标系,所有屏幕右下点的坐标为( Ws-1, Hs-1 ),而不是( Ws, Hs ));另外,视平面的( -0.5*Wp, -0.5*Hp )对应于屏幕的( 0, 0 )点。将上述两种取值代入变换方程可以得出:

上式便为视平面坐标系到屏幕坐标系的变换方程。

6 透视投影的实现

6.1 载入3D模型

使用Matt Fairfax实现的Model_3DS类支持3DS模型文件的载入,该类的实现非常简单,而且很容易使用,具体可参考[7]。由于本文的DEMO只需要其中的模型载入功能,所以对源代码进行了删减,去掉了纹理加载(暂不需要)和渲染(我们自己实现)代码,在析构函数中添加了资源释放代码。

6.2 视图变换

为表示透视投影的一般模型,实现了KCamera类,除保存视点的位置和姿态,还保存视图变换矩阵m_kmView,随着视点位置和姿态的变化,视图矩阵也不断更新,更新算法详见第4节。对于世界坐标系中的任何一点v(x, y, z),通过v = m_kmView*v将其变换到透视投影的标准模型坐标系,详见KCamera::Transform函数。

6.3 透视变换

KFrustum类用来对透视投影的标准模型进行建模,其成员包括视平面的尺寸大小,以及近截面和远截面的z轴坐标。KFrustum通过Project函数将视图变换的结果变换为透视坐标。算法的原理见第3节,代码实现如下:

void KFrustum::Project(KVector3& v)

{

// xp = x*n/z, yp = y*n/z, zp = n.

float fFactor = GetNear()/v.z;

v.x *= fFactor;

v.y *= fFactor;

v.z = GetNear();

}

6.4 屏幕变换

屏幕变换的算法通过宏实现,代码如下:

#define ToScreen(v, Ws, Hs) /

{/

float x = (v.x/GetWidth()+0.5f)*(Ws-1);/

float y = (v.y/GetHeight()+0.5f)*(Hs-1);/

v.x = KMath::Round(x);/

v.y = KMath::Round(y);/

}

6.5 渲染

Demo中的渲染使用软件实现,没有使用任何第三方图形库,主代码在KCamera::Render函数中,它接收两次参数:Model_3DS和KSurface,对Model_3DS中的顶点进行透视投影,然后将结果绘制到Ksurface中。函数代码如下:

bool KCamera::Render(Model_3DS& m3DS, KSurface& kSurface)

{

kSurface.Fill(RGB(0,0,0)); // 背景为黑色

COLORREF crPen = RGB(255,0,0); // 用红色绘制模型

KMatrix4 m = m_kmView;

int Ws = kSurface.GetWidth();

int Hs = kSurface.GetHeight();

for(int i=0; i<m3DS.numObjects; i++)

{

Model_3DS::Object& obj = m3DS.Objects[i];

for(int n=0; n<obj.numFaces; n+=3)

{

int index = obj.Faces[n]*3;

KVector4 v0(obj.Vertexes[index], obj.Vertexes[index+1], obj.Vertexes[index+2]);

index = obj.Faces[n+1]*3;

KVector4 v1(obj.Vertexes[index], obj.Vertexes[index+1], obj.Vertexes[index+2]);

index = obj.Faces[n+2]*3;

KVector4 v2(obj.Vertexes[index], obj.Vertexes[index+1], obj.Vertexes[index+2]);

Transform(v0, Ws, Hs);

Transform(v1, Ws, Hs);

Transform(v2, Ws, Hs);

// 绘制网线

kSurface.MoveTo(v0.x, v0.y);

kSurface.LineTo(v1.x, v1.y, crPen);

kSurface.LineTo(v2.x, v2.y, crPen);

kSurface.LineTo(v0.x, v0.y, crPen);

}

}

return true;

}

6.6 Demo和效果图

Demo程序使用VC6实现, 工程源代码 可以在我的下载空间下载。工程代码中包含一个国际象棋的3ds模型文件chess.3ds,该模型在Demo的渲染结果如图9所示。

图9 Demo程序渲染结果

7 小结

本文详细介绍了透视投影的基本理论,并通过程序对透视投影的相关算法进行了验证。但本文涉及的仅是透视投影的最基础方面,为了使文章简洁,还有很多知识没有讨论,包括视景体的规范化,视口(View port),以及更深入的深度信息、光栅化以及插值矫正等,代码实现中也没有考虑剔出和裁减,以后有机会将继续介绍相关内容。

8 参考文献

[1] http://zh.wikipedia.org/

[2] Donald Hearn, M. Pauline Baker, Computer Graphics C Version(2nd Edition), Prentice Hall, 1996

[3] Eric Lengyel, Mathematics for 3D Game Programming and Computer Graphics(2nd Edition), Charles River Media, Inc., 2004

[4] David H. Eberly, 3D Game Engine Design: A Practical Approach To Real-Time Computer Graphics, Morgan Kaufmann, 2000

[5] Andr é LaMothe, Tricks of the 3D Game Programming Gurus: Advanced 3D Graphics and Rasterization, Sams, 2003

[6] View Transformation . CSC 830 Note 3. Course note credit to Prof. Seth Teller, MIT.

[7] http://www.torquepowered.com/community/resources/view/506

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2011年03月28日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
透视投影矩阵推导[通俗易懂]
透视投影矩阵(Perspective Projection Matrix)的作用是进行规范化透视投影变换,即 观察空间 → \rightarrow →规范化观察空间。
全栈程序员站长
2022/11/09
1.7K0
透视投影矩阵推导[通俗易懂]
WebGL简易教程(五):图形变换(模型、视图、投影变换)
通过之前的教程,对WebGL中可编程渲染管线的流程有了一定的认识。但是只有前面的知识还不足以绘制真正的三维场景,可以发现之前我们绘制的点、三角形的坐标都是[-1,1]之间,Z值的坐标都是采用的默认0值,而一般的三维场景都是很复杂的三维坐标。为了在二维视图中绘制复杂的三维场景,需要进行相应的的图形变换;这一篇教程,就是详细讲解WebGL的图形变换的过程,这个过程同样也适合OpenGL/OpenGL ES,甚至其他3D图形接口。
charlee44
2019/10/08
3K0
WebGL简易教程(五):图形变换(模型、视图、投影变换)
[OpenGL]OpenGL坐标系及坐标转换
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ouyangshima/article/details/25135009
用户1148525
2019/06/11
4.4K0
附加实验2 OpenGL变换综合练习
理解掌握OpenGL程序的投影变换,能正确使用投影变换函数,实现正投影与透视投影。
步行者08
2018/10/09
1.5K0
伪 3D 中的贴图纹理的透视矫正
导语 伪 3D 效果一般是在二维平面上对贴图纹理进行拉伸变形制造出透视效果,从而模拟 3D 的视觉效果。但通过 OpenGL 直接渲染不规则四边形时,不进行透视纹理矫正,就会出现纹理缝隙裂痕等问题。本文将分析透视矫正原理并给出解决方案。 问题概述 一般要实现近大远小的透视景深效果,都是通过透视投影的方式在 OpenGL 渲染得到的。如果在 OpenGL 中不开启透视投影,使用简单四边形面片来达到 3D 效果则需要对四边形面片进行旋转或者进行拉伸变形。但不经过透视投影矩阵的计算,得到的纹理渲染结果就会有缝隙
天天P图攻城狮
2023/02/27
2.4K0
伪 3D 中的贴图纹理的透视矫正
【笔记】《计算机图形学》(7)——观察
这系列的笔记来自著名的图形学虎书《Fundamentals of Computer Graphics》,这里我为了保证与最新的技术接轨看的是英文第五版,而没有选择第二版的中文翻译版本。不过在记笔记时多少也会参考一下中文版本
ZifengHuang
2020/08/10
2.2K0
【笔记】《计算机图形学》(7)——观察
终端图像处理系列 - OpenGL ES 2.0 - 3D基础(矩阵投影)
Overview 移动设备的屏幕是二维平面,要想把一个三维场景渲染在手机二维屏幕上,需要利用OpenGL中的矩阵投射,将三维空间中的点映射到二维平面上。三维矩阵的相关知识是学习OpenGL最重要的课程之一。 线性代数 学习OpenGL三维投射知识之前,我们得事先了解下一些基础的线性代数知识,如向量运算,矩阵运算。 向量运算 向量: 指一个同时具有大小和方向的几何对象,因常常以箭头符号表示以区别于其它量而得名。 向量加减 向量的加(减)法定义是分量的相加(减),即将一个向量中的每一个分量加上(减去)另一个向量
天天P图攻城狮
2018/02/02
2.6K0
终端图像处理系列 - OpenGL ES 2.0 - 3D基础(矩阵投影)
OpenGL-投影和摄像机
本文介绍了从相机内外参数的标定、立体匹配、多视几何、投影映射、体渲染等多个方面,系统地讲解了移动设备GPU上基于光线的3D渲染从输入到输出的整个过程。同时,通过实例介绍了在移动端GPU上实现这些算法的具体实现方式和优化策略,包括Vulkan、Metal、OpenGL ES、WebGL等多种平台上的实现。本文旨在帮助读者了解3D渲染技术的基本原理,以及在移动端GPU上实现这些算法的具体实现方式和优化策略,包括Vulkan、Metal、OpenGL ES、WebGL等多种平台上的实现。
MelonTeam
2018/01/08
3.4K0
OpenGL-投影和摄像机
写给 python 程序员的 OpenGL 教程
OpenGL 是 Open Graphics Library 的简写,意为“开放式图形库”,是用于渲染 2D、3D 矢量图形的跨语言、跨平台的应用程序编程接口(API)。OpenGL 不是一个独立的平台,因此,它需要借助于一种编程语言才能被使用。C / C++ / python / java 都可以很好支持 OpengGL,我当然习惯性选择 python 语言。
全栈程序员站长
2022/07/22
3.4K0
写给 python 程序员的 OpenGL 教程
​OpenGL 学习系列---坐标系统
在前面绘制基本图形中,遇到了很明显的问题,圆形不像圆形,正多边形不像正多边形?就像下面图形一样:
音视频开发进阶
2019/07/25
1.4K0
OpenGL渲染流水线之世界矩阵,相机变换矩阵,透视投影变换矩阵
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29523119/article/details/78577246
用户1148525
2019/06/11
1.5K0
透视投影矩阵_透视投影矩阵推导知乎
首先,重要的是要记住OpenGL中的矩阵是使用列主顺序(而不是行主顺序)定义的。在所有的OpenGL书籍和参考文献中,OpenGL中使用的透视投影矩阵定义为:
全栈程序员站长
2022/11/09
1.3K0
透视投影矩阵_透视投影矩阵推导知乎
万字长文详解如何用Python玩转OpenGL | CSDN 博文精选
【编者按】OpenGL(开放式图形库),用于渲染 2D、3D 矢量图形的跨语言、跨平台的应用程序编程接口,C、C++、Python、Java等语言都能支持 OpenGL。本文作者以 Python 语法为例,用两万字详解 OpenGL 的理论知识、用法与实际操作,干货满满,一起来看看吧。
AI科技大本营
2019/12/02
9.8K0
万字长文详解如何用Python玩转OpenGL | CSDN 博文精选
透视投影变换矩阵推导_矩阵的投影
http://www.codeguru.com/cpp/misc/misc/math/article.php/c10123__1/Deriving-Projection-Matrices.htm,由于本人能力有限,有译的不明白的地方大家可以参考原文,谢谢^-^!
全栈程序员站长
2022/11/10
1.7K0
透视投影变换矩阵推导_矩阵的投影
iOS开发-OpenGL ES入门教程3
教程 OpenGL ES入门教程1-Tutorial01-GLKit OpenGL ES入门教程2-Tutorial02-shader入门 这次是三维图形变换。 OpenGL ES系列教程在这里。
落影
2018/04/27
2K0
iOS开发-OpenGL ES入门教程3
[译]OpenGL投影矩阵
电脑显示屏是一个2D平面,为了能够在这个2D平面上显示OpenGL渲染的3D场景,我们必须将3D场景当作2D图像投影到这个2D平面(计算机屏幕)上.GL_PROJECTION 矩阵就是用来做这种投影变换的.首先,该矩阵将所有观察空间的顶点坐标变换到裁剪空间,接着,将变换后的顶点坐标(即裁剪坐标)的每个分量(x,y,z,w)(x,y,z,w)(x,y,z,w)除以坐标的 www 分量,使其变换为标准化设备坐标(NDC).
用户2615200
2019/07/11
1.8K0
[译]OpenGL投影矩阵
opengl投影矩阵变换_opengl 坐标
A computer monitor is a 2D surface. A 3D scene rendered by OpenGL must be projected onto the computer screen as a 2D image. GL_PROJECTION matrix is used for this projection transformation. First, it transforms all vertex data from the eye coordinates to the clip coordinates. Then, these clip coordinates are also transformed to the normalized device coordinates (NDC) by dividing with w component of the clip coordinates.
全栈程序员站长
2022/11/04
1.9K0
opengl投影矩阵变换_opengl 坐标
基于正交投影的点云局部特征
由于点云具有无序,不规则,无拓扑结构的特点,因此可以利用多个二维图像通过三维到二维投影来表示三维点云的几何特征。用图像表示特征可以提供稳定的信息,多个投影角度可以弥补投影过程中造成的信息丢失投影,实现对空间信息的解码。充分利用三维空间信息取决于三维物理坐标系统的建立,但传感器的坐标系统没有抵抗旋转的能力。
小白学视觉
2020/12/07
6890
6.5编程实例-立方体透视投影
GLint winWidth = 600, winHeight = 600; //设置初始化窗口大小
步行者08
2018/10/09
9400
OpenGL ES 2.0 (iOS)[04]:坐标空间 与 OpenGL ES 2 3D空间
第一次变换 模型变换(Model Transforms):就是指从模型空间转换到世界空间的过程
半纸渊
2018/09/04
1.9K0
OpenGL ES 2.0 (iOS)[04]:坐标空间 与 OpenGL ES 2 3D空间
相关推荐
透视投影矩阵推导[通俗易懂]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档