`
chinamming
  • 浏览: 151217 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

透视投影详解

 
阅读更多

[概述]

投影变换完成的是如何将三维模型显示到二维视口上,这是一个三维到二维的过程。你可以将投影变换看作是调整照相机的焦距,它模拟了为照相机选择镜头的过程。投影变换是所有变换中最复杂的一个。

[视锥体]

视锥体是一个三维体,他的位置和摄像机相关,视锥体的形状决定了模型如何从camera space投影到屏幕上。最常见的投影类型-透视投影,使得离摄像机近的物体投影后较大,而离摄像机较远的物体投影后较小。透视投影使用棱锥作为视锥体,摄像机位于棱锥的椎顶。该棱锥被前后两个平面截断,形成一个棱台,叫做View Frustum,只有位于Frustum内部的模型才是可见的。

[透视投影的目的]

透视投影的目的就是将上面的棱台转换为一个立方体(cuboid),转换后,棱台的前剪裁平面的右上角点变为立方体的前平面的中心(下图中弧线所示)。由图可知,这个变换的过程是将棱台较小的部分放大,较大的部分缩小,以形成最终的立方体。这就是投影变换会产生近大远小的效果的原因。变换后的x坐标范围是[-1, 1],y坐标范围是[-1, 1],z坐标范围是[0, 1](OpenGL略有不同,z值范围是[-1, 1])。

[透视投影矩阵推导]

下面来推导一下透视投影矩阵,这样我们就可以自己设置投影矩阵了,就可以模拟神奇的D3DXMatrixPerspectiveLH函数的功能了。那么透视投影到底做了什么工作呢?这一部分算是个难点,无论是DX SDK的帮助文档,还是大多数图形学书籍,对此都是一带而过,很少有详细讨论的,早期的DX SDK文档还讨论的稍微多一些,而新近的文档则完全取消了投影矩阵的推导过程。

我们可以将整个投影过程分为两个部分,第一部分是从Frustum内一点投影到近剪裁平面的过程,第二部分是由近剪裁平面缩放的过程。假设Frustum内一点P(x,y,z)在近剪裁平面上的投影是P'(x',y',z'),而P'经过缩放后的最终坐标设为P''(x",y",z")。假设所求的投影矩阵为M,那么根据矩阵乘法可知,如下等式成立。

PM=P'',即

先看第一部分,为了简化问题,我们考虑YOZ平面上的投影情况,见下图。设P(x, y, z)是Frustum内一点,它在近剪裁平面上的投影是P'(x', y', z')。(注意:D3D以近剪裁平面作为投影平面),设视锥体在Y方向的夹角为Θ。

由上图可知,三角形OP'Q'与三角形OPQ相似,于是有如下等式成立。

在看第二部分,将P'缩放的过程,假设投影平面的高度为H,由于转换后cuboid的高度为2。所以有

又因为投影平面的纵横比为Aspect,所以

最后看z'',当Frustum内的点投影到近剪裁平面的时候,实际上这个z'值已经没有意义了,因为所有位于近剪裁平面上的点,其z'值都是n,看起来我们甚至可以抛弃这个z'值,可以么?当然不行!别忘了后面还有深度测试呢。由第一幅图可知,所有位于线段p'p上的点,最终都会投影到p'点,那么如果这条线段上真的有多个点,如何确定最终保留哪一个呢?当然是离观察这最近的这个了,也就是深度值(z值)最小的。所以z'坐标可以直接保存p点的z值。因为在光栅化之前,我们需要对z坐标的倒数进行插值(原因请参见Mathematics for 3D Game Programming and Computer Grahpics 3rd section 5.4),所以可以将z''写成z的一次表达式形式,如下

在映射前,z的范围是[n,f],这里n和f分别是近远两个剪裁平面到原点的距离,在映射后,z''的范围是[0,1],将数据代入上面的一次式,可得下面的方程组

解这个方程组得到

所以

整理一下得

将X'',y'',z''代入最开始的矩阵乘法等式中得

由上式可见,x'',y'',z''都除以了Pz,于是我们将他们再乘以Pz(这并不该变齐次坐标的大小),得到如下等式。

注意这里,x即Px,y即Py,z即Pz,解矩阵的每一列得到

于是所求矩阵为

代码

一般来说,在程序中我们通常给定四个参数来求透视投影矩阵,分别是y方向的视角,纵横比,近剪裁平面到原点的距离及远剪裁平面到原点的距离,通过这四个参数即可求出上面的矩阵,代码如下。

D3DXMATRIX BuildProjectionMatrix(float fov, float aspect, float zn, float zf)
{
    D3DXMATRIX proj;
    ZeroMemory(&proj, sizeof(proj));

    proj.m[0][0] = 1 / (tan(fov * 0.5f) *aspect) ;
    proj.m[1][1] = 1 / tan(fov * 0.5f) ;
    proj.m[2][2] = zf / (zf - zn) ;
    proj.m[2][3] = 1.0f; 
    proj.m[3][2] = (zn * zf) / (zn - zf);

    return proj ;
}

矩阵求解完毕,现在可以用如下代码试试效果,这和使用D3D函数D3DXMatrixPerspectiveFovLH所得效果是一致的。

D3DXMATRIX proj = BuildProjectionMatrix(D3DX_PI / 4, 1.0f, 1.0f, 1000);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ;

Happy Coding!!!

投影变换完成的是如何将三维模型显示到二维视口上,这是一个三维到二维的过程。你可以将投影变换看作是调整照相机的焦距,它模拟了为照相机选择镜头的过程。投影变换是所有变换中最复杂的一个。

[视锥体]

视锥体是一个三维体,他的位置和摄像机相关,视锥体的形状决定了模型如何从camera space投影到屏幕上。最常见的投影类型-透视投影,使得离摄像机近的物体投影后较大,而离摄像机较远的物体投影后较小。透视投影使用棱锥作为视锥体,摄像机位于棱锥的椎顶。该棱锥被前后两个平面截断,形成一个棱台,叫做View Frustum,只有位于Frustum内部的模型才是可见的。

[透视投影的目的]

透视投影的目的就是将上面的棱台转换为一个立方体(cuboid),转换后,棱台的前剪裁平面的右上角点变为立方体的前平面的中心(下图中弧线所示)。由图可知,这个变换的过程是将棱台较小的部分放大,较大的部分缩小,以形成最终的立方体。这就是投影变换会产生近大远小的效果的原因。变换后的x坐标范围是[-1, 1],y坐标范围是[-1, 1],z坐标范围是[0, 1](OpenGL略有不同,z值范围是[-1, 1])。

[透视投影矩阵推导]

下面来推导一下透视投影矩阵,这样我们就可以自己设置投影矩阵了,就可以模拟神奇的D3DXMatrixPerspectiveLH函数的功能了。那么透视投影到底做了什么工作呢?这一部分算是个难点,无论是DX SDK的帮助文档,还是大多数图形学书籍,对此都是一带而过,很少有详细讨论的,早期的DX SDK文档还讨论的稍微多一些,而新近的文档则完全取消了投影矩阵的推导过程。

我们可以将整个投影过程分为两个部分,第一部分是从Frustum内一点投影到近剪裁平面的过程,第二部分是由近剪裁平面缩放的过程。假设Frustum内一点P(x,y,z)在近剪裁平面上的投影是P'(x',y',z'),而P'经过缩放后的最终坐标设为P''(x",y",z")。假设所求的投影矩阵为M,那么根据矩阵乘法可知,如下等式成立。

PM=P'',即

先看第一部分,为了简化问题,我们考虑YOZ平面上的投影情况,见下图。设P(x, y, z)是Frustum内一点,它在近剪裁平面上的投影是P'(x', y', z')。(注意:D3D以近剪裁平面作为投影平面),设视锥体在Y方向的夹角为Θ。

由上图可知,三角形OP'Q'与三角形OPQ相似,于是有如下等式成立。

在看第二部分,将P'缩放的过程,假设投影平面的高度为H,由于转换后cuboid的高度为2。所以有

又因为投影平面的纵横比为Aspect,所以

最后看z'',当Frustum内的点投影到近剪裁平面的时候,实际上这个z'值已经没有意义了,因为所有位于近剪裁平面上的点,其z'值都是n,看起来我们甚至可以抛弃这个z'值,可以么?当然不行!别忘了后面还有深度测试呢。由第一幅图可知,所有位于线段p'p上的点,最终都会投影到p'点,那么如果这条线段上真的有多个点,如何确定最终保留哪一个呢?当然是离观察这最近的这个了,也就是深度值(z值)最小的。所以z'坐标可以直接保存p点的z值。因为在光栅化之前,我们需要对z坐标的倒数进行插值(原因请参见Mathematics for 3D Game Programming and Computer Grahpics 3rd section 5.4),所以可以将z''写成z的一次表达式形式,如下

在映射前,z的范围是[n,f],这里n和f分别是近远两个剪裁平面到原点的距离,在映射后,z''的范围是[0,1],将数据代入上面的一次式,可得下面的方程组

解这个方程组得到

所以

整理一下得

将X'',y'',z''代入最开始的矩阵乘法等式中得

由上式可见,x'',y'',z''都除以了Pz,于是我们将他们再乘以Pz(这并不该变齐次坐标的大小),得到如下等式。

注意这里,x即Px,y即Py,z即Pz,解矩阵的每一列得到

于是所求矩阵为

代码

一般来说,在程序中我们通常给定四个参数来求透视投影矩阵,分别是y方向的视角,纵横比,近剪裁平面到原点的距离及远剪裁平面到原点的距离,通过这四个参数即可求出上面的矩阵,代码如下。

D3DXMATRIX BuildProjectionMatrix(float fov, float aspect, float zn, float zf)
{
    D3DXMATRIX proj;
    ZeroMemory(&proj, sizeof(proj));

    proj.m[0][0] = 1 / (tan(fov * 0.5f) *aspect) ;
    proj.m[1][1] = 1 / tan(fov * 0.5f) ;
    proj.m[2][2] = zf / (zf - zn) ;
    proj.m[2][3] = 1.0f; 
    proj.m[3][2] = (zn * zf) / (zn - zf);

    return proj ;
}

矩阵求解完毕,现在可以用如下代码试试效果,这和使用D3D函数D3DXMatrixPerspectiveFovLH所得效果是一致的。

D3DXMATRIX proj = BuildProjectionMatrix(D3DX_PI / 4, 1.0f, 1.0f, 1000);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ;

Happy Coding!!!

分享到:
评论

相关推荐

    深入理解透视投影变换

    #### 三、透视投影变换详解 透视投影变换的核心步骤包括: 1. **构建透视投影矩阵**: - 透视投影矩阵是一个4×4的矩阵,它根据视锥体的参数(如视野角度、近截面距离、远截面距离等)来构造。 - OpenGL中的`...

    OpenGL透视变换详解

    除了`gluPerspective`,OpenGL还提供了一个叫做`glFrustum`的透视投影函数,它允许更灵活的控制近裁剪面和远裁剪面的形状。`glFrustum`接受六个参数,定义了近裁剪面的左下角和右上角坐标,以及近裁剪面和远裁剪面的...

    OpenGL 学习.doc

    ### OpenGL中的视图变换与透视投影详解 #### 视图变换:`gluLookAt`函数解析 在OpenGL中,`gluLookAt`函数是一个关键的工具,用于定义观察者(即“摄像头”)的位置、方向以及面向的点,从而创建一个观察矩阵。这...

    《地球投影知识详解》

    1. **透视投影**:这种方法较为直观,通过假设地球被缩小成一个类似于地球仪的球体,并在其内部设置光源,将地球表面的信息投影到球体外部的平面上。这种方法虽然直观易懂,但对于整个地球而言并不实用。 2. **广义...

    详解OpenGL的坐标系、投影和几何变换

    透视投影则模拟真实世界的视觉效果,物体离观察者越远,看起来越小,使用`gluPerspective`函数设置。`glOrtho`的参数定义了一个可见立方体的边界,而`gluPerspective`的参数定义了一个四棱台形的可视区域。 3. 几何...

    建筑识图与制图详解第一章投影的概念.ppt

    《建筑识图与制图详解》第一章主要讲解了投影的概念及其在工程图示中的应用。投影是光线照射物体,物体的影子投射在遮挡面上形成的一种视觉表现形式。根据光源的不同,投影可分为两类:中心投影和平行投影。 中心...

    投影变换 推导过程详解 1

    在推导过程中,我们寻找了一个特殊的投影变换矩阵F,它是由旋转矩阵Rθ、Rφ、平移矩阵T以及透视矩阵P组合而成的。这个变换矩阵能够将图像的顶点从一个坐标系变换到另一个坐标系。 3. 旋转矩阵: 文档中提到了两个...

    3d照相机成像原理视景体详解

    2. 透视投影:与正交投影不同,透视投影考虑了距离因素,使得远离观察者的事物看起来更小,这符合我们日常的视觉体验。在计算机图形学中,透视投影通常使用弗兰斯透镜(Frustum)来表示,它模拟了真实世界的深度感知...

    透视投影下基于轨迹基的非刚体三维结构恢复研究 (2014年)

    这种方法通过结合因式分解法和线性迭代方法,在轨迹空间中进行操作,并利用弱透视投影与真实透视投影之间的近似关系,通过对矩阵进行加权并使用迭代算法来计算深度信息,最终用弱透视投影模型下的结果近似地得到真实...

    《阴影透视》期末考试复习题及参考答案.pdf

    1. **阴影透视基础**:阴影透视是一种表现物体三维形状和空间关系的绘画技法,它结合了投影理论,特别是在建筑和工程领域,用于绘制和理解三维物体的二维表示。 2. **三视图原理**:题目中提到的H面、V面和W面分别...

    地理坐标系与投影坐标系

    - **几何法**:利用平面、圆柱面或圆锥面作为承影面,通过直观的透视投影方法将地球表面的点和线转换到平面上。 - **解析法**:确定球面上的地理坐标与平面上对应点的直角坐标之间的函数关系。 #### 四、投影类型 ...

    Vulkan开发实战详解源码

    6. **Projection Transformation** (04_ProjectionTransformation):投影变换是将3D世界空间转换为2D屏幕空间的关键步骤,包括透视投影和平行投影。在Vulkan中,开发者需要手动处理这些变换,以实现所需的视角效果。...

    图形学三维视图

    ### 图形学三维视图知识点详解 ...此外,还详细探讨了平行投影和透视投影的基本原理及其在实际应用中的具体实现方法。这些知识点不仅对学习图形学至关重要,也是理解和掌握计算机图形学中高级概念的基础。

    一种基于matlab的摄象机标定方法的实现

    3. **计算透视投影矩阵**:根据标定点的世界坐标和图像坐标,使用最小二乘法计算透视投影矩阵。 4. **内部参数优化**:利用非线性优化算法调整内部参数,使预测的图像坐标尽可能接近实际坐标。 5. **外部参数计算**...

    1建筑识图与构造(投影的知识).pptx

    【建筑识图与构造——投影知识详解】 投影是建筑领域中理解图纸和设计的重要工具,它将三维物体在二维平面上的表现形式。本篇主要介绍了投影的基本知识、分类以及在土建工程中常用的各种投影图。 一、投影的形成与...

    assignment & experiment2-2020-fall何宇航1

    无论长方体木箱如何放置,采用三点透视投影总能看到至少7个角点,这是透视投影的基本性质。透视投影根据视点位置和投影面的关系,可以分为一点、两点和三点透视。 6. 透视投影类型的判断 透视投影的类型可以根据...

    摄像机标定详解版

    透视投影是一种中心投影法,它通过一系列最终汇聚到一点(称为投影中心)的投影线,将三维世界中的点投影到二维图像平面上。在摄像机模型中,三维空间点Pw通过投影π映射到二维图像坐标p,这个过程可以表示为P=π(Pw...

    基于鱼眼矫正的原理

    球面透视投影约束指的是,空间中的直线经过透视投影后,在球面上表现为一个大圆。这一约束条件为鱼眼图像校正提供了理论基础。 #### 校正方法详解 本节将详细介绍基于球面透视投影约束的鱼眼镜头校正方法的具体...

    PS怎样制作人像投影.pdf

    【PS制作人像投影详解】 在Photoshop(PS)中制作人像投影是提升图像立体感和真实感的重要技巧。投影通常与倒影一起出现,它们都是光影在游戏中创造视觉效果的关键元素。以下将详细介绍如何使用PS制作人像投影: 1...

    化工制图的投影基础知识.pptx

    ### 化工制图中的投影基础知识详解 #### 一、投影方法概述 在化工制图领域,为了准确地表达和理解三维物体的空间形态,通常会采用不同的投影方法来进行图形的绘制。这些投影方法主要包括中心投影法、平行投影法...

Global site tag (gtag.js) - Google Analytics