OpenGL学习随笔(四)——2022.1.26

        通过上回学习,我们学习和了解了3D世界中常用的基本数学知识,在本回中,我们将继续学习3D世界中的一些数学基础。


    一、局部空间和世界空间
        3D图形学常见的应用是模拟三维世界、在其中放入物体并在显示器上观看它。放在3D世界中的物体通常用三角形的集合来建模(三角形是最常用的几何图形)。如何建模将在后续内容中详细介绍,这回先简单了解一下。
        当建立物体的3D模型时,我们通常以最方便的定位方式描述模型。例如,如果模型是一个球体,那么我们就将球心定于原点,并赋给它一个简单半径1。**模型定义的空间叫做局部空间或模型空间,OpenGL文档使用的术语是物体空间**
        之后这个球形可能被用于另一个模型的一部分,如成为机器人的头部或天体卫星系统中的一员。机器人或天体卫星系统都有自己的模型空间。此时,我们可以通过之前学习的平移矩阵,缩放矩阵和旋转矩阵将球体模型放入机器人模型空间或天体卫星系统模型空间中。通过这种方式,可以分层次的构建复杂模型。
        使用同样的方式,**通过设定物体在模型世界中的朝向和大小,将物体放在模拟这个世界的空间中,这个空间叫做世界空间。将对象定位及定向在世界空间的矩阵称为模型矩阵或M。**


    二、视觉空间和合成相机
        为了将3D空间显示在2D显示器上,我们必须找到一点并确定观察方向作为我们观察虚拟世界的窗口。正如我们在现实世界里通过眼睛从一点观察一样,**在3D模型中,这个点叫做“视图”或“视觉空间”或“合成相机**
        通常,观察3D世界需要一下步骤:

  1. 将相机放入世界的某个位置。
  2. 调整相机的角度,通常需要一套它自己的直角坐标系
  3. 定义一个视体(view volume)
  4. 将视体内的对象投影到投影平面。

图源自《计算机图形学编程(使用OpenGL和C++)》作者:V.斯科特.戈登 约翰.克莱维吉 (人民邮电出版社)199页)

         在OpenGL中,有一个固定在原点(0,0,0)并向下看向Z轴负方向的相机,为了应用OpenGL相机,我们需要将它模拟移动到适合的位置和方向。

  1. 需要先找出在世界中的物体与我们期望的相机位置的相对位置,即物体应该在下图所示相机U、V、N轴定义的相机空间中的位置。
  2.  对于给定世界中的点Pw,我们需要通过变换将它转化成相应相机空间中的点。从而让它看起来好像是从我们期望的相机位置C进行观看的。我们通过计算它在相机空间中的位置Pc来实现。已知OpenGL相机的位置永远固定在(0,0,0)处,则需要做的变换为:(1)将Pw平移,使其向量为负的期望相机位置。(2)将Pw旋转,其角度为负的期望相机旋转的角度。
  3. 我们通过构建一个单一变换矩阵完成旋转和平移,这个矩阵叫做视图变换矩阵V,矩阵V通过合并矩阵T(包含负相机期望位置的平移矩阵)和R(包含负期望相机旋转的旋转矩阵),即Pc = (R*T)*Pw = V*Pw
  4. 通常,V矩阵与模型矩阵M合并为一个模型-视图绝阵(MV矩阵),即MV = V*M,之后,点Pw在从自己的模型空间通过一个步骤就可以直接转换到相机空间,即Pc = MV * Pw。
  5. 对于复杂的场景,我们需要对每个顶点进行变换,通过预先计算MV,对于空间中的每个点的变换只需要一次矩阵变换即可,减少了计算量。

 (图源自《计算机图形学编程(使用OpenGL和C++)》作者:V.斯科特.戈登 约翰.克莱维吉 (人民邮电出版社)200页)

三、投影矩阵

        设置好相机的位置之后,就可以学习投影矩阵了,分别是透视投影和正射投影。

  •         透视投影矩阵

        透视投影通过使用透视概念模拟我们看真实世界的方式,尝试让2D图像看起来像是3D的。物体近大远小,3D空间中的平行线用透视法画出来就不再平行了。

        我们通过使用变换矩阵将平行线变为恰当的不平行线来实现这个效果。这个矩阵叫做透视矩阵或者透视变换 。通过定义4 个参数来进行视体的构建,4个参数分别是纵横比、视场、投影平面(也叫近剪裁平面)、远裁剪平面。近剪裁平面也是物体所投影到的平面,通常放在离相机较近的位置;视场是可视空间的纵向角度;纵横比是远裁剪平面的宽度比高度;远裁剪平面如何选取将在后续章节中讲到,通过这4个元素形成的形状叫做视锥。如下图:

