前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenGL坐标转换推导(十一)

OpenGL坐标转换推导(十一)

原创
作者头像
PengJie
修改2021-01-11 10:08:17
2.3K0
修改2021-01-11 10:08:17
举报
文章被收录于专栏:音视频修炼路音视频修炼路

OpenGL坐标转换过程

之前我们已经提到在OpenGL中,所有物体都是在一个3D空间里的,但是屏幕都是2D像素数组,所以OpenGL会把3D坐标转变为适应屏幕的2D像素,最终投射到2D的屏幕上去。所以对于每一个顶点坐标都会依次进行model、view、projection三种变换。这三种变换实现代码如下:

代码语言:txt
复制
gl_Position = projection * view * model * vec4(position.xyz, 1);

简单来说就是gl_Position就是我们的每一个3维坐标经过model、view、projection三种变换的得出在标准化设备坐标系(Normalized Device Coordinates, NDC)中的坐标,可以回顾一下前文提到的每个坐标系之间关系如下图,

实际上model、view、projection这三种变换,分别是通过左乘一个矩阵来完成的。总的来说在OpenGL体现中,如果要实现3D物体的运动实际上是每个顶点的位置改变,而顶点的位置改变则是通过矩阵乘法来实现的。

代码中的vec4(position.xyz, 1)表示顶点在本地坐标系中的坐标(是一个四维的齐次坐标)。它左边乘上model矩阵,就得到了该顶点在世界坐标系中的坐标。这个model变换可能包含了缩放、旋转、平移(这三种变换。然后,世界坐标系中的坐标再左乘一个view矩阵,就变换到了相机坐标系。最后,再左乘projection矩阵。也就是说上面代码projection, view ,model分别对应着一种矩阵。

平移矩阵的推导过程

我们前文一直在说顶点位置的变换,3D对象的本地坐标经过一个model变换,就变换到成了世界坐标。不同的对象经过各自的model变换之后,就都位于同一个世界坐标系中了,它们的世界坐标就能表达各自的相对位置。一般来说,model变换又包含三种可能的变换:缩放、旋转、平移。而顶点的缩放、旋转、平移是通过顶点坐标和矩阵乘法来实现的,那么这个矩阵是怎么确定的呢,我们可以从线性代数的基础理论上进行一下了解。

如果我们要对顶点坐一个平移,我们最先可能会想到通过向量的平移来实现,先从二维开始分析,如下图

我们建立了一个直角坐标系,添加向量\overrightarrow{OP} ,它是一个有大小和方向的量。把它表示在坐标系里的时候,起点在原点O,终点指向点P。这个向量的坐标和点P的坐标一样,都可以记为(1,2)。因为的向量有一个性质,是向量与起点位置无关,也就是说,一个向量向任意方向平移之后不变。比如,在上图中,向量 \overrightarrow{OP} 平移之后得到向量\overrightarrow{AQ},平移前后它们的大小和方向都一样,所以它们表示相同的向量。所以,平移后的向量\overrightarrow{AQ} 也是用以坐标(1,2)来表示。也就是说向量平移后坐标不变,那么我们要对顶点进行平移变换,就不能直接通过对一个向量的平移来得到。

那么我们必须换一种方法来实现顶点的平移,比如通过向量加法来完成。见下图。

图中A点平移到B点,相当于做一个向量加法:\overrightarrow{OA} +\overrightarrow{AB} =\overrightarrow{OB} 我们看到,在直角坐标系中,向量加法满足三角形法则。其中向量 \overrightarrow{AB} 代表了平移的大小和方向,称为平移向量。因为向量平移大小和方向不变,\overrightarrow{AB}和向量 \overrightarrow{OA'} 相等,能看出它的坐标是(0.5,1)。向量 \overrightarrow{OA} 加上这样的一个平移向量,相当于把点A沿x轴平移0.5个单位,并沿y轴平移1个单位,这样就平移到了点B的位置。

前面图中是2维向量的例子,现在我们扩展到3维,假设顶点坐标是(x,y,z)将平移变换用向量坐标来表示,如下:

\left[ \begin{matrix} x \\ y \\ z \\ \end{matrix} \right]+\left[ \begin{matrix} P_x \\ P_y \\ P_z \\ \end{matrix} \right]=\left[ \begin{matrix} x+P_x \\ y+P_x \\ z+P_x \\ \end{matrix} \right] ,其中的\left[ \begin{matrix} P_x \\ P_y \\ P_z \\ \end{matrix} \right] 就代表前面提到的平移向量的值。

在线性代数中,一个变换通常使用矩阵的乘法来表达。而且OpenGL 使用GPU来进行运算,GPU对于矩阵乘法有着非常高效的算法。我们也希望这里的平移变换能用矩阵乘法(具体说是左乘)来表达。我们设想一个3x3的矩阵A,让它乘上顶点的3维坐标:

A \left[ \begin{matrix} x \\ y \\ z \\ \end{matrix} \right]=\left[ \begin{matrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \\ \end{matrix} \right]\left[ \begin{matrix} x \\ y \\ z \\ \end{matrix} \right]=\left[ \begin{matrix} a_{11}x & a_{12}y & a_{13}z \\ a_{21}x & a_{22}y & a_{23}z \\ a_{31}x & a_{32}y & a_{33}z \\ \end{matrix} \right]

我们发现,无论矩阵A的各个元素取什么样的值,我们只能得到x,y,z的线性组合,而怎么样也得不到类似前面向量加法的结果形式(x,y,z分别加上一个常数)。为了解决这个问题,我们将3维的顶点坐标换成4维的齐次坐标。所谓齐次坐标,就是在3维坐标的基础上,加上第4个维度,并把它的值设成1。也就是说,3维坐标 \left[ \begin{matrix} x \\ y \\ z \\ \end{matrix} \right]变成齐次坐标就是:\left[ \begin{matrix} x \\ y \\ z \\ 1 \\ \end{matrix} \right]

当然,齐次坐标的第4个元素,也可以不是1,不过这种情况我们暂时用不到,现在我们可以简单的认为,齐次坐标就是多了第4个维度,并且它是一个固定的1。多出来的这个1只要在需要的时候把它去掉,我们就能得到原来的3维坐标。实际上,在OpenGL ES中,我们总是以4维的齐次坐标来表示顶点坐标。所以上文代码中vertex shader程序中的 vec4(position.xyz, 1)

代码语言:txt
复制
gl_Position = projection * view * model * vec4(position.xyz, 1);

vec4(position.xyz,1)就是一个齐次坐标。

这样一个4维的顶点坐标经过左乘一个矩阵,得到的结果也是一个4维的顶点坐标(仍然是个齐次坐标)。这个矩阵需要是4X4的。根据矩阵乘法的定义,现在我们很容易拼出一个能表示平移的矩阵来:\left[ \begin{matrix} 1 & 0 & 0 & P_{x} \\ 1 & 0 & 0 & P_{y} \\ 1 & 0 & 0 & P_{z} \\ 1 & 0 & 0 & 1 \\ \end{matrix} \right]\left[ \begin{matrix} x \\ y \\ z \\ 1 \\ \end{matrix} \right]=\left[ \begin{matrix} P_{x} + x \\ P_{y} +y \\ P_{z} +z \\ 1 \\ \end{matrix} \right]

其中矩阵:\left[ \begin{matrix} 1 & 0 & 0 & P_{x} \\ 1 & 0 & 0 & P_{y} \\ 1 & 0 & 0 & P_{z} \\ 1 & 0 & 0 & 1 \\ \end{matrix} \right]就是我们要推导的,它是4x4平移矩阵。其中PxPyPz元素恰好是平移向量,使得顶点坐标

经过矩阵乘法之后得到了向量加法的结果形式\left[ \begin{matrix} P_{x} + x \\ P_{y} +y \\ P_{z} +z \\ 1 \\ \end{matrix} \right]

缩放矩阵的推导过程

上图表示的是一个2维向量的缩放过程。向量 \overrightarrow{OP} 在x和y方向上都放大了1.5倍就得到了向量\overrightarrow{OP_{1}},记作(3,1.5)。也就是一个2维向量的放大和缩小就是自身对应的坐标在x轴和y轴大小的放大和缩小。同理一个顶点在3维空间的放大和缩小则是在3维空间顶点自身坐标(x,y,z)也放大和缩小相同的倍数。还是以上图2维向量为例,向量 \overrightarrow{OP} 在x方向上缩小为原来的0.5倍,在y方向上放大为原来的2倍,就得到了向量 \overrightarrow{OP_{2}} ,坐标从(2,1)变换成了(1,2),这也是一种缩放变换。

在3维空间,假设我们把顶点坐标(x,y,z)用4维的齐次坐标表示(x,y,z,1)各个维度的坐标分别放大或缩小一个倍数对应指为

S_x,S_y,S_z,1则可以用\left[ \begin{matrix} S_{x}x \\ S_{y}y \\ S_{z}z \\ 1 \\ \end{matrix} \right]表示。缩放操作用矩阵乘法可以写成: \left[ \begin{matrix} S_{x} & 0 & 0 & 0 \\ 0 & S_{y} & 0 & 0 \\ 0 & 0 & S_{z} & 0 \\ 0 & 0 & 0 & 1 \\ \end{matrix} \right]\left[ \begin{matrix} x \\ y \\ z \\ 1 \\ \end{matrix} \right]=\left[ \begin{matrix} S_{x}x \\ S_{y}y \\ S_{z}z \\ 1 \\ \end{matrix} \right]上面这个式子意思就是,一个向量的x,y,z坐标经过缩放变换之后,分别变成了原来Sx,Sy,Sz倍。而式子中左乘的这个4x4的矩阵,就是我们要推导的缩放矩阵:\left[ \begin{matrix} S_{x} & 0 & 0 & 0 \\ 0 & S_{y} & 0 & 0 \\ 0 & 0 & S_{z} & 0 \\ 0 & 0 & 0 & 1 \\ \end{matrix} \right]

小结

以上两种矩阵推算过程只是OpenGL 众多矩阵变换中的两种,是为了举例说明顶点坐标变换的思维过程,让初学者容易触摸到入门的门槛。有兴趣的同学,可以再在这基础上作更深入详细的研究。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • OpenGL坐标转换过程
  • 平移矩阵的推导过程
  • 缩放矩阵的推导过程
  • 小结
相关产品与服务
图像处理
图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档