Learn OpenGLES:画三角形

本文介绍了如何使用OpenGL将CPU中的三角形数据传输到GPU,并通过顶点和片段着色器进行处理,展示了OpenGL图形管线的基本流程。通过创建顶点缓冲区、编写顶点和片段着色器,最终实现颜色渐变动画的三角形渲染。
摘要由CSDN通过智能技术生成
上一贴我们简单的搭建了一个OpenGL的运行窗口,也简单的对这个窗口进行绘制。 
这一贴,我们将介绍OpenGL如何将CPU中的内存数据送到GPU的内存中,Shader又是如何找到这些数据,并进行绘制的。
我们将通过绘制三角形这一简单的例子,为大家简单的介绍下OpenGL的管线流程,以及如何渲染颜色,颜色渐变动画等知识。

#介绍OpenGL的管线
Opengl 中所有的事物,都是由点来表示的,而这些点又是由3D坐标表示的。但是最终要在屏幕或窗口中显示的是2D画面,这也就是说Opengl一大部分的工作是 如何将3D 坐标变换为2D坐标,Opengl中 有一个 图形管线(graphics pipeline)来专门处理这一过程。 图形流程可以分为两部分:一, 将3d坐标转换为2d坐标;二,将2d坐标变换为实际的彩色像素。

图形流程一般以 一列3D坐标(物体模型的顶点)作为输入,然后生成新的顶点,并通过对顶点位置属性的空间变换,对颜色属性的灯光变换,再将其转为2D坐标,最终渲染为2D彩色图形。这一过程 可分为多个步骤,而每一步骤都是以上一步的输出为输入。 在Opengl中,每一步都被高度定制(简单的由一个API表示)。 这所有的步骤之间可以并行执行。多数显卡都有数千个小的处理单元(processing cores),通过在GPU中运行小的工程从而使得图形流程可以很快处理数据 。这些小的工程被称为着色器(shaders)。

有些着色器是可以供开发者配置,通过编写这些着色器可以替换opengl里默认的着色器, 从而可以使得开发者细致的掌控流程中一些特定的部分。 OpenGL为我们提供了GLSL语言,该语言除了简单的基本类型(类C)外,都是一些抽象的函数实现,而这些函数实现的算法都集成到了GPU中,从而大大的节省了CPU的运行时间。


下图简单的描述了图形管线的处理步骤:


如何由顶点再到最后的渲染成像一目了然。 这里面,最重要的两个就是顶点着色(Vertex Shader) 和 片段着色(Fragment Shader), 由于OpenGL 2.0以后,接口编程的开放,这两个就需要用户自己定制,而其他的在一般情况下可保持默认。

# 顶点由CPU到GPU
 在MyGLRenderer里, 创建一个构造函数,定义三角形的顶点数据:
 
1
2
3
4
5
6
float []  verticesWithTriangle =
  {
       0f, 0f,
       5f, 5f,
       10f, 0f  
}

 一般在Java中的数据,是由虚拟机为其分配好内存的,因此这一步还不能让CPU真正获取我们所定义的数据,并将数据传递给GPU,
好在Java为我们提供了Buffer这样的对象, 它可以直接在Native层分配内存,以让CPU获取。 在Java中,一个浮点型是4字节,因此,我们可定义BYTES_PER_FLOAT = 4,并有
1
2
vertexData = ByteBuffer.allocateDirect(tableVerticesWithTriangles.length*BYTES_PER_FLOAT)
    .order(ByteOrder.nativeOrder()).asFloatBuffer();
在这里,我么将分配好的字节按nativeOrder进行排序,这样在大小端机器上都能适用。

CPU的数据是要送到GPU供Shader使用的,因此,我们需要在Shader中制定顶点的属性
首先,在Android工程目录, res下面创建一个raw文件夹,并创建vertexShader.glsl
1
2
3
4
5
6
7
// vertex shader
attribute vec4 a_Position;
               
void  main()
{
     gl_Position = a_Position;
}
上面我们只定义了顶点的位置属性, 因此,我们只声明 一个位置属性。 vec4是一个四维数组,如果我们没有为其分配数据,它将自动填充0, 0, 0, 1。 在vertexShader, 最终OpenGL 会将输入的顶点位置赋值给gl_Position 进行输出。

接着,我们定义fragmentShader.glsl
1
2
3
4
5
6
7
8
//fragShader
precision mediump  float ;
uniform vec4 u_Color;
               
void  main()
{
     gl_FragColor = u_Color;
}

第一句定义了数据的精度,就像java语言的double, float类型一样。   highp就像double代表了高精度,因其效率不高,只用于有限的几个操作。我们只需用mediump即可。 然后,定义了一个 uniform颜色变量, 一般uniform变量在shader中不会有太大变化。 最后,将颜色赋值给gl_FragColor, 完成最后的颜色输出。
gl_Position 和 gl_FragColor 都是OpenGL的内置变量。

# 链接着色器到工程中
  为了能够让Opengl能够使用这些着色器,还需要对这些着色器进行编译,以便能够在运行时使用它们。
 第一件事,就是创建一个 着色器工程(Shader Program ):
首先,我们需要将Shader的代码,读到一个字符串中。在我们package下,创建一个TexResourceRender.java
里面写上如下函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public  static  String readTextFromResource(Context context,  int  resourceId)
     {
         StringBuilder body =  new  StringBuilder();
               
         try {
             InputStream inputStream = context.getResources().openRawResource(resourceId);
               
             InputStreamReader inputStreamReader =  new  InputStreamReader(inputStream);
             BufferedReader bufferedReader =  new  BufferedReader(inputStreamReader);
               
             String nextLine;
               
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值