图源自《计算机图形学编程(使用OpenGL和C++)》作者:V.斯科特.戈登 约翰.克莱维吉 (人民邮电出版社)209页) 

        透视矩阵用于将3D空间中的点变换至近裁剪平面上合适的位置,它的构建需要先计算q,A,B,C的值,之后用这些值来构建透视矩阵。生成透视矩阵比较容易,GLM库包含了一个用于构建透视矩阵的函数glm:perspective()。

图源自《计算机图形学编程(使用OpenGL和C++)》作者:V.斯科特.戈登 约翰.克莱维吉 (人民邮电出版社)210页)

  •    正射投影矩阵

        在正射投影中,平行线仍然是平行的。正射与透射相反,在视体中的物体不因其与相机的距离而作任何调整,直接进行投影。正射投影是一种平行投影,其中所有的投影都与投影平面垂直。正射矩阵通过6个参数构建:(1)从相机到投影平面的距离Znear,(2)从相机位置到远裁剪平面的距离Zfar,(3)L、R、T、B,其中L和R分别是投影平面左右边界的X坐标,T和B分别是投影平面上下边界的Y坐标。并非所有的平行投影都是正射投影。正射矩阵形式如下:

图源自《计算机图形学编程(使用OpenGL和C++)》作者:V.斯科特.戈登 约翰.克莱维吉 (人民邮电出版社)212页) 

 四、LookAt矩阵

        当需要把相机放在某处看一个特定的位置时,就需要用LookAt矩阵。LookAt变换依然是由相机旋转决定的。我们通过指定大致的旋转朝向的向量(如Y轴)。通常可以通过一系列叉积获得相机旋转的正面、侧面及上面。此处省略计算过程,在GLM中函数可以通过指定相机位置、目标位置以及初始“向上”向量Y,构建一个LookAt矩阵,为glm::lookAt()。

五、在GLSL中构建变换矩阵

        虽然在GLM库中已经有了变换矩阵的相应的函数,但是在GLSL中,只定义了基础的矩阵运算,因此我们有必要自己写一些函数来实现矩阵变换。

        注意:在GLSL中用于初始化mat4矩阵的语法是以列为单位读入值。即前四个数为第一列,接下来四个数为第二列,直到第四列。

//构建并返回平移矩阵
mat4 buildTranslate(float x,float y,float z)
{
    mat4 trans = mat4(1.0, 0.0, 0.0, 0.0,
                      0.0, 1.0, 0.0, 0.0,
                      0.0, 0.0, 1.0, 0.0,
                      x  , y  , z  , 1.0);
    return trans;
}

//构建并返回绕X轴旋转的旋转矩阵
mat4 bulidRotateX(float rad)
{
    mat4 xrot = mat4(1.0, 0.0, 0.0, 0.0,
                     0.0, cos(rad), -sin(rad), 0.0,
                     0.0, sin(rad), cos(rad), 0.0,
                     0.0, 0.0, 0.0, 1.0);
    retunr xrot;
}

//构建并返回绕Y轴旋转的旋转矩阵
mat4 buildRotateY(float rad)
{
    mat yrot = mat4(cos(rad), 0.0, sin(rad), 0.0,
                    0.0, 1.0, 0.0, 0.0,
                    -sin(rad), 0.0, cos(rad), 0.0,
                    0.0, 0.0, 0.0, 1.0);
    return yrot;
}

//构建并返回绕Z轴旋转的旋转矩阵
mat4 buildRotateZ(float rad)
{
    mat4 zrot = mat4(cos(rad), -sin(rad), 0.0, 0.0,
                     sin(rad), cos(rad), 0.0, 0.0,
                     0.0, 0.0, 1.0, 0.0,
                     0.0, 0.0, 0.0, 1.0);
    return zrot;
}

//构建并返回缩放矩阵
mat4 buildScale(float x,float y,float z)
{
    mat4 scale = mat4(x  , 0.0, 0.0, 0.0,
                      0.0, y  , 0.0, 0.0,
                      0.0, 0.0, z  , 0.0,
                      0.0, 0.0, 0.0, 1.0);
    return scale;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

#include<BJTU>

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值