OpenGL ES系列五--图元形式及绘制方式

OpenGL ES图元形式及绘制方式

OpenGL ES的绘制主要涉及到两个方面,一个是图元绘制,还有一个是绘制方式。下面我们先以图元绘制开始,下面再讲解绘制顺序。

图元绘制(此处默认使用GLES30.glDrawArrays()函数绘制)

在OpenGL ES中支持的绘制图元有以下三种:点、线、三角形,每一种图元都有多种绘制方式,我们都会讲解说明。以下是示例代码,感兴趣的可以下载下来看一下。

OpenGL ES示例代码

先上一下我们实例代码中四个点的坐标位置:

//顶点坐标数组(每三个一组,共四组,对应四个顶点坐标)
val vertexIndexArray = floatArrayOf(
         //x,y,z
         //左上
         -1.0f, 1.0f, 1f,
         //右上
         1.0f, 1.0f, 1f,
         //右下
         1.0f, -1.0f, 1f,
         //左下
         -1.0f, -1.0f, 1f
)

对应的空间坐标图如下:

OpenGL ES系列五--图元形式及绘制方式_第1张图片

可能画的不是很好,见谅啊。

点的绘制只有一种即GLES30.GL_POINTS,它会按我们上面定义的顺序依次绘制,效果图如下:

OpenGL ES系列五--图元形式及绘制方式_第2张图片

在绘制点的时候有一点需要注意:

在OpenGL ES1.0里面,在java层是有API可以直接设置点大小的:gl.glPointSize(),这里的gl为实现GLSurfaceView.Renderer重写方法中的GL10,但是从OpenGL ES2.0/3.0开始是没有这个API的,如果要设置点大小,只能在顶点着色器里面设置,它提供了内置变量gl_PointSize。具体可以下载上面的Demo,里面都有详细的注释。

线

线的绘制形式有三种:

  • GLES30.GL_LINES。以给定的顶点为依据,每两个绘制一条直线,顶点数超过会被丢弃,比如五个顶点,那么第五个不会绘制出来
  • GLES30.GL_LINE_STRIP。以给定的顶点为依据,按照顶点顺序连接顶点
  • GLES30.GL_LINE_LOOP。以给定的顶点为依据,按照顶点顺序连接顶点,最后会将首尾两点连接

还是以上面四个点为例,效果分别如下:

OpenGL ES系列五--图元形式及绘制方式_第3张图片

OpenGL ES系列五--图元形式及绘制方式_第4张图片

OpenGL ES系列五--图元形式及绘制方式_第5张图片

三角形

三角形的绘制形式同样有三种:

  • GL_TRIANGLES。三个点一组,如果不够三个点就会被丢弃
  • GL_TRIANGLE_STRIP。顶点按照顺序依次组成三角形绘制,最后实际形成的是一个三角型带。
  • GL_TRIANGLE_FAN。将第一个点作为中心点,其他点作为边缘点,绘制一系列的组成扇形的三角形

以上面的4个顶点为例,效果如下:

OpenGL ES系列五--图元形式及绘制方式_第6张图片

第四个点由于没有可以拼成的三角形,被丢弃。

OpenGL ES系列五--图元形式及绘制方式_第7张图片

OpenGL ES系列五--图元形式及绘制方式_第8张图片

绘制方式

绘制同样的图元,在OpenGL ES中其实是有多种方式的,下面我们就介绍一下常用的,一些不常用的也会列出,可以自己去查询:

  1. glDrawArrays
  2. glDrawElements
  3. glDrawRangeElements
  4. glDrawArraysInstanced(渲染大量类似对象时使用)
  5. glDrawElementsInstanced(渲染大量类似对象时使用)

我们以1、2为例,我们上面的效果图用的都是glDrawArrays,现在我们详细说明每一个参数的含义:

public static native void glDrawArrays(
    //绘制图元的形式,就是我们上面一节讲的GLES30.GL_GL_TRIANGLES、GLES30.GL_POINTS等
    int mode,
    //第一个顶点索引从多少开始,一般都是从0开始
    int first,
    //要绘制的顶点个数
    int count
)

我们以绘制GL_TRIANGLE_FAN为例,first设置1,看看效果图:

OpenGL ES系列五--图元形式及绘制方式_第9张图片

我们发现当我们索引从1开始时,三角形少了一个,因为虽然我们绘制的是四个顶点,可是第一个点并没有绘制,而是从第二个点开始。

现在说明glDrawElements的参数含义:

public static native void glDrawElements(
        //绘制图元的形式
        int mode,
        //绘制的顶点个数
        int count,
        //顶点参数类型,GL_FLOAT、GL_INT、GL_UNSIGNED_SHORT等
        int type,
        //保存顶点索引数组的缓存数据
        java.nio.Buffer indices
    )

我们以如下顺序作为索引数组

//顶点绘制索引数组
val vertexIndexArray = shortArrayOf(
        //x,y,z
        //右上
        1,
        //右下
        2,
        //左下
        3,
        //左上
        0
)

此时的效果是:

OpenGL ES系列五--图元形式及绘制方式_第10张图片

补充知识点(为了看代码不会懵逼)

编写OpenGL ES程序的大致流程,这个是在所有OpenGL ES项目中都有涉及到的,基本上都是相同的。

  1. 创建GLSurface子类

    这里主要是做一些初始化操作,比如初始化版本、初始化渲染器、设置渲染器、设置渲染模式

  2. 渲染器的初始化

    渲染器为GLSurfaceView.Renderer的子实现类,主要是重写三个方法:onSurfaceCreated、onSurfaceChanged、onDrawFrame,在这三个函数中做一些不同的逻辑处理。onSurfaceCreated主要是做一些初始化配置,比如初始化算法实例(算法类里面会定义顶点相关数据,绘制操作等,相当于把所有的逻辑都放在这里,当然你也可以不这么做,按自己的想法来搞)、初始化着色器程序、初始化着色器变量句柄(可以理解为着色器变量的唯一标识);onSurfaceChanged主要是做视口设置、相机位置设置、投影矩阵设置等;onDrawFrame则是为着色器传递数据,并绘制

  3. 算法类实例化时做一些初始化操作–初始化顶点数据、初始化着色器和句柄

    初始化顶点数据:这一步其实就是第二步中onSurfaceCreated执行的逻辑,我们在这里会初始化顶点坐标、顶点颜色、顶点纹理、顶点索引、顶点法向量等等

    初始化着色器和句柄:这一步也是在第二步中onSurfaceCreated执行的逻辑,我们需要读取着色器源码,然后传递给相应的API来创建着色器程序,一旦创建成功,我们需要从着色器程序中获取着色器变量的句柄(可以理解为着色器变量的唯一标识),后面绘制时我们可以根据这个句柄为着色器变量传值

  4. 算法类的onCreate方法,对应onSurfaceCreated

    这里我们主要是做设置背景、根据需要开启一些被禁用的功能(比如深度测试、混合等等)、初始化线程等

  5. 算法类的onChange方法,对应onSurfaceChanged

    主要是设置视口、设置相机、设置投影等

  6. 算法类的onDraw方法,对应onDrawFrame

    主要是配置着色器程序、为着色器变量(句柄)赋值、矩阵变换(平移、旋转、缩放…)、绘制相应的图元等

有了上面一个大致顺序的说明,在看demo的时候才不会晕。到这里也已经差不多了,如有什么不足之处还请指出,互相学习。

你可能感兴趣的:(OpenGL-ES)