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

效果图

相关推荐
雨白5 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹6 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空8 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭8 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日9 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安9 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑9 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟14 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡15 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0015 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体