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)
    }
}

效果图

相关推荐
每次的天空3 小时前
Android学习总结之算法篇四(字符串)
android·学习·算法
x-cmd4 小时前
[250331] Paozhu 发布 1.9.0:C++ Web 框架,比肩脚本语言 | DeaDBeeF 播放器发布 1.10.0
android·linux·开发语言·c++·web·音乐播放器·脚本语言
高林雨露5 小时前
Java 与 Kotlin 对比示例学习(三)
java·kotlin
lc9991025 小时前
基于kotlin native的C与kotlin互相调用
开发语言·kotlin
tangweiguo030519877 小时前
Android BottomNavigationView 完全自定义指南:图标、文字颜色与选中状态
android
遥不可及zzz8 小时前
Android 应用程序包的 adb 命令
android·adb
无知的前端8 小时前
Flutter 一文精通Isolate,使用场景以及示例
android·flutter·性能优化
_一条咸鱼_8 小时前
Android Compose 入门之字符串与本地化深入剖析(五十三)
android
ModestCoder_9 小时前
将一个新的机器人模型导入最新版isaacLab进行训练(以unitree H1_2为例)
android·java·机器人
robin_suli10 小时前
Spring事务的传播机制
android·java·spring