OpenGL ES->GLSurfaceView绘制图形的流程
创始人
2024-11-04 05:36:17
0

自定义View代码

class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs), GLSurfaceView.Renderer {     var mProgrem = 0     init {         // 设置 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 es                                 layout (location = 0) in vec4 aPosition;                                                                  void main() {                                   gl_Position = aPosition;                                 }""".trimIndent()          // 片段着色器代码         val fragmentShaderCode = """#version 300 es                 precision 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) // 将顶点数据放入 FloatBuffer         vertexBuffer.position(0) // 在将数据放入缓冲区后,位置指针会指向缓冲区的末尾。重置位置指针为 0,使得在后续操作中可以从缓冲区的开始位置读取数据          // 3. 创建顶点缓冲区对象(Vertex Buffer Object, VBO)         val vbo = IntArray(1)         GLES30.glGenBuffers(1, vbo, 0) // 生成一个缓冲区对象ID,并存储在数组 vbo 中,存放位置为0         GLES30.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,并指定其位置为 0      void 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        | +---------------------+         +-------------------+         +------------------+ 

相关内容

热门资讯

技巧辅助挂!pokermast... 技巧辅助挂!pokermaster修改器,丹东约战麻将辅助器,演示教程(有挂细节)1、点击下载安装,...
现场直击!wepokerplu... 现场直击!wepokerplus万能挂,丰城双剑新版最强高分攻略,操作教程(有挂方针)1.丰城双剑新...
插件辅助挂!wepoker有辅... 插件辅助挂!wepoker有辅助器吗,乐平包王攻略,学习教程(有挂方略)1、首先打开乐平包王攻略辅助...
据玩家消息!拱趴大菠萝辅助神器... 据玩家消息!拱趴大菠萝辅助神器,多乐跑得快辅助器,机巧教程(证实有挂)1、在拱趴大菠萝辅助神器插件功...
此事备受玩家关注!来玩app破... 此事备受玩家关注!来玩app破解版,h5能反杀吗,绝活教程(有挂详细)1、打开软件启动之后找到中间准...
值得注意的是!aapoker破... 值得注意的是!aapoker破解侠是真的吗,蜀山四川游戏修改工具,经验教程(有挂助手)1、金币登录送...
第三方辅助!wepoker脚本... 第三方辅助!wepoker脚本,广东星悦有外开挂辅助器吗,法门教程(有挂分析)广东星悦有外开挂辅助器...
此事引发广泛关注!德州透视脚本... 此事引发广泛关注!德州透视脚本,崇阳斗棋辅助脚本视频,诀窍教程(的确有挂)暗藏猫腻,小编详细说明崇阳...
黑科技辅助挂!wepoker买... 黑科技辅助挂!wepoker买脚本靠谱吗,情怀七喜游戏辅助,法门教程(有挂方法)1、每一步都需要思考...
方法辅助挂!aapoker怎么... 方法辅助挂!aapoker怎么设置提高好牌几率,蘑菇云辅助使用视频,绝活儿教程(讲解有挂)1、完成蘑...