Android OpenGL ES 知识总览1

OpenGL ES是在Android, iOS等移动平台上使用的3D图形绘制引擎,其本身是一套API标准,khronos组织负责这套API的设计规范,具体实现交由硬件厂商、模拟器厂商与操作系统厂商来完成,只要求符合其API标准的要求,就可以在不同的硬件上使用相同的API来达到平台一致的显示要求。

图形处理器GPU

图形处理器是用于对图形图像进行处理和输出显示的一种专门用途的芯片,一般它代表着计算机上的高性能/并行性/群核等等特征,以及厂商差异性,OpenGL/OpenGL ES就是用来统一所有GPU厂商对操作系统和应用程序厂商的一个统一图形接口规范体系,基本上对于现在所有PC设备与移动设备无不支持OpenGL标准。
同时我们可以在支持OpenGL ES移动设备上使用EGL接口层,使得我们可以在本地应用层面上使用EGL接口进行窗口应用开发。让窗口图形应用开发更简便,我们可以将不限于Android的各个平台的OpenGL ES与本地窗口的接口操作API都看作EGL接口,一般来说EGL接口都会提供一个rendering context API提供给我们使用。

相关新闻:Firefox将会在Linux平台上迁移到EGL接口
http://www.linuxeden.com/a/92972

着色器(Shaders)

什么是着色器?

着色器就是OpenGL用于指定界面绘制元素的一系列属性和方法的一种控制屏幕上的像素的程序,这个程序运行在不同厂商的GPU处理器或者模拟处理程序中,它控制着每个像素的颜色、位置、以及其他的高级形态等等,我们不能编写直接运行在不同GPU上的通用程序,但是我们通过着色器脚本GLSL(GL Shading Language),通过操作系统驱动层传入到OpenGL驱动,通过pipeline对脚本进行编译链接与使用。

OpenGL ES绘制流程

API
顶点数组/缓冲对象
顶点着色器
图元装配
光栅化
片元着色器
帧缓冲

OpenGL ES着色器绘制流程

GLSL
OpenGL编译
图元装配
光栅化
帧缓冲

在Android上使用OpenGL ES 2.0

在Android上原生支持OpenGL 1.0, 2.0, 3.0, 3.1等版本,我们以2.0为例。
要在Android上使用OpenGL首先需要在清单文件中指明应用程序本身要用到的OpenGL版本,

 <uses-feature android:glEsVersion="0x00020000" android:required="true" />

我们需要在我们的Activitiy 中定义一个GLSurfaceView 来显示我们的GL内容并为之交互。
我们需要一个GLSurfaceView实例来显示OpenGL的内容

//activity要传入Activity自身的context实例
GLSurfaceView glSurfaceView = new GLSurfaceView(activity);

并且设置

//设置版本号为2
glSurfaceView.setEGLContextClientVersion(2);
//按需渲染,节能减排
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
glSurfaceView.setRenderer(new MyRenderer(this));

上面我们对用于展示OpenGL ES的GLSurfaceView就算设置完成了。

我们需要对一个类进行实现,定义为内部类也好或者定义一个类实现其接口也好,MyRenderer类将会是GLSurfaceView.Renderer的接口实现。

    public interface Renderer {
        void onSurfaceCreated(GL10 gl, EGLConfig config);
        void onSurfaceChanged(GL10 gl, int width, int height);
        void onDrawFrame(GL10 gl);
    }

onSurfaceCreated方法用于当OpenGL的Surface被创建时要执行的动作,
onSurfaceChanged方法用于Surface大小发生变更时要执行的动作,在这个方法中一般会对视口大小进行调整,通过执行gl.glViewport(0, 0, width, height);方法来实现。
onDrawFrame方法用于绘制每一帧时对画面状态的一个更新和绘制。这个过程是更新pipeline告知OpenGL绘制流程的过程。一般伴有gl.glClear(GL10.GL_COLOR_BUFFER_BIT); 开头,对整个画布进行清理初始化。

MyRenderer作为Renderer的子类,我们的目标就是要实现这三个函数来实现对内容的绘制。

