OpenGLES应用开发实践指南Android卷-(二)定义顶点和着色器

本章介绍我们 的第一个项目:简单的空气曲棍球游戏。(不懂事什么的百度谷歌搜一搜)

1.定义空气曲棍球桌子的结构

1.1 我们可以重用第一章的项目
  • 把项目重命名为AirHockey1
  • 把FirstOpenGLProjectActivity重命名为AirHockeyActivity
  • 把FirstOpenGLProjectRenderer重命名为AirHockeyRenderer
  • 把strings.xml里的app_name修改为AirHockey
  • 把包名com.firstopenglproject.android修改为com.airhockey.android
    OpenGLES应用开发实践指南Android卷-(二)定义顶点和着色器
1.2 在代码中定义顶点

因为这些顶点定义在二维二维坐标系中,所以每个顶点要用两个浮点数进行标记:一个标记x轴的位置,另外一个标记y轴的位置。
因为一个顶点有两个分量,.所以首先创建一个常量用来记住这一事实;打开AirHockeyRenderer类,并在它的顶端加入如下常量:
OpenGLES应用开发实践指南Android卷-(二)定义顶点和着色器
在onSurfaceCreated()的前面加入如下构造函数
OpenGLES应用开发实践指南Android卷-(二)定义顶点和着色器

2.使数据可以被OpenGL存取

在AirHockeyRenderer类的顶部,构造函数之前加入如下代码:
OpenGLES应用开发实践指南Android卷-(二)定义顶点和着色器
那个FloatBuffer用来在本地内存中存储数据

在构造函数体的结尾处加入如下代码:
OpenGLES应用开发实践指南Android卷-(二)定义顶点和着色器

  • ByteBuffer.allocateDirect()分配了一块本地内存,这块内存不会被垃圾回收器回收管理。因为顶点都存储在一个浮点数组里,并且每个浮点数有4个字节,所以这块内存的大小应该是tableVerticesWithTriangles.length * BYTES_PER_FLOAT。
  • 下一行order(ByteOrder.nativeOrder())告诉字节缓冲区(byte buffer)按照本地字节序(native byte order)组织它的内容;
  • 我们不愿意直接操作单独的字节,而是希望使用浮点数。所以调用asFloatBuffer()得到一个可以反映底层字节的FloatBuffer类实例;
  • 然后就可以调用vertexData.put(tableVerticesWithTriangles)把数据从Dalvik的内存复制到本地内存了。当进程结束的时候,这块内存就会被释放掉,所以我们一般不用关心她。

3.引入OpenGL管道

我们定义了曲棍球桌子的结构,并且把这些数据复制到了OpenGL可以存取的本地内存;把曲棍球桌子画到屏幕上之前,她需要在OpenGL的管道(pipeline)中传递,这就需要使用称为着色器(shader)的子例程。这些着色器会告诉图形处理单元(GPU)如何绘制数据。有两种着色器,在绘制任何内容到屏幕之前需要定义她们。

  1. 顶点着色器(vertex shader)生成每个顶点的最终位置,针对每个顶点,他都会执行一次;一旦最终位置确定了,OpenGL就可以把这些可见的顶点的集合组装成点、直线以及三角形。
  2. 片段着色器(fragment shader)为组成点、直线或者三角形的每个片段生成最终的颜色,针对每个片段,它都会执行一次;一个片段是一个小的、单一的颜色的长方形区域,类似于计算机屏幕上的一个像素。

一旦最后的颜色生成了,OpenGL就会把它们写到一块称为帧缓冲区(frame buffer)的内存块中,然后,android会把这个帧缓冲区显示到屏幕上。

3.1 创建第一个顶点着色器simple_vertex_shader.glsl

OpenGLES应用开发实践指南Android卷-(二)定义顶点和着色器

3.2 创建第一个片段着色器simple_fragment_shader.glsl

OpenGLES应用开发实践指南Android卷-(二)定义顶点和着色器

4.小结

  • 首先,我们学习了如何定义一个顶点属性数组,并把这个数组复制到本地内存里,以便OpenGL存取她。
  • 然后,我们写了一个顶点着色器和一个片段着色器;并了解到一个着色器只是可以运行在GPU上的一个特殊类型的程序。