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


在这里插入图片描述

相关推荐
Railshiqian16 分钟前
ubuntu常用快捷键和变量记录
android·ubuntu
等一场春雨2 小时前
window11 wsl mysql8 错误分析:1698 - Access denied for user ‘root‘@‘kong.mshome.net‘
android·kong
lichong9512 小时前
【Flutter&Dart】 拖动改变 widget 的窗口尺寸大小GestureDetector~简单实现(10 /100)
android·flutter·api·postman·smartapi·postapi·foxapi
sunly_2 小时前
Flutter:打包apk,安卓版本更新(二)
android·flutter
vincent_woo3 小时前
再学安卓 - binder之ServiceManager
android·操作系统
思忖小下4 小时前
深入Android架构(从线程到AIDL)_09 认识Android的主线程
android·thread
tmacfrank4 小时前
Coroutine 基础六 —— Flow
android·开发语言·kotlin
林鸿群4 小时前
Android Studio与Android Gradle 插件及Gradle工具匹配列表
android·ide·android studio
kandra7774 小时前
KMP最佳拍档-CMP
android·ios·kotlin
linweidong5 小时前
《Android最全面试题-Offer直通车》目录
android·校招·大厂·android面经·安卓面·社招·android简历