一看就懂的OpenGL ES教程 您所在的位置:网站首页 ug100转2d图怎么转教程 一看就懂的OpenGL ES教程

一看就懂的OpenGL ES教程

2023-06-20 23:41| 来源: 网络整理| 查看: 265

我正在参加「掘金·启航计划」

通过阅读本文,你将获得以下收获: 1.正交投影变换数学推导原理 2.透视投影变换矩阵数学推导 3.视口变换

上篇回顾

上一篇一看就懂的OpenGL ES教程——走进3D的世界之坐标系统(上篇)已经讲解了关于坐标系统以及从局部坐标转换到观察坐标的过程,并且轻描淡写地介绍了投影的概念,今天就来从数学角度推导下投影矩阵,并且将讲下最终从投影后的坐标系转换到屏幕坐标,即视口变换的过程,最后就是实战环节,事不宜迟,赶忙上菜~

投影变换数学推导

在上一篇博文中,已经将坐标转换进行到了摄像机坐标系,如下图红色框所示:

image.png

此时摄像机已经在原点了,下一步要进行的就是投影变换,即Projection transformation。

上一篇博文已经祭出此图让大家对于投影有了基本的了解,但是要怎么得到投影变换矩阵呢?

image.png

推导出投影矩阵,这是3D渲染到2D最复杂的一个步骤,我们就从更简单的正交投影入手吧。

正交投影数学推导

现实世界中,我们理论上视野是无限远的(只要眼睛足够好~),但在计算机中,无限远的物体太小渲染起来意义不大,浮点数也无法表示无限大,无限靠近眼睛的物体只会把摄像机完全挡住,也没什么意义,所以一般我们假设在摄像机坐标空间中,存在某个空间区域为摄像机的整个可视空间,为了通用,我们用空间中任意一个长方体来表示:

image.png

这个长方体一般称为视景体,视景体由六个平面定义:左、右、下、上、近和远。每个平面由一个法向量和一个距离原点的距离定义。

具体每个面和原点的距离设为:

左裁切面:x=l,left 右裁切面:x=r,right 上裁切面:y=t,top 下裁切面:y=b,bottom 近裁切面:z=n,near 远裁切面:z=f,far

整个正交投影变换过程,本质就是保持可视空间中的每个点的相对位置不变,然后通过压缩成每个维度坐标从-1到1来达到转换成标准归一化空间(ndc坐标系空间,Normalized Device Coordinates)的目的。

大家可能会有疑问,正交投影物体的大小和远近无关,为什么还要保留深度z呢?这是因为正交投影虽然物体大小和深度无关,但是前后物体是有遮挡关系的,所以要保留z,到深度测试阶段,需要根据深度来决定片段的前后关系。

要完成这个变换过程,就需要2个步骤: 1. 平移视景体到坐标原点. 2. 将视景体缩放为x,y,z方向都在-1到1之间的正方体。

平移视景体到坐标原点,其实只要算出视景体的中心点位置即可,然后对中点三个坐标维度数值取反即为将其平移到原点的值,所以:

image.png

此时视景体已经成功到达坐标原点:

image.png

接下来,为了归一化,我们要将视景体缩放到x,y,z方向都在-1到1之间的正方体,其实就是将长方体的长宽高缩放为2,很容易得到以下缩放矩阵:

image.png

经过此矩阵变换,视景体已经成功缩放到x,y,z方向都在-1到1之间的正方体:

image.png

于是,正交变换矩阵就是2个矩阵相乘:

image.png

即:

image.png

f7b169129e95af2fd005ec7dc7579f54.jpeg

透视投影推导

对于透视投影,显然情况更加复杂了。我们的目标就是要算出平截头体(四棱锥)中的任意一点,投影到近平面之后的坐标是多少。

image.png

这里提供一种思路: 1. 先把平截头体“压”成一个长方体。 2. 对长方体中的点做正交投影变换。

步骤2我们在上面正交投影已经推导过了,现在重点就是步骤1了,即将左边的四棱锥压成右边的长方体。

image.png

说的倒是容易,关键怎么压,变换矩阵是什么?

078b48ad113d99326ba25663326cdb53.jpeg

齐次坐标前置知识

首先我们要再补一点齐次坐标相关的前置知识。

在一看就懂的OpenGL ES教程——仿抖音滤镜的奇技淫巧之变换滤镜(理论基础篇)就曾经提到过齐次坐标的概念,里面说到为了解决平移变换不能和缩放旋转变换合成一个变换矩阵的问题,从而增加了一个维度的齐次坐标。

而对于透视投影来说,齐次坐标又有另外一个作用。

如果一个点在无穷远处,这个点的坐标将会(∞,∞),在笛卡尔坐标系空间,这变得没有意义。平行线在透视空间的无穷远处交于一点,但是在笛卡尔坐标系空间却不能,数学家发现了一种方式来解决这个问题。

image.png

没错,解决方案正是齐次坐标。

我们可以在一个3D笛卡尔坐标末尾加上一个额外的变量w来形成3D齐次坐标,因此,一个点(X,Y,Z)在齐次坐标里面变成了(x,y,z,w),并且有

X = x/w

Y = y/w

Z = z/w

即把齐次坐标转化为笛卡尔坐标的方法是前面n-1个坐标分量分别除以最后一个分量即可,所以可以得到:

(x, y, z, 1)和(kx, ky, kz, k != 0)表示的是空间中同一个点,甚至,和(xz, yz, z2z^2z2, z != 0)也是同一个坐标点。

所以(1, 0, 0, 1)和(2, 0, 0, 2)都表示点(1, 0, 0)。