OpenGL ES的坐标系统

OpenGL ES的坐标系统既不是左上角为原点,也不是以左下角为原点,而是以屏幕中央为原点,无论屏幕大小如何,屏幕从左到右和从上到下的范围都是 ( − 1 , 1 ) (-1,1) (1,1),是以屏幕中心为原点 ( 0 , 0 ) (0,0) (0,0)的笛卡尔坐标系。
左上角 ( − 1 , 1 ) (-1,1) (1,1),右上角 ( 1 , 1 ) (1,1) (1,1)
左下角 ( − 1 , − 1 ) (-1,-1) (1,1),右下角 ( 1 , − 1 ) (1,-1) (1,1)

Vertex Shader 顶点着色器

定一个顶点着色器需要以下几种定义的数据:

  • 属性量(attribute):使用顶点数组提供的每个顶点数据的定义
  • 不变量(uniform):顶点着色器所用到的常量数据
  • 采样:采样是顶点着色器中可选的数据,通过顶点着色器定义的易总特殊的不变量格式用于表示纹理数据
  • 着色器程序:顶点着色器源码或者可执行代码描述在顶点上所有的表现。
  • 中间可变量(vary):顶点着色器所用到的中间可变量。

vary的意思是可变的,uniform的意思是一致的attribute的意思是属性

顶点着色器在GPU中的计算会有很多临时变量和可变量作为计算过程的中间量,但是最终要赋值给三个量,作为GLSL的计算结果:

  • gl_Position 定义了最终顶点着色器绘制的位置
  • gl_FrontFacing 定义了当前是正面的部分还是背面部分,绘制过程可以依据面向来计算颜色,或者其他资源型操作
  • gl_PointSize定义了点的大小

这三个内置变量都是用于着色器接受GLSL脚本的执行结果的量。
一个简单的例子:


// 顶点着色器所使用的不变量
uniform mat4 m_Matrix; 
//顶点着色器所使用的属性量
attribute vec4 a_position;
attribute vec4 a_color;
//顶点着色器所使用的的可变量,可变量也是顶点着色器输出量,可以作为其他片元着色器的输入量
varying vec4 v_color;
void  main(){
      v_color = a_color;
 	  gl_Position =  a_position;
 	  gl_PointSize = 20;
}

Fragment Shader 片段着色器/片元着色器

片段着色器又叫做片元着色器,属于不同文献书籍的翻译差异
片元着色器的GLSL也有一些常用的关键字,如下:

  • vary可变量: 由顶点着色器生成的输出可变量并且光栅化单元,每个片元使用了插值。
  • uniform 不变量:片元着色器所使用的常量
  • 采样器:一种特定类型的不变量用于表示被片元着色器使用的uniform不变量。
  • 着色器程序

这里面没有属性关键字的使用。片元着色器将会生成颜色并且交给内置变量gl_FragColor

在OpenGL ES 2.0的pipeline中,颜色、模板、深度、屏幕坐标信息都会在光栅化过程中的片元操作阶段生成。

光栅化过程

经过OpenGL在GPU中的一些对GLSL翻译处理与图元组配以后,将会对组配的数据进行光栅化过程,光栅化过程交由片元着色器阶段处理,简而言之就是GPU会将我们从SL语言描述的内容转换成图像数据渲染到GPU输出缓冲区中。

图元组配器
片元着色器阶段
线条
三角形

看个简单的片元着色器的例子:

//定义中等浮点数精度
 precision mediump float;
 varying vec4 v_color;//由顶点着色器导出的顶点颜色变量
 void main(){
       //将导入的v_color赋值给内置变量gl_FragColor
       gl_FragColor = v_color;
 }

GL Shader Language 语言

上面我已经举出了些许Shader语言脚本的个例,我们此时再看一下其语法。

Shader语法特别简单,类似C语言语法,属性和变量的格式为

[变量类型] [数据类型] [变量名]

语句都以;分号结尾

主程序也是void main {}包裹主程序体。
不同的是GLSL的结尾一定是给着色器内置变量赋值为结尾,将最终的着色器属性定义传回GPU处理。

