OpenGL ES->GLSurfaceView着色器程序中传递顶点数组和颜色数组绘制渐变三角形

自定义View代码

kotlin 复制代码
class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {
    init {
        // 设置 OpenGL ES 3.0 版本
        setEGLContextClientVersion(3)
        // 设置当前类为渲染器, 注册回调接口的实现类
        setRenderer(MyRenderer())
        // 设置渲染模式, 仅在需要重新绘制时才进行渲染,以节省资源
        renderMode = RENDERMODE_WHEN_DIRTY
    }
}

自定义Renderer渲染代码

kotlin 复制代码
class MyRenderer : GLSurfaceView.Renderer {
    private var mProgram = 0
    private var vbo = IntArray(2)  // 顶点缓冲区对象,需要存储位置数组,颜色数组
    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        // 当 Surface 创建时调用, 进行 OpenGL ES 环境的初始化操作, 设置清屏颜色为黑色 (Red=0, Green=0, Blue=0, Alpha=1)
        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)

        // 准备数据和缓存区,创建缓冲区对象并绑定数组对象
        initializeBuffers()

        // 创建并编译着色器程序
        mProgram = initializeShaders()
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        // 当 Surface 尺寸发生变化时调用,例如设备的屏幕方向发生改变, 设置视口为新的尺寸,视口是指渲染区域的大小
        GLES30.glViewport(0, 0, width, height)
    }

    override fun onDrawFrame(gl: GL10?) {
        // 每一帧绘制时调用, 清除颜色缓冲区和深度缓冲区
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)
        // 绘制图形
        drawSomething(mProgram)
    }

    private fun initializeBuffers() {
        // 顶点数据
        val vertices = floatArrayOf(
            0.0f, 0.5f, 0.0f,  // 顶点 1 (顶部)
            -0.5f, 0.0f, 0.0f,  // 顶点 2 (左侧)
            0.5f, 0.0f, 0.0f   // 顶点 3 (右侧)
        )

        // 颜色数据
        val colors = floatArrayOf(
            1.0f, 0.0f, 0.0f,  // 顶点 1 的颜色 (红色)
            0.0f, 1.0f, 0.0f,  // 顶点 2 的颜色 (绿色)
            0.0f, 0.0f, 1.0f  // 顶点 3 的颜色 (蓝色)
        )

        // 分配顶点数据的缓冲区
        val vertexBuffer = ByteBuffer.allocateDirect(vertices.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(vertices)
            .position(0)

        // 分配颜色数据的缓冲区
        val colorBuffer = ByteBuffer.allocateDirect(colors.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(colors)
            .position(0)

        // 创建顶点缓冲区对象并绑定
        GLES30.glGenBuffers(2, vbo, 0)
        // 下面两个GLES30.glBindBuffer方法的调用
        // 目的是将顶点数据和颜色数据上传到 GPU,并存储在缓冲区对象中,这个操作通常只需要执行一次,除非你需要更新缓冲区中的数据
        // 绑定顶点缓冲区对象
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0])
        GLES30.glBufferData(
            GLES30.GL_ARRAY_BUFFER,
            vertices.size * 4,
            vertexBuffer,
            GLES30.GL_STATIC_DRAW
        )

        // 绑定颜色缓冲区对象
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[1])
        GLES30.glBufferData(
            GLES30.GL_ARRAY_BUFFER,
            colors.size * 4,
            colorBuffer,
            GLES30.GL_STATIC_DRAW
        )
    }

    // 准备着色器程序
    private fun initializeShaders(): Int {
        // 顶点着色器代码
        val vertexShaderCode = """#version 300 es
                layout (location = 0) in vec4 aPosition; // 输入顶点位置
                layout (location = 1) in vec4 aColor; // 输入顶点颜色
                out vec4 vColor; // 临时变量, 用于传递顶点颜色
                
                void main() {
                  gl_Position = aPosition; // 输出顶点位置
                  vColor = aColor; // 输出顶点颜色
                }""".trimIndent()

        // 片段着色器代码
        val fragmentShaderCode = """#version 300 es
                precision mediump float; // 指定浮点精度
                in vec4 vColor; // 输入顶点颜色
                out vec4 fragColor; // 输出片段颜色
                
                void main() {
                  fragColor = vColor; // 输出片段颜色
                }""".trimIndent()

        // 创建和编译顶点着色器程序
        val vertexShader = GLES30.glCreateShader(GLES30.GL_VERTEX_SHADER)
        GLES30.glShaderSource(vertexShader, vertexShaderCode)
        GLES30.glCompileShader(vertexShader)

        // 创建和编译片段着色器程序
        val fragmentShader = GLES30.glCreateShader(GLES30.GL_FRAGMENT_SHADER)
        GLES30.glShaderSource(fragmentShader, fragmentShaderCode)
        GLES30.glCompileShader(fragmentShader)

        // 创建着色器程序, 将顶点着色器和片段着色器链接到一起
        val program = GLES30.glCreateProgram()
        GLES30.glAttachShader(program, vertexShader)
        GLES30.glAttachShader(program, fragmentShader)
        GLES30.glLinkProgram(program)
        return program
    }

    fun drawSomething(program: Int) {
        GLES30.glUseProgram(program)
        // 下面两个GLES30.glBindBuffer方法的调用
        // 目的是在绘制时确保使用正确的缓冲区对象。每次绘制时,你都需要告诉 OpenGL ES 使用哪个缓冲区对象,这样它才能从这些缓冲区中读取数据进行绘制
        // 绑定顶点缓冲区对象
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0])
        val positionHandle = GLES30.glGetAttribLocation(program, "aPosition")
        GLES30.glEnableVertexAttribArray(positionHandle)
        GLES30.glVertexAttribPointer(positionHandle, 3, GLES30.GL_FLOAT, false, 0, 0)

        // 绑定颜色缓冲区对象
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[1])
        val colorHandle = GLES30.glGetAttribLocation(program, "aColor")
        GLES30.glEnableVertexAttribArray(colorHandle)
        GLES30.glVertexAttribPointer(colorHandle, 3, GLES30.GL_FLOAT, false, 0, 0)

        // 绘制
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3)

        // 禁用顶点数据
        GLES30.glDisableVertexAttribArray(positionHandle)
        GLES30.glDisableVertexAttribArray(colorHandle)
    }
}

效果图

相关推荐
Dingdangr3 小时前
Android中的Intent的作用
android
技术无疆3 小时前
快速开发与维护:探索 AndroidAnnotations
android·java·android studio·android-studio·androidx·代码注入
GEEKVIP3 小时前
Android 恢复挑战和解决方案:如何从 Android 设备恢复删除的文件
android·笔记·安全·macos·智能手机·电脑·笔记本电脑
Jouzzy10 小时前
【Android安全】Ubuntu 16.04安装GDB和GEF
android·ubuntu·gdb
极客先躯10 小时前
java和kotlin 可以同时运行吗
android·java·开发语言·kotlin·同时运行
茜茜西西CeCe13 小时前
移动技术开发:登录注册界面
java·gitee·gradle·android studio·安卓·移动技术开发·原生安卓开发
Good_tea_h13 小时前
Android中的单例模式
android·单例模式
计算机源码社18 小时前
分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)
android·微信小程序·uni-app·毕业设计项目·毕业设计源码·计算机课程设计·计算机毕业设计开题
丶白泽18 小时前
重修设计模式-结构型-门面模式
android
晨春计20 小时前
【git】
android·linux·git