美文网首页
OpenGL ES-3D图形变换知识

OpenGL ES-3D图形变换知识

作者: _清墨 | 来源:发表于2018-06-27 11:17 被阅读161次

    最近一段时间很忙,没什么时间再去研究OpenGL,有朋友问我OpenGL ES图形变换的相关问题,这里抽出时间整理一下相关资料,便于大家学习3D图形运动的知识。
    (ps:有朋友以为我去腾讯云+社区写博客去了,这里说明一下,没有换平台写博客,只是加入了腾讯的云+社区分享计划,这里写的文章会自动同步到腾讯云+社区,有腾讯云+社区的朋友也可关注我)

    一.坐标系统

    OpenGL希望在所有顶点着色器运行后,所有我们可见的顶点都变为标准化设备坐标(Normalized Device Coordinate, NDC)。也就是说,每个顶点的x,y,z坐标都应该在-1.0到1.0之间,超出这个坐标范围的顶点都将不可见。我们通常会自己设定一个坐标的范围,之后再在顶点着色器中将这些坐标转换为标准化设备坐标。然后将这些标准化设备坐标传入光栅器(Rasterizer),再将他们转换为屏幕上的二维坐标或像素。

    将坐标转换为标准化设备坐标,接着再转化为屏幕坐标的过程通常是分步,也就是类似于流水线那样子,实现的,在流水线里面我们在将对象转换到屏幕空间之前会先将其转换到多个坐标系统(Coordinate System)。将对象的坐标转换到几个过渡坐标系(Intermediate Coordinate System)的优点在于,在这些特定的坐标系统中进行一些操作或运算更加方便和容易,这一点很快将会变得很明显。对我们来说比较重要的总共有5个不同的坐标系统:

    1.局部空间(Local Space,或者称为物体空间(Object Space))
    2.世界空间(World Space)
    3.观察空间(View Space,或者称为视觉空间(Eye Space))
    4.裁剪空间(Clip Space)
    5.屏幕空间(Screen Space)

    我们在用他们的时候,一般是为了将坐标从一个坐标系转换到另一个坐标系,用到的这些转换矩阵,最重要的几个分别是模型(Model)、视图(View)、投影(Projection)三个矩阵。首先,顶点坐标开始于局部空间(Local Space),称为局部坐标(Local Coordinate),然后经过世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)结束。

    上面说到的模型(Model)、视图(View)、投影(Projection)三个矩阵,与之密切相关的坐标系统分别为世界空间坐标系、观察空间坐标系、裁剪空间坐标系

    世界空间
    如果我们想将我们所有的对象导入到程序当中,它们有可能会全挤在世界的原点上(0,0,0),然而这并不是我们想要的结果。我们想为每一个对象定义一个位置,从而使对象位于更大的世界当中。世界空间(World Space)中的坐标就如它们听起来那样:是指顶点相对于(游戏)世界的坐标。物体变换到的最终空间就是世界坐标系,并且你会想让这些物体分散开来摆放(从而显得更真实)。对象的坐标将会从局部坐标转换到世界坐标;该转换是由模型矩阵(Model Matrix)实现的。

    观察空间
    观察空间(View Space)经常被人们称之OpenGL的摄像机(Camera)(所以有时也称为摄像机空间(Camera Space)或视觉空间(Eye Space))。观察空间就是将对象的世界空间的坐标转换为观察者视野前面的坐标。因此观察空间就是从摄像机的角度观察到的空间。而这通常是由一系列的平移和旋转的组合来平移和旋转场景从而使得特定的对象被转换到摄像机前面。这些组合在一起的转换通常存储在一个观察矩阵(View Matrix)里,用来将世界坐标转换到观察空间。

    裁剪空间
    在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个给定的范围内,且任何在这个范围之外的点都应该被裁剪掉(Clipped)。被裁剪掉的坐标就被忽略了,所以剩下的坐标就将变为屏幕上可见的片段。这也就是裁剪空间(Clip Space)名字的由来。

    说到裁剪空间,又不得不提到投影的概念:
    为了将顶点坐标从观察空间转换到裁剪空间,我们需要定义一个投影矩阵(Projection Matrix),它指定了坐标的范围,例如,每个维度都是从-1000到1000。投影矩阵接着会将在它指定的范围内的坐标转换到标准化设备坐标系中(-1.0,1.0)。所有在在范围(-1.0,1.0)外的坐标都不会被绘制出来并且会被裁剪。在投影矩阵所指定的范围内,坐标(1250,500,750)将是不可见的,这是由于它的x坐标超出了范围,随后被转化为在标准化设备坐标中坐标值大于1.0的值并且被裁剪掉。
    由投影矩阵创建的观察区域(Viewing Box)被称为平截头体(Frustum),且每个出现在平截头体范围内的坐标都会最终出现在用户的屏幕上。将一定范围内的坐标转化到标准化设备坐标系的过程(而且它很容易被映射到2D观察空间坐标)被称之为投影(Projection),因为使用投影矩阵能将3维坐标投影(Project)到很容易映射的2D标准化设备坐标系中。

    一旦所有顶点被转换到裁剪空间,最终的操作——透视划分(Perspective Division)将会执行,在这个过程中我们将位置向量的x,y,z分量分别除以向量的齐次w分量;透视划分是将4维裁剪空间坐标转换为3维标准化设备坐标。这一步会在每一个顶点着色器运行的最后被自动执行。
    在这一阶段之后,坐标经过转换的结果将会被映射到屏幕空间(就是我们的glViewport)且被转换成片段。
    投影矩阵将观察坐标转换为裁剪坐标的过程采用两种不同的方式,每种方式分别定义自己的平截头体。我们可以创建一个正射投影矩阵(Orthographic Projection Matrix)或一个透视投影矩阵(Perspective Projection Matrix)。

    投影矩阵

    投影矩阵我们在OpenGL里分为 透视投影正交投影

    透视投影其实就跟我们眼睛看到的效果是一样的,近处的东西大,远处的东西小,很好的比喻如:站在火车轨道上看两条轨道: image.png

    这种符合人体视觉近大远小的效果。

    而正交投影,则是远近都是一样的效果,如下图,摄像机看做人的视点,透视投影与正交投影在 Near clip plane上的效果对比:

    image

    一般来说,我们做OpenGLES项目的时候,所使用的都是符合视觉效果的透视投影矩阵GLKMatrix4MakePerspective

    GLKMatrix4 GLKMatrix4MakePerspective(float fovyRadians, float aspect, float nearZ, float farZ)
    {
        float cotan = 1.0f / tanf(fovyRadians / 2.0f);
        
        GLKMatrix4 m = { cotan / aspect, 0.0f, 0.0f, 0.0f,
                         0.0f, cotan, 0.0f, 0.0f,
                         0.0f, 0.0f, (farZ + nearZ) / (nearZ - farZ), -1.0f,
                         0.0f, 0.0f, (2.0f * farZ * nearZ) / (nearZ - farZ), 0.0f };
        
        return m;
    }
    

    当然正交投影也是很有用的,如一般工程测绘的那些项目,需要真实测绘每个面、线,这时常用的投影就是正交投影。

    好了,以上就是OpenGL做3D变换需要了解的理论知识。
    转成代码的话还需要大家自己根据项目实际来做,最后注意一点:

    OpenGL 中物体最初是在本地坐标空间中,然后转换到世界坐标空间,再到 camera 视图空间,再到投影空间,这一系列转换都是靠 matrix 计算来实现,也就是我们常用模型矩阵、摄像机矩阵、投影矩阵的原因。

    相关文章

      网友评论

          本文标题:OpenGL ES-3D图形变换知识

          本文链接:https://www.haomeiwen.com/subject/ziiqyftx.html