推荐:
什么是三角形(三角插形)
发布时间:2022-09-05

一、引言

在Android OpenGL基础(一、绘制三角形四边形)中,我们简单实现了绘制三角形的功能。大家可能会发现,我们声明的是一个标准设备坐标系下的等边三角形:

class Triangle {
    // 三角形三个点的坐标值
    private var triangleCoords = floatArrayOf(
        0.0f, 0.5f, 0.0f,      // top
        -0.5f, -0.5f, 0.0f,    // bottom left
        0.5f, -0.5f, 0.0f      // bottom right
    )
}

但是实际绘制出来的结果却是:

这是因为OpenGL假设屏幕采用均匀的方形坐标系,所以在把标准坐标系下的坐标绘制到非方形的屏幕上时,就会出现拉伸:

那怎么保证顶点的实际绘制效果与预期一致,绘制出我们想要的等边三角形呢。要解决这个问题,可以通过应用 OpenGL 相机视图和投影模式来转换坐标,这样,我们的图形对象在任何屏幕上都会按正确的比例绘制。

二、坐标系统

在程序中设置了物体的顶点坐标后,OpenGL还需要经过一系列的坐标变换,最终变换到屏幕坐标,才决定了顶点的实际绘制位置。这个过程需要用到几个变换矩阵,最重要的几个分别是模型(Model)、观察(View)、投影(Projection) 三个矩阵。我们的顶点坐标起始于局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。

下面通过一个例子展示下各个变换过程的主要工作,假设我们要绘制一个正方体和一个三棱锥,在定义了正方体和三棱锥后,到他们实际绘制到屏幕上,经历了以下几个坐标变换:

2.1 局部坐标(Local Coordinate)

首先,我们需要先设置好正方体和三棱锥的顶点位置,这个时候分别在二者自身的局部坐标中设置自身顶点的坐标即可。二者的局部坐标都是一个(-1,1)的标准坐标系,此时二者之间还没有关系。

2.2 世界坐标(World Coordinate)

在各物体的局部坐标设置后,实际世界中的物体是分散放在不同地方的,如下图所示,正方体和三棱锥分别放到了不同不同的位置,这个时候二者之间才有了相互间的位置关系。

正方体和三棱锥的坐标将会从局部变换到世界空间。该变换是由模型矩阵(Model Matrix)实现的。模型矩阵是一种变换矩阵,它能通过对物体进行位移、缩放、旋转来将它置于它本应该在的位置或朝向。

目前Android OpenGL基础(一、绘制三角形四边形)中绘制三角形的例子比较简单,几何体都是放在世界坐标的正中心,所以暂时不需要特殊指定模型矩阵。暂时先只做简单了解。

2.3 观察坐标(View Coordinate)

在世界坐标中摆放完正方体和三棱锥的位置后,接下来需要设置我们想观察的位置,从不同的位置观察世界坐标中的正方体和三棱锥,看到的是不同的样子。例如从2.2小节中camera的位置去观察,看到的结果如下:

观察空间经常被人们称之OpenGL的摄像机(Camera,是个抽象的概念,不是Android手机的相机,不要混淆)。从世界空间转换到观察空间通常是由一系列的位移和旋转的组合来完成,这些组合在一起的变换通常存储在一个观察矩阵(View Matrix)里。

2.4 裁剪坐标(Clip Coordinate)

在设置了观察矩阵后,OpenGL世界的所有物体已经呈现在我们视野前方,但是实际展示的时候并不需要全部展示,因此需要把不展示的部分裁剪掉,绘制的时候忽略裁剪掉的部分,减少绘制时的运算量。决定哪部分可以展示是由投影矩阵决定的(因为使用投影矩阵能将3D坐标投影(Project)到很容易映射到2D的标准化设备坐标系中)。