当前位置: 首页 > news >正文

OpenGL ES->GLSurfaceView绘制图形的流程

自定义View代码

class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs), GLSurfaceView.Renderer {var mProgrem = 0init {// 设置 OpenGL ES 3.0 版本setEGLContextClientVersion(3)// 设置当前类为渲染器, 注册回调接口的实现类setRenderer(this)// 设置渲染模式, 仅在需要重新绘制时才进行渲染,以节省资源renderMode = RENDERMODE_WHEN_DIRTY}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()// 顶点着色器代码val vertexShaderCode = """#version 300 eslayout (location = 0) in vec4 aPosition;void main() {gl_Position = aPosition;}""".trimIndent()// 片段着色器代码val fragmentShaderCode = """#version 300 esprecision mediump float;uniform vec4 vColor;out vec4 fragColor;void main() {fragColor = vColor;}""".trimIndent()// 初始化着色器mProgrem = initializeShaders(vertexShaderCode, fragmentShaderCode)}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(mProgrem)}fun initializeBuffers(){// 1. 准备菱形的顶点数据val vertices = floatArrayOf(0.0f,  0.5f, 0.0f,  // 顶点 1 (顶部)-0.5f,  0.0f, 0.0f,  // 顶点 2 (左侧)0.5f,  0.0f, 0.0f,  // 顶点 4 (右侧)0.0f, -0.5f, 0.0f   // 顶点 3 (底部))// 2. 分配顶点数据的直接字节缓冲区val vertexBuffer = ByteBuffer.allocateDirect(vertices.size * 4) // 每个 float 占 4 个字节, 指定缓冲区所需要的字节数.order(ByteOrder.nativeOrder()) // 指定字节顺序(确定是大端还是小端), 默认情况下为小端, 即低地址存放低位数据, 高地址存放高位数据.asFloatBuffer() // 转换为FloatBuffer, 因为顶点数据是float类型vertexBuffer.put(vertices) // 将顶点数据放入 FloatBuffervertexBuffer.position(0) // 在将数据放入缓冲区后,位置指针会指向缓冲区的末尾。重置位置指针为 0,使得在后续操作中可以从缓冲区的开始位置读取数据// 3. 创建顶点缓冲区对象(Vertex Buffer Object, VBO)val vbo = IntArray(1)GLES30.glGenBuffers(1, vbo, 0) // 生成一个缓冲区对象ID,并存储在数组 vbo 中,存放位置为0GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0]) // 绑定生成的顶点缓冲区对象,使其成为当前缓冲区操作的目标// 4. 将顶点数据复制到缓冲区中GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vertices.size * 4, FloatBuffer.wrap(vertices), GLES30.GL_STATIC_DRAW)}fun drawSomething(program : Int){// 8. 获取顶点数据的位置, 并使用该位置的数据val positionHandle = GLES30.glGetAttribLocation(program, "aPosition")GLES30.glEnableVertexAttribArray(positionHandle)GLES30.glVertexAttribPointer(positionHandle, 3, GLES30.GL_FLOAT, false, 0, 0)// 9. 设置片段着色器的颜色val colorHandle = GLES30.glGetUniformLocation(program, "vColor")GLES30.glUniform4f(colorHandle, 1.0f, 0.0f, 0.0f, 1.0f) // 红色// 10. 绘制菱形GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4)// 11. 禁用顶点数据GLES30.glDisableVertexAttribArray(positionHandle)}fun initializeShaders(vertexShaderCode: String, fragmentShaderCode: String) : Int {// 5. 创建和编译顶点着色器程序val vertexShader = GLES30.glCreateShader(GLES30.GL_VERTEX_SHADER)GLES30.glShaderSource(vertexShader, vertexShaderCode)GLES30.glCompileShader(vertexShader)// 6. 创建和编译片段着色器程序val fragmentShader = GLES30.glCreateShader(GLES30.GL_FRAGMENT_SHADER)GLES30.glShaderSource(fragmentShader, fragmentShaderCode)GLES30.glCompileShader(fragmentShader)// 7. 创建着色器程序, 将顶点着色器和片段着色器链接到一起val program = GLES30.glCreateProgram()GLES30.glAttachShader(program, vertexShader)GLES30.glAttachShader(program, fragmentShader)GLES30.glLinkProgram(program)GLES30.glUseProgram(program)return program}
}

总结