数据传输的集装箱——FloatBuffer

浮点缓冲区类型是用于保存浮点类型的缓冲区的类,是Buffer的子类,这意味着他也有NIO当中Buffer的诸多可用的对缓冲空间的指针方法,这部分都是Buffer当中的通用函数,比如

  • capacity() 返回缓冲区容量
  • position() 返回缓冲区当前的指针位置
  • position(int newPosition) 指定缓冲区位置指针
  • limit() 返回缓冲区上限
  • limit(int newLimit) 设定新的缓冲区上限
  • mark() 设定指针标记为当前的position
  • reset() 重置到指针mark的位置
  • clear() 位置归零,上限设定为容量值,取消mark标记
  • flip() 翻转缓冲区,当前位置指针被设定为上限,当前位置归零,取消mark标记
  • rewind() 回卷,位置归零,取消mark标记
    ……
    等等关键方法,这里只列举常用的一些方法和说明。
    通过ByteBuffer方法分配直接内存,并且指定本地字节序,并且指定为FloatBuffer类型,就可以作为顶点数据缓冲区来使用了。
//分配Direct内存的大小一般是数组大小 x 数据类型长度
public static final int BYTES_PER_FLOAT = 4;
FloatBuffer  vertexData = ByteBuffer
                .allocateDirect(length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();

Android OpenGL ES API

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import static android.opengl.GLES20.*;

以上三个命名空间下的一些常用API

GL10:
API参数说明
glClearColorfloat red,green,blue,alpha初始清屏颜色
glClearint mask清屏动作glClear(GL10.GL_COLOR_BUFFER_BIT)
glViewportint x, int y, int width, int height定义视口尺寸

程序编译相关API

GLES20
API参数说明返回
glCreateShaderint type参数通过GL_VERTEX_SHADER 和GL_FRAGMENT_SHADER 选择使用哪种着色器返回着色器对象ID
glShaderSourceint shader, String glsl着色器对象ID 和 GLSL脚本
glCompileShader对指定的着色器传入代码, 参数是着色器对象ID 和glsl代码,对指定的着色器对象ID进行编译
glGetShaderivint shader, int pname, int[] params, int offset获取着色器信息: shader是着色器对象ID,pname是要获取的着色器属性 ,params参数数组,offset偏移量
glGetShaderInfoLogint shader着色器对象ID返回着色器日志
glDeleteShaderint shader特定的着色器对象ID 删除着色器
glCreateProgram创建着色器程序返回创建的程序ID
glAttachShaderint program, int shader对特定的程序ID附加着色器
glLinkProgramint program对特定的程序ID执行链接操作
glGetProgramivint program, int pname, int[] params, int offset获取程序信息 program是程序对象ID,pname是要获取的程序属性 ,params参数数组,offset偏移量
glValidateProgramint program对特定的编译好的程序ID执行验证操作
glGetProgramInfoLogint program获取程序信息日志
glUseProgramint program使用程序
glGetUniformLocationint program , int name获取指定名称的uniform变量的位置
glGetUniformLocationint program , int name获取指定名称的attribute变量的位置
glVertexAttribPointerint indx, int size, int type, boolean normalized, int stride, java.nio.Buffer ptr指定程序传入顶点属性指针: indx属性位置指针,size 位置数量, normalized是否标准化,stride,ptr数组缓冲区
glEnableVertexAttribArrayint indx启用顶点属性

着色器程序编译流程

着色器在真正被OpenGL使用并且推到FrameBuffer之前,需要对脚本进行编译

glShaderSource
glCompileShader
glCreateProgram
glAttachShader
glLinkProgram
glValidateProgram

首先需要将代码经过函数glShaderSource传入着色器程序,然后编译着色器glCompileShader,如果没有出错的话,接下来调用glCreateProgram创建着色器程序,此时程序中没有着色器,我们将着色器附着到程序上,通过glAttachShader将着色器附着到程序上,最后链接程序,我们完成了对着色器程序的编译工作,而这些工作都是在运行时完成的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值