Android Opengl(三)绘制三角形

一、GLSurfaceView

GLSurfaceView 类提供了用于管理 EGL 上下文、在线程间通信以及与 activity 生命周期交互的辅助程序类。您无需使用 GLSurfaceView 即可使用 GLES。

例如,GLSurfaceView 会创建一个渲染线程,并在线程上配置 EGL 上下文。当 Activity 暂停时,状态将自动清除。大多数应用无需了解有关 EGL 的任何信息即可通过 GLSurfaceView 来使用GLES。

二、绘制三角形

OpenGl绘制图形的基本步

  • 使用GLSurfaceView创建OpenGl ES环境

  • 编译着色器程序(顶点着色器+片元着色器)

    创建shader对象,GLES30.glCreateShader(type)
    指定Shader源码,GLES30.glShaderSource()
    编译Shader,GLES30.glCompileShader(shader)

  • 链接OpenGL程序
    创建OpenGl程序,GLES30.glCreateProgram()
    绑定Shader到OpenGL程序,GLES30.glAttachShader()
    链接OpenGL程序,GLES30.glLinkProgram()

  • 使用OpenGL程序
    使用OpenGL程序,GLES30.glUseProgram()
    传递顶点数据
    传递片元数据

绘制三角形大体步骤

1、使用GLSurfaceView作为布局展示

2、对GLSurfaceView初始化,初始化时需要使用到GLSurfaceView.Renderer。

3、GLSurfaceView.Renderer中回调

  • onSurfaceCreated
  • onSurfaceChanged
  • onDrawFrame

在上面三个函数中进行处理绘制三角形逻辑。

1、使用GLSurfaceView作为布局展示

kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.opengl.GLSurfaceView
        android:id="@+id/glSurfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

2、对GLSurfaceView初始化,初始化时需要使用到GLSurfaceView.Renderer。

下面的代码是在Activity中的。

kotlin 复制代码
    private fun initGlSurfaceView() {
        // 设置OpenGL版本号
        glSurfaceView?.setEGLContextClientVersion(2)
        val render = DemoGlRender()
        // 设置openGl的Render
        glSurfaceView?.setRenderer(render)
        // 默认渲染方式为RENDERMODE_CONTINUOUSLY
        //  当设置为RENDERMODE_WHEN_DIRTY时只有在创建和调用requestRender()时才会刷新。
        glSurfaceView?.renderMode = RENDERMODE_WHEN_DIRTY
        //   当设置为RENDERMODE_CONTINUOUSLY时渲染器会不停地渲染场景
//        glSurfaceView?.renderMode = RENDERMODE_CONTINUOUSLY
    }

    override fun onResume() {
        super.onResume()
        glSurfaceView?.onResume()
    }

    override fun onPause() {
        super.onPause()
        glSurfaceView?.onPause()
    }

默认渲染方式为RENDERMODE_CONTINUOUSLY

  • RENDERMODE_CONTINUOUSLY模式

    当设置为RENDERMODE_CONTINUOUSLY时渲染器会不停地渲染场景,

  • RENDERMODE_WHEN_DIRTY模式

    当设置为RENDERMODE_WHEN_DIRTY时只有在创建和调用requestRender()时才会刷新。

3、GLSurfaceView.Renderer实现类中处理onSurfaceCreated、onSurfaceChanged、onDrawFrame

onSurfaceCreated:设置屏幕颜色、加载shader程序、挂载program

onDrawFrame:激活顶点坐标、绑定定点数据、绑定颜色数据、绘制

kotlin 复制代码
class DemoGlRender : GLSurfaceView.Renderer {
    /*
     * 顶点位置程序
     */
    private val vertexShaderCode =
        "attribute vec4 vPosition;" +
                "void main() { " +
                "   gl_Position = vPosition;" +
                "}"

    /**
     * 片元颜色程序
     */
    private val fragmentShaderCode =
        "precision mediump float;" +
                "uniform vec4 vColor;" +
                "void main() { " +
                "   gl_FragColor = vColor;" +
                "}"

    /**
     * 三角形顶点位置
     */
    private val triangleCoors = floatArrayOf(
        0.5f, 0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f
    )

    /**
     * 三角形颜色值
     */
    private val color = floatArrayOf(
        1.0f, 1.0f, 1.0f, 1.0f
    )

    private var program: Int? = null
    private var vertexBuffer: FloatBuffer? = null
    override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
        // 设置背景颜色
        GLES20.glClearColor(1f, 0f, 0f, 1.0f)
        // 清理缓存
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        createFloatBuffer()
        // 创建定点着色程序
        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
        // 创建片元着色程序
        val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
        if (vertexShader == 0 || fragmentShader == 0) {
            return;
        }
        linkProgram(vertexShader, fragmentShader)
    }

    private fun createFloatBuffer() {
        // 申请物理层空间
        val byteBuffer = ByteBuffer.allocateDirect(triangleCoors.size * 4).apply {
            this.order(ByteOrder.nativeOrder())
        }
        // 坐标数据转换
        vertexBuffer = byteBuffer.asFloatBuffer()
        vertexBuffer?.put(triangleCoors, 0, triangleCoors.size)
        vertexBuffer?.position(0)
    }

    private fun linkProgram(vertexShader: Int, fragmentShader: Int) {
        // 创建空的opengl es 程序
        program = GLES20.glCreateProgram()
        program?.let {
            // 将顶点着色器加入程序
            GLES20.glAttachShader(it, vertexShader)
            // 将片元着色器加入程序
            GLES20.glAttachShader(it, fragmentShader)
            // 链接到着色器程序
            GLES20.glLinkProgram(it)
            // 将程序加入到opengl30环境中
            GLES20.glUseProgram(it)
            val info = GLES20.glGetProgramInfoLog(it)
            // 打印链接程序日志
            Log.e("wdf", "info==" + info)
        }
    }


    override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {
        // 设置绘制窗口
        GLES20.glViewport(0, 0, width, height)
    }

    override fun onDrawFrame(p0: GL10?) {
        program ?: return
        if (program == 0) {
            return
        }
        program?.let {
            GLES20.glClear(GLES30.GL_COLOR_BUFFER_BIT)
            GLES20.glUseProgram(it)
            // 获取顶点着色器的vPosition,与程序中声明vPosition变量名保持一致
            val vPosition = GLES20.glGetAttribLocation(it, "vPosition")
            GLES20.glEnableVertexAttribArray(vPosition)
            // 3*4是指  跨3个读下一个顶点
            GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 3 * 4, vertexBuffer)
            // 设置三角形颜色,与程序中声明vColor变量名保持一致
            val vColor = GLES20.glGetUniformLocation(it, "vColor")
            GLES20.glUniform4fv(vColor, 1, color, 0)
            // 绘制
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3)
            GLES20.glDisableVertexAttribArray(vPosition)
        }
    }


    /**
     * 创建shader,加载shader程序
     */
    private fun loadShader(type: Int, shaderCode: String): Int {
        val shader = GLES20.glCreateShader(type)
        GLES20.glShaderSource(shader, shaderCode)
        GLES20.glCompileShader(shader)
        return shader
    }

}

三、为什么要给GLSurfaceView设置GLSurfaceView.Renderer


在这里插入图片描述

相关推荐
阿巴斯甜9 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker9 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952710 小时前
Andorid Google 登录接入文档
android
黄林晴12 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android