    1. 准备菱形的顶点数据:需要绘制的顶点数据存放在Float的数组中
    1. 分配顶点数据的直接字节缓冲区,使用 ByteBuffer 直接与底层硬件进行数据传输,避免了不必要的内存拷贝,从而提高性能
    • 常见内存拷贝图
      +--------------+          +--------------+          +--------------+
      |   float[]    |  ---->   |  FloatBuffer |  ---->   |    GPU       |
      |  (Java Heap) |          |  (Java Heap) |          |   (Native)   |
      +--------------+          +--------------+          +--------------+
      
    • 使用 ByteBuffer
      +--------------+          +--------------+          +--------------+
      |   float[]    |  ---->   | ByteBuffer   |  ---->   |    GPU       |
      |  (Java Heap) |          | (Direct)     |          |   (Native)   |
      +--------------+          +--------------+          +--------------+
      
    1. 创建顶点缓冲区对象(Vertex Buffer Object, VBO)
    1. 将顶点数据复制到缓冲区中
    1. 创建和编译顶点着色器程序
      // 定义顶点着色器代码的多行字符串
      val vertexShaderCode = """#version 300 es                // 指定使用 OpenGL ES 3.0 版本layout (location = 0) in vec4 aPosition;  // 定义输入变量 aPosition,并指定其位置为 0void main() {                  // 主函数gl_Position = aPosition;   // 将输入的顶点位置赋值给 gl_Position,进行顶点变换}
      """.trimIndent()                   // 去除多行字符串的公共缩进
      
    1. 创建和编译片段着色器程序
      // 定义片段着色器代码的多行字符串
      val fragmentShaderCode = """#version 300 es                  // 指定使用 OpenGL ES 3.0 版本precision mediump float;         // 设置默认的浮点数精度为中等精度uniform vec4 vColor;             // 定义一个 uniform 变量 vColor,用于传递颜色out vec4 fragColor;              // 定义一个输出变量 fragColor,用于存储片段的颜色void main() {                    // 主函数fragColor = vColor;          // 将 uniform 变量 vColor 的值赋给输出变量 fragColor}
      """.trimIndent()                     // 去除多行字符串的公共缩进
      
    1. 创建着色器程序, 将顶点着色器和片段着色器链接到一起
    1. 获取顶点数据的位置, 并使用该位置的数据
    1. 设置片段着色器的颜色
    1. 绘制菱形
    1. 禁用顶点数据
+---------------------+         +-------------------+         +------------------+
| Application (Java)  |  ---->  |   OpenGL Driver   |  ---->  |      GPU         |
+---------------------+         +-------------------+         +------------------+
| float[] vertices    |         |   Bind VBO        |         |  Process VBO     |
|                     |         |   Upload Data     |         |  Use Data        |
+---------------------+         +-------------------+         +------------------+
http://www.lryc.cn/news/420378.html

相关文章:

  • Linux OOM Killer详解
  • 2024rk(案例二)
  • 小红书爆文秘籍:ChatGPT助你从0到1创造热门内容!
  • django快速实现个人博客(附源码)
  • K8s部署篇之手动部署二进制高可用集群架构
  • 【Unity/XLua】xlua自带教程示例分析(6)—— lua协程
  • CV目标检测概述
  • 如何在notebook中运行nodejs
  • Mybatis学习-day19
  • IDEA构建SpringBoot多模块项目
  • 【前端】NodeJS:nvm
  • Docker网络模式及通信
  • 类模板实现实现Qt click/hover自定义操作
  • Arco Design:引领未来的Vue 3创意先锋,一键开启高效与美感并重的Web开发之旅!
  • 【MySQL】Linux下用C/C++链接MySQL数据库
  • Python金融量化专栏简介
  • 出行365:依托分布式数据库,让出行无忧 | OceanBase案例
  • 【C语言】位段详解
  • LVS集群实验
  • 在 Spring Boot 中使用适配器模式实现支付网关的统一接口
  • 【书生·浦语大模型实战营】第三期 入门岛作业
  • Redis的String类型常用命令总结
  • 河南萌新联赛2024第(四)场:河南理工大学
  • Linux中临时使用账号提权进行业务操作
  • lwip 3. 网线拔掉后 lwip_recvfrom不能返回
  • Linux环境安装Docker Engine
  • 大厂面试题分享
  • FPGA面试问题整理
  • 3Done学习笔记
  • AI学习指南深度学习篇-卷积层详解