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

效果图

相关推荐
JavaNoober1 分钟前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
王六岁16 分钟前
UIAutomatorViewer 安装指南 (macOS m3pro 芯片)
android studio
城东米粉儿44 分钟前
关于ObjectAnimator
android
zhangphil2 小时前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我3 小时前
从头写一个自己的app
android·前端·flutter
饕餮争锋3 小时前
Kotlin: [Internal Error] java.lang.NoSuchFieldError: FILE_HASHING_STRATEGY
java·kotlin
lichong9514 小时前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端
用户69371750013844 小时前
14.Kotlin 类:类的形态(一):抽象类 (Abstract Class)
android·后端·kotlin
火柴就是我4 小时前
NekoBoxForAndroid 编译libcore.aar
android
Kaede65 小时前
MySQL中如何使用命令行修改root密码
android·mysql·adb