OpenGL ES Android 第二课 绘制三角形

有了第一篇的基础,现在开始着手绘制一个三角形,
先总结一下 OpenGL es 绘制的基本流程

1. 编写 vertex Shader 和 Fragment shader 的代码
2. 编译 vertex Shader和Fragment shader
3. 创建 programs 对象,连接两个 shader
4. onDrawFrame 中,绘制 shader

我们按照上面的步骤一步步的来

第一步 编写shader

顶点着色器(vertex shader)
 attribute vec4 vPosition;
 void main() {
     gl_Position = vPosition;
 }

发现比上一篇的的多了一个东西,其实就是多定义了一个成员变量vPosition,其中 attribute表示成员变量,vec4表示类型为齐次坐标,也就是说gl_Position这个变量的内容取自vPosition这个变量,而这个变量在后面会被我们 Java 层赋值

片元着色器
 uniform vec4 vColor;
 void main() {
     gl_FragColor = vColor;
 }

原理和上面一致,定义变量让外界赋值

第二步 处理 shader

这一步在步骤十分固定 样板代码

  1. 设置背景
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
  1. 编译 链接 处理 shader 源码
val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
                VERTEX_SHADER)
val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,FRAGMENT_SHADER)
//创建一个空的OpenGLES程序
mProgram = GLES20.glCreateProgram()
//将顶点着色器加入到程序
GLES20.glAttachShader(mProgram, vertexShader)
//将片元着色器加入到程序中
GLES20.glAttachShader(mProgram, fragmentShader)
//连接到着色器程序
GLES20.glLinkProgram(mProgram)
fun loadShader(type: Int, shaderString: String): Int {
        val shader = GLES20.glCreateShader(type)
        GLES20.glShaderSource(shader, shaderString)
        GLES20.glCompileShader(shader)
        return shader
}
  1. 把图形坐标点数据转化成 openGL 可以识别的格式
//申请底层空间
val bb = ByteBuffer.allocateDirect(triangleCoords.size * 4)
//数据硬件对齐
bb.order(ByteOrder.nativeOrder())
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
vertexBuffer = bb.asFloatBuffer()
vertexBuffer.put(triangleCoords)
vertexBuffer.position(0)
  1. 最后 绘制三角形

设置 shader

GLES20.glUseProgram(mProgram)

更改 Vertex Shader的 里面 vPosition 的值,把三角形的顶点数值赋值上去

//获取顶点着色器的vPosition成员句柄
val mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition")
//启用三角形顶点的句柄
GLES20.glEnableVertexAttribArray(mPositionHandle)
//准备三角形的坐标数据
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
        GLES20.GL_FLOAT, false,
        vertexStride, vertexBuffer)

同理,设置 Fragment shader 里面 vColor 的值

//获取片元着色器的vColor成员的句柄
val mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor")
//设置绘制三角形的颜色
GLES20.glUniform4fv(mColorHandle, 1, color, 0)

绘制三角形

//绘制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount)

回收资源 回收顶点数组引用

//禁止顶点数组的句柄
GLES20.glDisableVertexAttribArray(mPositionHandle)

第一个参数表示绘制方式,定义如下

int GL_POINTS       //将传入的顶点坐标作为单独的点绘制
int GL_LINES        //将传入的坐标作为单独线条绘制,ABCDEFG六个顶点,绘制AB、CD、EF三条线
int GL_LINE_STRIP   //将传入的顶点作为折线绘制,ABCD四个顶点,绘制AB、BC、CD三条线
int GL_LINE_LOOP    //将传入的顶点作为闭合折线绘制,ABCD四个顶点,绘制AB、BC、CD、DA四条线。
int GL_TRIANGLES    //将传入的顶点作为单独的三角形绘制,ABCDEF绘制ABC,DEF两个三角形
int GL_TRIANGLE_FAN    //将传入的顶点作为扇面绘制,ABCDEF绘制ABC、ACD、ADE、AEF四个三角形
int GL_TRIANGLE_STRIP   //将传入的顶点作为三角条带绘制,ABCDEF绘制ABC,BCD,CDE,DEF四个三角形

5.贴上完整代码

open class Triangle : Shape() {
    private val VERTEX_SHADER =
            "attribute vec4 vPosition;\n" +
                    " void main() {\n" +
                    "     gl_Position = vPosition;\n" +
                    " }"


    //gl_FragColor是fragment shader的内置变量,用于指定当前顶点的颜色,
    // 四个分量(r, g, b, a)。这里是想指定为红色,不透明。
    private val FRAGMENT_SHADER =
            "precision mediump float;\n" +
                    " uniform vec4 vColor;\n" +
                    " void main() {\n" +
                    "     gl_FragColor = vColor;\n" +
                    " }"
    private var triangleCoords = floatArrayOf(0.5f, 0.5f, 0.0f, // top
            -0.5f, -0.5f, 0.0f, // bottom left
            0.5f, -0.5f, 0.0f  // bottom right
    )

    private var color = floatArrayOf(1.0f, 1.0f, 1.0f, 1.0f) //白色

    //顶点之间的偏移量
    private val vertexStride = COORDS_PER_VERTEX * 4 // 每个顶点四个字节
    //顶点个数
    private val vertexCount = triangleCoords.size / COORDS_PER_VERTEX

    private var mProgram: Int = 0
    private lateinit var  vertexBuffer:FloatBuffer

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        //将背景设置为灰色
        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f)
        //申请底层空间
        val bb = ByteBuffer.allocateDirect(
                triangleCoords.size * 4)
        //数据硬件对齐
        bb.order(ByteOrder.nativeOrder())
        //将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
        vertexBuffer = bb.asFloatBuffer()
        vertexBuffer.put(triangleCoords)
        vertexBuffer.position(0)

        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
                VERTEX_SHADER)
        val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
                FRAGMENT_SHADER)

        //创建一个空的OpenGLES程序
        mProgram = GLES20.glCreateProgram()
        //将顶点着色器加入到程序
        GLES20.glAttachShader(mProgram, vertexShader)
        //将片元着色器加入到程序中
        GLES20.glAttachShader(mProgram, fragmentShader)
        //连接到着色器程序
        GLES20.glLinkProgram(mProgram)
    }


    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    }

    override fun onDrawFrame(gl: GL10?) {

        GLES20.glUseProgram(mProgram)

        //获取顶点着色器的vPosition成员句柄
        val mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition")
        //启用三角形顶点的句柄
        GLES20.glEnableVertexAttribArray(mPositionHandle)
        //准备三角形的坐标数据
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer)


        // 这里其实就是取出源码里面的 变量 进行赋值

        //获取片元着色器的vColor成员的句柄
        val mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor")
        //设置绘制三角形的颜色
        GLES20.glUniform4fv(mColorHandle, 1, color, 0)
        //绘制三角形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount)
        //禁止顶点数组的句柄
        GLES20.glDisableVertexAttribArray(mPositionHandle)
    }

}

你可能感兴趣的:(OpenGL ES Android 第二课 绘制三角形)