首先搞懂两个概念
OpenGL(Open Graphics Library,译名:开放图形库或者“开放式图形库”),是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API),这个接口由近350个不同的函数调用组成,用来绘制从简单的图形比特到复杂的三维景象。OpenGL常用于CAD、虚拟现实、科学可视化程序和电子游戏开发。(更详细的介绍可以去看看百度百科)
OpenGL ES(OpenGL for Embedded Systems)是 OpenGL 三维图形API的子集,针对手机、PDA和游戏主机等嵌入式设备而设计,也可以称OpenGL ES是OpenGL针对移动或嵌入式设备的阉割版,各显卡制造商和系统制造商来实现这组 API。我们用的android,ios手机支持都是OpenGL ES。
OpenGL ES在android中的应用场景我了解的有以下几方面:
1.一些三维模型模型的操作
2.游戏的开发
3.android相机的开发,比如加一些特殊的东西或是特殊模式的相机的开发比如黑白化,美白化等。
在学习openGL ES时有几个专业的术语需要了解
几何图元:openGL ES能绘制的基本图像,只支持点、线、三角形三种几何图元
模型:根据几何图元创建的物体
渲染:根据模型创建图像过程
openGL ES具体操作步骤
1、指定几何图元:根据指令绘制几何图元
2、顶点处理:根据模型视图和投影矩阵进行变换来改变顶点的位置,根据纹理坐标与纹理矩阵来改变纹理坐标的位置,如果涉及三维的渲染,那么这里还要处理光照计算和法线变换
3、图元组装:将规则将图元组装起来
4、格栅化操作:将图元数据分解成更小的单元并对应于帧缓冲区的各个像素。这些单元称为片元
5、片元处理:根据业务操作(比如提亮、色度饱和调节,高斯模糊)来获得片元的像素值。
6,帧缓冲操作:将处理好的模型写入缓冲区,准备呈现,缓冲类似于普通的Android双缓冲
其实openGL ES操作模型很像是搭积木,只是积木的组成是一个个小三角形,将一个个的三角形拼成我们想要的样子。
Android 1.0 开始支持 OpenGL ES 1.0 及 1.1。Android 2.2 开始支持 OpenGL ES 2.0。Android 4.3 开始支持 OpenGL ES 3.0。Android 5.0 开始支持 OpenGL ES 3.1。这里需注意OpenGL ES 3.x都向下兼容OpenGL ES 2.0,OpenGL ES 2.0是不向下兼容OpenGL ES 1.0。目前Android设备大部分都是Android 4.4,所以我们在开发时可以选择针对OpenGL ES 2.0进行开发。下面是判断设备是否支持OpenGL ES 2.0代码
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);boolean supportsEs2 = activityManager.getDeviceConfigurationInfo().reqGlEsVersion >= 0x20000||(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)&&(Build.FINGERPRINT.startsWith(\"generic\"))|| Build.FINGERPRINT.startsWith(\"unknow\")|| Build.MODEL.contains(\"google_sdk\")|| Build.MODEL.contains(\"Emulator\")|| Build.MODEL.contains(\"Android SDK built for x86\");``
OpenGL ES只是在管理和计算要渲染的模型的图元、纹理信息、编译好的着色器等内容,并不参与实际的绘制或是说窗口的操作,所以android中有了一个连接opengl与Android绘制窗口的桥梁EGL。不同平台窗口和openGL的中间连接桥梁可能是不同的,像ios中间连接桥梁是EAGL。
android,ios都OpenGL ES初始化环境是不同的,Android使用EGL,iOS使用EAGL,所以虽然OpenGL ES跨平台,也不能像其他的开源框架ios和android用同一套c或c++代码编写。
Android GLSurfaceView就是一个搭建好了EGL环境我们可以直接用作OpenGL ES操作的View,里面还有一个Renderer接口,查看注释里面有一行A generic renderer interface翻译就是一个通用的渲染接口,就是用于绘制界面的线程,里面有三个函数onSurfaceCreated(里面注释Called when the surface is created or recreated(在创建或重新创建曲面时调用,可以理解为进一次GLSurfaceView所在界面就会被调用一次,注释还有一句be lost when the Android device awakes after going to sleep.当安卓设备在进入睡眠状态后醒来时会迷失方向。)),onSurfaceChanged(里面注释Called when the surface changed size.(当曲面更改大小时调用)),onDrawFrame(里面注释Called to draw the current frame.(调用以绘制当前帧),每次从缓冲区拿数据进行绘制都会调用此方法)。下面参照google的文档简单绘制的一个四边形。
因为opengl es基本图元只有点、线、三角形,绘制一个四边形则需要拆为两个三角形绘制如下图
点的坐标为:
static float squareCoords[] = {-0.5f, 0.5f, 0.0f, // top left-0.5f, -0.5f, 0.0f, // bottom left0.5f, -0.5f, 0.0f, // bottom right0.5f, 0.5f, 0.0f }; // top right
绘制点的顺序是:
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
首先我们创建一个四边形模型,为了最大限度地提高工作效率,将点坐标和绘制点的顺序写入 ByteBuffer传递到 OpenGL ES 图形管道进行处理。
ByteBuffer bb = ByteBuffer.allocateDirect(// (# of coordinate values * 4 bytes per float)squareCoords.length * 4);bb.order(ByteOrder.nativeOrder());vertexBuffer = bb.asFloatBuffer();vertexBuffer.put(squareCoords);vertexBuffer.position(0);// initialize byte buffer for the draw listByteBuffer dlb = ByteBuffer.allocateDirect(// (# of coordinate values * 2 bytes per short)drawOrder.length * 2);dlb.order(ByteOrder.nativeOrder());drawListBuffer = dlb.asShortBuffer();drawListBuffer.put(drawOrder);drawListBuffer.position(0);
另外再介绍两个概念
Vertex Shader(顶点着色器)用来替换顶点处理阶段。
Fragment Shader(片元着色器,又称像素着色器)用来替换片元处理阶段。
再在四边形模型里加入这两个着色器
代码如下:
private final String vertexShaderCode =\"attribute vec4 vPosition;\" +\"void main() {\" +\" gl_Position = vPosition;\" +\"}\";private final String fragmentShaderCode =\"precision mediump float;\" +\"uniform vec4 vColor;\" +\"void main() {\" +\" gl_FragColor = vColor;\" +\"}\";
代码中赋值的是一种GLSL语言的定义,GLSL语言是为了实现着色器的功能而向开发人员提供的一种开发语言,这就是OpenGL ES从2.0开始对比于OpenGL ES1.x最大的改变可编程渲染管线图,OpenGL ES1.x渲染为固定渲染管线,想了解更多的GLSL语言相关内容可以去百度查看。
在绘制线程绑定四方形模型:
public class SquareRender implements GLSurfaceView.Renderer {//四边形模型private Square mSquare;@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {//界面创建时绑定模型mSquare=new Square();//设置背景色为黑色GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {GLES20.glViewport(0, 0, width, height);}@Overridepublic void onDrawFrame(GL10 gl) {//清空颜色GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);//绘制四边形mSquare.draw();}//加载相关的着色器 Vertex Shader(顶点着色器)Fragment Shader(片元着色器)public static int loadShader(int type, String shaderCode){// create a vertex shader type (GLES20.GL_VERTEX_SHADER)// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)int shader = GLES20.glCreateShader(type);// add the source code to the shader and compile itGLES20.glShaderSource(shader, shaderCode);GLES20.glCompileShader(shader);return shader;}}
将绘制线程赋给GLSurfaceView:
public class SquareGLSurfaceView extends GLSurfaceView{private final SquareRender renderer;public SquareGLSurfaceView(Context context) {this(context,null);}public SquareGLSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);// Create an OpenGL ES 2.0 contextsetEGLContextClientVersion(2);renderer = new SquareRender();// Set the Renderer for drawing on the GLSurfaceViewsetRenderer(renderer);}}
上面图形为参考google绘制三角形代码绘制,参考地址
我的完整代码,地址