为什么齐次坐标可以处理透视效果呢?

因为投影矩阵将给定的平截头体范围映射到裁剪空间,除此之外还修改了每个顶点坐标的w值,从而使得离观察者越远的顶点坐标w分量越大。被变换到裁剪空间的坐标都会在-w到w的范围之间(任何大于这个范围的坐标都会被裁剪掉)。一旦坐标变换到裁剪空间内之后,透视除法就会被应用到裁剪空间坐标上:

out=(x/wy/wz/w)out = \begin{pmatrix} x /w \\ y / w \\ z / w \end{pmatrix}out=⎝⎛​x/wy/wz/w​⎠⎞​

所以当物体距离观察者越远时,w就越大,最后得到的坐标点的x,y,三3个维度就越小,当物体无限远的时候,w无限大,所以最后得到的坐标点的x,y,z三个维度就无限接近0。

a607033dcd6206bb5767f62bb06ad18a.jpeg

透视投影数学推导

假设 (x, y, z)为平截头体中的任意一点, (x’, y’, z’)为该点经过投影变换后得到的点坐标,n为近平面和观察点的距离,f为远平面和观察点的距离。

首先我们往平行x轴方向向y-z轴所在平面看过去,根据相似三角形定理可得: image.png

同样的可以得到:

image.png

将它们代入(x’, y’, z’)可得到投影变换如下:

image.png

根据齐次坐标的特性,我们对每个维度都乘上z,也是表示原来那个点:

image.png

所以我们可以得到,这个把四棱锥“压”成长方体的视景体的变换矩阵和以上点的关系如下:

image.png

由于x, y, z之间是无关的,所以可以得到变换矩阵必然是以下的形式:

image.png

所以现在剩下的任务就是求该矩阵的第三行向量。

102b0dbe8b3d04eb0e0944c0b309b9b0.jpeg

怎么求呢?我们再看看还有哪些可以利用的信息可以帮助我们解决。

首先,很明显的一点,近平面上任意点投影之后位置保持不变,所以将z=n代入以上矩阵可得:

image.png

假设矩阵的第三行向量为(0 0 A B),则可得:

image.png

因为n和x,y是无关的,所以可得以下关系:

image.png

一条式子还不足以解出A,B,所以还需要另外一条式子。

我们注意到,远平面的中心点在投影变换之后,它的x,y不变,所以也可以利用这个性质,将远平面中心点坐标都乘上f:

image.png

用上面的方式代入式子可得:

image.png

终于得到2条关于A,B的方程式子了!于是乎可以解出A,B的值:

image.png

终于得到了从平截头体的四棱锥变换到视景体的长方体了,那接下来就是做正交投影了,只要将上面得到的矩阵和前一章节得到的正交投影矩阵相乘即可得到透视投影矩阵:

image.png

1e249c65de6071fd7b2bfc39e0d45381.png

视口变换

经过投影变换,我们已经来到了标准设备归一化坐标系空间(ndc坐标系空间,normalized device coordi- nates): image.png

接下来,就是要转换为具体的屏幕坐标了,即视口变换(viewport transformation)。(注意这里的屏幕空间指不一定完全等同于整一个手机设备屏幕,可以通过代码指定它的大小,比如只是手机屏幕的一部分)

我们的设备屏幕可以看做一个坐标系,假设屏幕宽度为width个像素,高度为height个像素,那么屏幕坐标范围为从(0, 0) 到 (width, height),每个像素用一个1*1的方格表示,每个像素的坐标用像素左下角点的坐标表示,即像素点的坐标从(0, 0)到(width - 1, height - 1),所以像素点的中心坐标为(x + 0.5, y + 0.5)。

image.png

现在我们要做的,就是将坐标从右边的ndc坐标空间,变换到左边的屏幕设备坐标空间。

image.png

此时已经通过投影变换转换到2D空间了,所以要做的就是从[-1, 1]*[-1, 1] 变换到 [0, width] x [0, height]。

经过投影变换的洗礼,想必这个变换就容易很多了,大家应该都能想出来: 1. 将ndc坐标系空间移动到屏幕坐标系空间的中点。 2. 缩放ndc坐标系空间宽高和屏幕空间宽度一样大。

那么不难得到视口变换矩阵如下:

image.png

5bf39fd65fe2aa129d5c0880a6ebc8c8.jpeg

总结

用2篇文章终于将整个坐标系变换讲完,通过坐标系的转换(模型变换-》视图变换-》投影变换-》视口变换),大家可以一步步看到3D物体是怎么渲染到2D平面的。当然坐标系转换这个说法很多人刚接触可能有点懵逼,其实只要理解为本质是对3D物体进行各种变换,使得其可以在2D平面显示出来的一个过程即可。拆分步骤只是为了在理解和编程上更加方便有层次。

能坚持看完这两篇文章不容易,下一篇文章,将进行3D渲染的实战,将会有趣得多,大家可以拭目以待~

项目代码

opengl-es-study-demo 不断更新中,欢迎各位来star~

参考:

GAMES101-现代计算机图形学入门-闫令琪 变换 Fundamentals of Computer Graphics, Fourth Edition 计算机图形学系列笔记 坐标系统

原创不易,如果觉得本文对自己有帮助,别忘了随手点赞和关注,这也是我创作的最大动力~

系列文章目录

体系化学习系列博文,请看音视频系统学习总目录

实践项目: 介绍一个自己刚出炉的安卓音视频播放录制开源项目 欢迎各位来star~

相关专栏:

C/C++基础与进阶之路

音视频理论基础系列专栏

音视频开发实战系列专栏

一看就懂的OpenGL es教程



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有