我正在参加「启航方案」
通过阅览本文,你将获得以下收成:
1.矩阵改换拓宽到3D相关常识
2.OpenGL的坐标体系
3.OpenGL坐标体系之间的转化
4.了解投影改换
上篇回顾
上篇一看就懂的OpenGL ES教程——仿抖音滤镜的奇技淫巧之高斯含糊滤镜 底子现已将如何用OpenGL es完结滤镜作用讲得差不多了,底子原理懂了,要完结更复杂的滤镜作用都是针对具体算法的处理上了,所以滤镜打怪升级系列也算是圆满落幕。从今日开始,将进入到一个十分令人兴奋的范畴,即3D范畴。
(本来是想写一篇更炫酷作用的仿抖音滤镜的博文,无法滤镜相关的博文耗时现已远超过我的方案,所以只能先安排十分重要有趣的3D烘托了,更炫酷作用的仿抖音滤镜的博文后边有时间也会补上。)
假如你现已能运用OpenGL完结一些视频滤镜作用了,并因此自鸣得意,那我可能要泼冷水了,由于关于OpenGL,你可能还没真实入门。
今日咱们必须从头审视OpenGL了,OpenGL终究是什么
(发出带有哲学滋味的思考)。
在该系列的第一篇博文一看就懂的OpenGL ES教程——图形烘托管线的那些事中曾说到:
OpenGL便是一个建立在图形硬件(一般便是gpu)之上的软件编程接口,这些接口有一套官方拟定的规范,具体完结由制造商(一般是显卡制造商)去完结,而编程者通过这些软件编程接口,就能够在计算机中绘制出2D以及3D的图形。
在之前的章节中,为了方便初学者入门,其实一直都是以2D的维度去了解OpenGL的(有心的读者应该有注意到之前传入的极点坐标的z重量都是0),但这样其实仅仅管中窥豹,这姿态是无法真实了解OpenGL的烘托流程的,只有在3D的维度,才干真实了解OpenGL,也才干充沛真实发挥OpenGL的作用
。(假如仅仅用OpenGL烘托2D图形,那就有种杀鸡用牛刀的滋味了)
所以今日的主题,便是研讨OpenGL是如何将一个3D的物体烘托成为2D屏幕上的图画的
。
前置常识——矩阵改换拓宽到3D
首要必备的前置理论常识依然是一看就懂的OpenGL ES教程——仿抖音滤镜的奇技淫巧之改换滤镜(理论根底篇) 所说到的改换矩阵,能够说这是贯穿全文的一大中心
,之前博文现已比较具体推导了平移、缩放、旋转矩阵的推导,那么现在将改换拓宽到3D,推导进程也是类似的,这儿就不赘述,我们能够依据一看就懂的OpenGL ES教程——仿抖音滤镜的奇技淫巧之改换滤镜(理论根底篇) 中的推导自行推导。
之前推导出2D空间中的点平移改换矩阵(包括齐次坐标)为:
表明一个将2D空间中的某个点(x,y)在x轴y轴方向上别离平移xt,ytx_t,y_t的矩阵。那么扩展到3D,很简单得到以下平移改换矩阵:
[100Tx010Ty001Tz0001]⋅(xyz1)=(x+Txy+Tyz+Tz1)\begin{bmatrix} \color{red}1 & \color{red}0 & \color{red}0 & \color{red}{T_x} \\ \color{green}0 & \color{green}1 & \color{green}0 & \color{green}{T_y} \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blue}{T_z} \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x + \color{red}{T_x} \\ y + \color{green}{T_y} \\ z + \color{blue}{T_z} \\ 1 \end{pmatrix}
表明一个将3D空间中的某个点(x,y,z)在x轴y轴z轴方向上别离平移$T_x,T_y,T_z$个单位的改换矩阵
。
关于缩放矩阵来说:
相同的,扩展到3D,很简单得到以下缩放改换矩阵:
[S10000S20000S300001]⋅(xyz1)=(S1⋅xS2⋅yS3⋅z1)\begin{bmatrix} \color{red}{S_1} & \color{red}0 & \color{red}0 & \color{red}0 \\ \color{green}0 & \color{green}{S_2} & \color{green}0 & \color{green}0 \\ \color{blue}0 & \color{blue}0 & \color{blue}{S_3} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{S_1} \cdot x \\ \color{green}{S_2} \cdot y \\ \color{blue}{S_3} \cdot z \\ 1 \end{pmatrix}
表明一个将3D空间中的某个点(x,y,z)在x轴、y轴、z轴方向上别离缩放S1,S2,S3S_1,S_2,S_3倍的改换矩阵。
旋转改换之前推出来的2D旋转改换矩阵是:
表明将2D空间中的某个点(x,y)在以原点为旋转轴逆时针旋转\alpha的改换矩阵。
那么扩展到3D空间就比较复杂了,由于不同的旋转轴是有所不同的(上面说的2D旋转改换,其实便是以z轴为旋转轴的旋转)。扩展到3D空间,比方下图为以x轴为旋转轴的情形:
以下是别离以x轴、y轴、z轴为旋转轴得到的旋转改换矩阵:
沿x轴旋转:
[10000cos−sin00sincos00001]⋅(xyz1)=(xcos⋅y−sin⋅zsin⋅y+cos⋅z1)\begin{bmatrix} \color{red}1 & \color{red}0 & \color{red}0 & \color{red}0 \\ \color{green}0 & \color{green}{\cos \theta} & – \color{green}{\sin \theta} & \color{green}0 \\ \color{blue}0 & \color{blue}{\sin \theta} & \color{blue}{\cos \theta} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x \\ \color{green}{\cos \theta} \cdot y – \color{green}{\sin \theta} \cdot z \\ \color{blue}{\sin \theta} \cdot y + \color{blue}{\cos \theta} \cdot z \\ 1 \end{pmatrix}
沿y轴旋转:
[cos0sin00100−sin0cos00001]⋅(xyz1)=(cos⋅x+sin⋅zy−sin⋅x+cos⋅z1)\begin{bmatrix} \color{red}{\cos \theta} & \color{red}0 & \color{red}{\sin \theta} & \color{red}0 \\ \color{green}0 & \color{green}1 & \color{green}0 & \color{green}0 \\ – \color{blue}{\sin \theta} & \color{blue}0 & \color{blue}{\cos \theta} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{\cos \theta} \cdot x + \color{red}{\sin \theta} \cdot z \\ y \\ – \color{blue}{\sin \theta} \cdot x + \color{blue}{\cos \theta} \cdot z \\ 1 \end{pmatrix}
沿z轴旋转:
[cos−sin00sincos0000100001]⋅(xyz1)=(cos⋅x−sin⋅ysin⋅x+cos⋅yz1)\begin{bmatrix} \color{red}{\cos \theta} & – \color{red}{\sin \theta} & \color{red}0 & \color{red}0 \\ \color{green}{\sin \theta} & \color{green}{\cos \theta} & \color{green}0 & \color{green}0 \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{\cos \theta} \cdot x – \color{red}{\sin \theta} \cdot y \\ \color{green}{\sin \theta} \cdot x + \color{green}{\cos \theta} \cdot y \\ z \\ 1 \end{pmatrix}
从3D到屏幕2D显现
前置常识讲完,接着便是进入主题的时分了。如何将3D的物体到烘托到2D屏幕显现呢?这儿有一个我们了解的十分相似的情形——摄影。
实际国际的物体是3维的,终究会被显现在2维的相片中。
照相机工作的底子原理是利用光学成像和感光材料的特性来记录图画。当按下快门时,镜头中的光线被聚焦到感光材料上,构成了一个倒竖的实时图画。
这是利用小孔成像的原理:物体通过暗箱的小孔后会在投影平面
上构成倒像。
所以OpenGL之所以能将3D物体烘托在2D的屏幕上,最底子的原理也是投影
。那终究什么是投影呢,在了解投影之前,先要讲一个东西——坐标体系
。
坐标体系
首要要知道的是,依照惯例,OpenGL是一个右手坐标系。简略来说,便是正x轴在你的右手边,正y轴朝上,而正z轴是朝向后方的。想象你的屏幕处于三个轴的中心,则正z轴穿过你的屏幕朝向你。坐标系画起来如下:
要将3D物体烘托在2D的屏幕上,这个进程的实质,其实便是将3D物体在实际国际中的坐标转化为屏幕设备坐标
的一个进程,这个进程一般比较复杂,所以一般是通过分步拆为几个转化进程,这样会简单了解,而且也方便编码。
所以物体的极点在终究转化为屏幕坐标之前还会被改换到多个坐标体系
,将物体的坐标改换到几个过渡坐标系(Intermediate Coordinate System)的长处在于,在这些特定的坐标体系中,一些操作或运算愈加方便和简单,比方能够针对某个改换独自处理,层次就愈加明晰了。
首要每一个3D物体一般是作为一个独立的模型被烘托的,所以每个物体一开始有自己的坐标系,这个坐标系就叫做部分坐标系,也叫做物体坐标系
,比方上图,处在c位的你其实一开始就有归于自己的坐标系:
(坐标系画得很绰,各位请见谅)
但是其实摄影的时分你并不是仅有,此刻需求一个更大的坐标系来表明每个人的方位(否则每个人的坐标方位就重叠了):
该坐标一般叫做国际坐标,是一个大局坐标
。表明当前要烘托的场景需求的最大的坐标系
。
咱们的目标是要将你和你的朋友投影到摄像机,所以重视的是你和你朋友和摄像机的相对方位,所以不如把原点搬到摄像机,以摄像机为为中心动身,即以摄像机为原点建立一个坐标系
:
此刻得到的坐标系一般叫做调查坐标
,即以调查者(摄像机)为中心的坐标系。
此刻就需求将物体投影
到摄像机的感光材料上了,而且由于摄像机拍摄到的物体规模是有限的,所以每个极点的x,y,z坐标都应该在-1.0到1.0
之间,超出这个坐标规模的极点都将不可见
,所以此刻能够进入摄像机画面的可能是这样的:
(左下角绿色小企鹅:???)
现在所在的坐标系一般叫做裁剪坐标系
,注意此刻通过投影之后,现已转为2D空间
,不过当前坐标仍是归一化
的。
最后由于图画终究是要显现在相片(屏幕)中的,所以一定有具体的像素表明,由于上面几个坐标系都仍是归一化的坐标系
,所以最后还需求转化为具体相片(屏幕)的坐标系(比方1080*720的屏幕)才干显现出来:
通过这一系列的坐标转化,终究改换到屏幕坐标系
上了,3D物体现已成功烘托到2D屏幕上了!
咱们再从OpenGL视点来总结下上面的改换进程:
- 部分坐标是目标相关于部分原点的坐标,也是物体起始的坐标。
- 下一步是将部分坐标改换为国际空间坐标,国际空间坐标是处于一个更大的空间规模的。这些坐标相关于国际的大局原点,它们会和其它物体一同相关于国际的原点进行摆放。
- 接下来咱们将国际坐标改换为调查空间坐标,使得每个坐标都是从摄像机或者说调查者的视点进行调查的。
- 坐标到达调查空间之后,咱们需求将其投影到裁剪坐标。裁剪坐标会被处理至-1.0到1.0的规模内,并判断哪些极点将会出现在屏幕上。
- 最后,咱们将裁剪坐标改换为屏幕坐标,最后改换出来的坐标将会送到光栅器,将其转化为片段。
以上进程皆发生在极点着色器阶段,即传给图元安装的极点方位,现已从3D转变为2D
。
那么从一个坐标系转化到另一个坐标系是则怎样完结的呢?从上图能够看出,用的正是之前经常提及的工具——矩阵
。
坐标系之间的转化
从部分坐标系转化到国际坐标系改换
一般来说,从部分坐标转化到国际坐标的进程称为模型改换
,比方你本来在自己的坐标里边坐标原点在你的右脚底部处,当你和你的朋友们一同摄影的时分,坐标原点大概率不在你的右脚底部处,此刻假如坐标原点放在最左面的朋友的右脚底部处,而你间隔最左面的朋友的右脚底部处有a个单位,则相当于要将你平移a个单位,这儿的平移a个单位即是一次模型改换
。当然模型变化不止是平移,能够缩放或者旋转,依据具体情况而定
,总归便是将物体放在国际坐标而需求的一次改换。而模型改换所需求的改换矩阵,就叫做模型矩阵(model matrix)
。
从国际坐标系转化到调查坐标系改换
从国际坐标系转化到调查坐标系改换的矩阵称为调查矩阵(View Matrix),通过转化为调查坐标系,能够找到一种从摄像机看过去的感觉,也能够很方便地实际物体在摄像机前方做相对运动的作用
。当然要明确一点的是,OpenGL自身没有摄像机(Camera)的概念,但咱们能够通过把场景中的一切物体往相反方向移动的方法来模拟出摄像机,产生一种咱们在移动的感觉,而不是场景在移动。
怎样改换到调查坐标系呢?
首要要知道摄像机是什么姿态的:
上图为一个摄像机,摄像机的方位在(0,0,2)点,它正往(0,0,0)点看去。
要把坐标系从国际坐标转化到摄像机的坐标系,首要要做什么呢?那当然是在摄像机上建立一个坐标系
。则怎样建立呢?
由于OpenGL是右手坐标系,所以摄像机一般都是往-z轴看过去的,所以能够以摄像机看过去的方向作为-z轴,即:
摄像机背后的蓝色轴即为摄像机坐标系的z轴方向
,即为摄像机看过去的点为起点,摄像机的方位点为结尾的向量
,也称为摄像机的方向向量
(这名称简单引起误解,其实和摄像机看过去的方向是相反的),它就能够作为摄像机z轴
。
然后便是要找到摄像机坐标系的x轴了,要知道x轴必然垂直于z轴,所以能够通过摄像机z轴向量和一个和y轴平行方向相同的向量和摄像机的方向向量
进行叉乘,即可得到摄像机的x轴:
图中和国际坐标系的y轴平行的灰色向量和蓝色向量(摄像机的方向向量
)叉乘即可得到赤色向量,一般称为摄像机右向量
,指向的即是摄像机x轴方向
。
剩余的便是摄像机的y轴了,y轴和x、z轴垂直,所以只要将摄像机的方向向量
和摄像机的x轴叉乘就能够了,如下图:
图中绿色向量即为摄像机的y轴方向向量,一般称为摄像机的上方向向量
。
这样,摄像机坐标系就建立完结了。即上图摄像机赤色轴为x轴,绿色轴为y轴,蓝色轴为z轴
。
接下来便是怎样把处于国际坐标系的物体转化为摄像机的坐标系呢?其实便是找出物体相关于摄像机的相对方位,咱们的目标便是找出这个转化矩阵
,即上面说得到的调查矩阵
。
由于国际坐标系中的一切物体进行相同的改换,则它们的相对方位不变。所以用同个改换矩阵对一切物体进行改换,它们的相对方位不变
。
于是咱们能够这样处理:
1. 将摄像机坐标系原点平移到与国际坐标系的原点重合。
2. 然后将摄像机的三个坐标轴旋转到和国际坐标系的三个坐标轴重合,就能够将一切物体转化到摄像机坐标系了。
咱们假定R\color{red}R是右向量即x轴,U\color{green}U是上向量即y轴,D\color{blue}D是方向向量z轴,P\color{purple}P是摄像机方位向量,即从国际坐标原点到摄像机的向量
。
第一步是将摄像机坐标系原点(便是摄像机本尊)平移到与国际坐标系的原点重合,依据之前所学的平移矩阵,很简单得到矩阵:
第二步是将摄像机的三个轴旋转到和国际坐标系的三个坐标轴重合,即R\color{red}R和国际坐标系的x
轴重合,U\color{green}U和国际坐标系的y
轴重合,D\color{blue}D和国际坐标系的z
轴重合,则能够得到以下转化矩阵:
(由于直接求摄像机的三个轴旋转到和国际坐标系的三个坐标轴重合的旋转矩阵欠好求,所以这儿的数学推导主要思路是先求出逆改换矩阵
,即国际坐标系三个轴旋转到和摄像机三个轴重合的旋转矩阵,然后再求出这个旋转矩阵的逆矩阵
即可。)
所以终究调查矩阵(View Matrix)便是二者相乘
:
ViewMatrix=[RxRyRz0UxUyUz0DxDyDz00001]∗[100−Px010−Py001−Pz0001]View Matrix = \begin{bmatrix} \color{red}{R_x} & \color{red}{R_y} & \color{red}{R_z} & 0 \\ \color{green}{U_x} & \color{green}{U_y} & \color{green}{U_z} & 0 \\ \color{blue}{D_x} & \color{blue}{D_y} & \color{blue}{D_z} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} 1 & 0 & 0 & -\color{purple}{P_x} \\ 0 & 1 & 0 & -\color{purple}{P_y} \\ 0 & 0 & 1 & -\color{purple}{P_z} \\ 0 & 0 & 0 & 1 \end{bmatrix}
投影改换
接下来便是从3D改换到2D的要害了,这儿的投影和咱们平时说的投影很类似:
实质便是将3维空间中的物体投到一个平面上显现出来
。而在OpenGL中,这儿是是改换到一个规范归一化设备空间
。
最常见的投影有2种,一种是正交投影
,一种是透视投影
:
正交投影便是物体自身尺度多大,投影到投影平面仍是多大。而透视投影则是模拟人眼的功能,创造出一种近大远小
的感觉,如下图所示:
假如用以上2种投影应用于一个正立方体,那么就会出现以下不同作用图:
正交投影:
透视投影:
下面2个图能够更深入地了解投影是什么:
右边的为正交投影,左面的为透视投影
。
2种投影都有一个摄像机在一端像眼睛相同看过去,然后间隔摄像机近的有一个投影平面
,一般叫做近平面
,间隔摄像机远的有一个平面,叫做远平面
。
正交投影中,近平面和远平面是相同大的
,这两个平面组成了一个长方体,长方体内的物体都能够被投影到近平面上(长方体外的物体则会被裁剪掉
),能够看出投影线(假定有)是平行的
。
透视投影中,远平面比近平面大
,将摄像机和近平面和远平面上对应点用别离4条直线连起来,就组成了一个四棱锥,一般叫做平截头体
,平截头体中的物体都会被投影到近平面上(平截头体外的物体则会被裁剪掉
),能够看出投影线是被投影点和和摄像机的连线,该连线和近平面的交点便是显现该点的方位
。总的来看,便是从远平面到近平面,一切点的投影连线终究都聚集在摄像机一点上
。
能够显着看出,正交投影物体尺度保持不变,透视投影物体近大远小
。
还有一点:不管什么投影,间隔投影平面近的物体都会遮挡住间隔投影平面更远的物体
。
总结
一转眼现已写了上万字了,大伙们估量也看累了,我也写累了哈哈,接下来要讲的投影改换推导原理只能放在下一篇博文了。
今日主要介绍了改换矩阵扩展到3D的场景,以及OpenGL的坐标体系和各个坐标体系之间的转化,
首要是从部分坐标通过模型改换(Model transformation)转化到国际杯坐标系,再通过视图改换(View transformation)转化到调查坐标系(即摄像机坐标系),再通过投影改换(Projection transformation)转化到规范归一化设备空间,这一系列操作,在江湖也常常被称为MVP改换
~
当然说的不是NBA得MVP哈。。
下一篇将具体解说将3D物体烘托到2D平面最重要的投影改换以及投影改换的数学推导,还有最后的视口改换
,都是很有意思很重要的内容,我们有兴趣的话能够继续重视,将在近期出炉~
原创不易,假如觉得本文对自己有帮助,别忘了随手点赞和重视,这也是我创作的最大动力~
项目代码
opengl-es-study-demo 不断更新中,欢迎各位来star~
参考:
GAMES101-现代计算机图形学入门-闫令琪
改换
Fundamentals of Computer Graphics, Fourth Edition
计算机图形学系列笔记
坐标体系
系列文章目录
体系化学习系列博文,请看音视频体系学习总目录
实践项目: 介绍一个自己刚出炉的安卓音视频播放录制开源项目 欢迎各位来star~
相关专栏:
C/C++根底与进阶之路
音视频理论根底系列专栏
音视频开发实战系列专栏
一看就懂的OpenGL es教程