阅读 156

OpenGL ES学习第三篇:定义一个最简单的纹理

OpenGL ES学习第三篇:定义一个最简单的纹理

本文你可以了解到

  • OpenGL ES在应用层绘制流程
  • 定义一个最简单的三角形纹理过程
  • 使用native代码定义一个最简单的三角形纹理

OpenGL ES绘制分为三步

  • 定义纹理
  • 定义渲染器
  • 定义EGL环境

定义纹理

纹理可以理解为Android页面开发中用于绘制在View上的Bitmap,有加载、绘制、释放三个生命周期

  1. 加载纹理
  2. 绘制纹理
  3. 释放纹理
  4. 辅助方法
1. 定义纹理基类接口类,包括以上生命周期方法
interface ITexture {
    //加载纹理
    fun surfaceCreated()
    //绘制纹理
    fun updateTexImage(){}
    //释放纹理
    fun surfaceDestroyed()
    //辅助方法
    fun surfaceChanged(w: Int, h: Int){}
    fun setTextureSize(w: Int, h: Int){}
}
复制代码
2. 定义最简单的纹理实现:三角形纹理

顶点着色器设计:三角形只有一个平面,我们定义一个顶点数组,并提交给顶点着色器中gl_Position变量

private val vertexCoords = floatArrayOf(// 需自行了解下OpenGL世界坐标体系
        -1f, -1f,//左下
        1f, -1f,//右下
        0f, 0f//左上
    )

private val vertexShader = "attribute vec4 aPosition;" +
            "void main(){" +
            "   gl_Position=aPosition;" +
            "}"
复制代码

片段着色器设计:片段着色器给顶点提交的结构进行着色,本例中为写死红色

private val fragShader = "precision mediump float;" +
            "void main(){" +
            "   gl_FragColor=vec4(1.0, 0.0, 0.0, 1.0);" +
            "}"
复制代码

然后就可以实现纹理的三个关键生命周期了ShaderUtil为工具类方法。该方法比较固定,不做描述,自行查看。也奉劝诸位不要在意细节,封装好后基本上不会在查看,除非编译、链接shader代码出错时用来查bug。

override fun surfaceCreated() {
    vertexBuffer = ByteBuffer.allocateDirect(vertexCoords.size * 4).run {
        order(ByteOrder.nativeOrder())
        asFloatBuffer()
    }.apply {
        put(vertexCoords)
        position(0)
    }
    program = ShaderUtil.createProgram(vertexShader, fragShader)
    //获取顶点着色器中的变量handle,用于给三角形赋值坐标
    GLES20.glBindAttribLocation(program, aPositionIndex, "aPosition")
}

override fun updateTexImage() {
    GLES20.glUseProgram(program)
    //给顶点着色器中顶点赋值,第二个参数size为2意思是传入的坐标为2维坐标,绘制平面可以不需要z轴
    GLES20.glVertexAttribPointer(aPositionIndex, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer)
    GLES20.glEnableVertexAttribArray(aPositionIndex)//启用顶点
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 3)//绘制
    GLES20.glDisableVertexAttribArray(aPositionIndex)
}

override fun surfaceDestroyed() {
    GLES20.glDisableVertexAttribArray(aPositionIndex)
    GLES20.glDeleteProgram(program)
}
复制代码

这样一个2D纹理三角形就定义好了,就可以通过渲染器绘制到屏幕上了

3. 补充:定义三角形纹理的native实现方式

代码类似,直接上,注意API版本从2换成了3,着色器使用稍有改动,可以看出代码写在native里会更简洁,所以OpenGL开发应该主要在native层写代码。

GLfloat vertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        0.0f, 0.0f
};
GLushort indices[] = {0, 1, 2};

void texture_triangle::surfaceCreated() {
    char vertexSource[] = "#version 300 es                         \n"
                          "layout(location=0) in vec4 vPosition;   \n"
                          "void main()                             \n"
                          "{                                       \n"
                          "    gl_Position=vPosition;              \n"
                          "}                                       \n";
    char fragmentSource[] = "#version 300 es                       \n"
                            "precision mediump float;              \n"
                            "out vec4 fragColor;                   \n"
                            "void main()                           \n"
                            "{                                     \n"
                            "  fragColor=vec4(1.0, 0.0, 0.0, 1.0); \n"
                            "}                                     \n";
    program = ShaderUtil::createProgram(vertexSource, fragmentSource);
}
void texture_triangle::surfaceDestroyed() {
    if (program) {
        glDeleteProgram(program);
        program = GL_NONE;
    }
}

void texture_triangle::updateTexImage() {
    glUseProgram(program);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
    glUseProgram(GL_NONE);
}
复制代码
文章分类
Android