android opengl es 总结
什么是OpenGL ES?OpenGL ES (为OpenGL for Embedded System的缩写) 为适用于嵌入式系统的一个免费二维和三维图形库。 为桌面版本OpenGL 的一个子集。 OpenGL ES 定义了一个在移动平台上能够支持OpenGL最基本功能的精简标准,以适应如手机,PDA或其它消费者移动终端的显示系统。 Khronos Group 定义和管理了OpenGL ES标准。 OpenGL 与 OpenGL ES的关系OpenGL ES 是基于桌面版本OpenGL 的:OpenGL ES 1.0? 基于OpenGL 1.3 , 在2003年发布 OpenGL ES 1.1?? 基于OpenGL 1.5 ,? 在2004年发布 OpenGL ES 2.0? 基于OpenGL2.0,?? 在2007年发布 OpenGL 2.0 向下兼容OpenGL 1.5?? 而 OpenGL ES 2.0 和OpenGL ES 1.x 不兼容,是两种完全不同的实现。 OpenGL ES管道(Pipeline)OpenGL ES 1.x 的工序是固定的,称为Fix-Function Pipeline,可以想象一个带有很多控制开关的机器,尽管加工的工序是固定的,但是可以通过打开或关闭开关来设置参数或者打开关闭某些功能。OpenGL ES 2.0 允许提供编程来控制一些重要的工序,一些“繁琐”的工序比如栅格化等仍然是固定的。(这些开关被就是state,注意应该尽量少的改变state,以免影响性能)管道“工序”大致可以分为 Transformation Stage 和 Rasterization Stage两大步。 OpenGL ES 支持的基本图形为 点Point, 线Line, 和三角形Triangle ,其它所有复制图形都是通过这几种基本几何图形组合而成。 在发出绘图指令后,会对顶点(Vertices)数组进行指定的坐标变换或光照处理。 顶点处理完成后,通过Rasterizer 来生成像素信息,称为”Fragments“ 。 对于Fragment 在经过Texture Processing, Color Sum ,Fog 等处理并将最终处理结果存放在内存中(称为FrameBuffer)。 OpenGL 2.0可以通过编程来修改上述红色的部分的步骤,称为Programmable Shader. OpenGL ES API 命名习惯?定义的常量都以GL_为前缀。比如GL10.GL_COLOR_BUFFER_BIT OpenGL ES 指令以gl开头 ,比如gl.glClearColor 某些OpenGL指令以3f 或4f结尾,3和4代表参数的个数,f代表参数类型为浮点数,如gl.glColor4f ,i,x 代表 int如 gl.glColor4x 对应以v结尾的OpenGL ES 指令,代表参数类型为一个矢量(Vector) ,如 glTexEnvfv 所有8-bit整数对应到byte 类型,16-bit 对应到short类型,32-bit整数(包括GLFixed)对应到int类型,而所有32-bit 浮点数对应到float 类型。 GL_TRUE,GL_FALSE 对应到boolean类型 C字符串((char*)) 对应到Java 的 UTF-8 字符串。?
?
?
?创建简单的opengl es实例http://developer.android.com/resources/tutorials/opengl/opengl-es10.html???基本几何图形定义OpenGL ES 支持绘制的基本几何图形分为三类:点,线段,三角形。也就是说OpenGL ES 只能绘制这三种基本几何图形。任何复杂的2D或是3D图形都是通过这三种几何图形构造而成的。OpenGL ES提供了两类方法来绘制一个空间几何图形:
public abstract void?glDrawArrays(int?mode, int first, int count) 使用VetexBuffer 来绘制,顶点的顺序由vertexBuffer中的顺序指定。 public abstract void?glDrawElements(int mode, int count, int type, Buffer indices) ,可以重新定义顶点的顺序,顶点的顺序由indices Buffer 指定。 mode列表:GL_POINTS?绘制独立的点、GL_LINE_STRIP绘制一条线段、GL_LINE_LOOP绘制一条封闭线段(首位相连)、GL_LINES绘制多条线段、GL_TRIANGLES绘制多个三角形(两两不相邻)、GL_TRIANGLE_STRIP绘制多个三角形(两两相邻)、GL_TRIANGLE_FAN以一个点为顶点绘制多个相邻的三角形对应顶点除了可以为其定义坐标外,还可以指定颜色,材质,法线(用于光照处理)等。
glEnableClientState 和 glDisableClientState 可以控制的pipeline开关可以有:GL_COLOR_ARRAY (颜色) ,GL_NORMAL_ARRAY (法线), GL_TEXTURE_COORD_ARRAY (材质), GL_VERTEX_ARRAY(顶点), GL_POINT_SIZE_ARRAY_OES等。
对应的传入颜色,顶点,材质,法线的方法如下:
glColorPointer(int size,int type,int stride,Buffer pointer)在OpenGL ES 中,
使用GL10.GL_MODELVIEW 来同时指定viewing matrix 和modeling matrix. 使用GL10.GL_PROJECTION 指定投影变换,OpenGL 支持透视投影(3D)和正侧投影(2D)。 使用glViewport 指定 Viewport 变换。 ??通用的矩阵变换指令?这里介绍对应指定的坐标系(比如viewmodel, projection或是viewport) Android OpenGL ES支持的一些矩阵运算及操作。矩阵本身可以支持加减乘除,对角线全为1的4X4 矩阵成为单位矩阵Identity Matrix 。将当前矩阵设为单位矩阵的指令 为glLoadIdentity(). 矩阵相乘的指令glMultMatrix*()?允许指定任意矩阵和当前矩阵相乘。 选择当前矩阵种类glMatrixMode().??OpenGL ES 可以运行指定GL_PROJECTION,GL_MODELVIEW等坐标系,后续的矩阵操作将针对选定的坐标。 将当前矩阵设置成任意指定矩阵glLoadMatrix*() 在栈中保存当前矩阵和从栈中恢复所存矩阵,可以使用glPushMatrix()和glPopMatrix() 特定的矩阵变换平移glTranslatef(),旋转glRotatef()?和缩放glScalef() 方法public abstract void?glTranslatef?(float x, float y, float z) 用于坐标平移变换。方法public abstract void?glRotatef(float angle, float x, float y, float z)用来实现选择坐标变换,单位为角度。 (x,y,z)定义旋转的参照矢量方向。多次旋转的顺序非常重要。方法public abstract void?glScalef?(float x, float y, float z)用于缩放变换。在进行平移,旋转,缩放变换时,所有的变换都是针对当前的矩阵(与当前矩阵相乘),如果需要将当前矩阵回复最初的无变换的矩阵,可以使用单位矩阵(无平移,缩放,旋转)。
public abstract void?glLoadIdentity()。
在栈中保存当前矩阵和从栈中恢复所存矩阵,可以使用public abstract void?glPushMatrix()
和
public abstract void?glPopMatrix()。
在进行坐标变换的一个好习惯是在变换前使用glPushMatrix保存当前矩阵,完成坐标变换操作后,再调用glPopMatrix恢复原先的矩阵设置。??Viewing和Modeling(MODELVIEW) 变换?ndroid OpenGL ES 的GLU包有一个辅助函数gluLookAt提供一个更直观的方法来设置modelview 变换矩阵:
void gluLookAt(GL10 gl, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)eyex,eyey,eyez 指定观测点的空间坐标。 tarx,tary,tarz ,指定被观测物体的参考点的坐标。 upx,upy,upz 指定观测点方向为“上”的向量。(0,1,0) ???投影变换Projection投影变换则对应于调整相机镜头远近来取景。下面代码设置当前Matrix模式为Projection投影矩阵:gl.glMatrixMode(GL_PROJECTION);gl.glLoadIdentity();OpenGL ES可以使用两种不同的投影变换:透视投影(Perspective Projection)和正侧投影(Orthographic Projection)。Android OpenGL ES提供了一个辅助方法gluPerspective()可以更简单的来定义一个透视投影变换:GLU.gluPerspective(GL10 gl, float fovy, float aspect, float zNear, float zFar)
fovy: 定义视锥的view angle. aspect:? 定义视锥的宽高比。 zNear: 定义裁剪面的近距离。就是前面距离原点的距离 zFar: 定义创建面的远距离。就是后面距离原点的距离 正侧投影(Orthographic Projection)正侧投影,它的视锥为一长方体,特点是物体的大小不随到观测点的距离而变化,投影后可以保持物体之间的距离和夹角。??定义3D模型的前面和后面下面代码设置逆时针方法为面的“前面”:gl.glFrontFace(GL10.GL_CCW);下面给出了OpenGL ES中与Depth Buffer相关的几个方法:
gl.Clear(GL10.GL_DEPTH_BUFFER_BIT) 清空Depth Buffer (赋值为1.0)通常清空Depth Buffer和Color Buffer同时进行。 gl.glClearDepthf(float depth) 指定清空Depth Buffer是使用的值,缺省为1.0,通常无需改变这个值, gl.glEnable(GL10.GL_DEPTH_TEST) 打开depth Test gl.glDisable(GL10.GL_DEPTH_TEST) 关闭depth Test ?OpenGL光照模型为了能看出3D效果,给场景中添加光源。如果没有光照,绘出的球看上去和一个二维平面上圆没什么差别OpenGL 光照模型中最终的光照效果可以分为四个组成部分:Emitted(光源), ambient(环境光),diffuse(漫射光)和specular(镜面反射光),最终结果由这四种光叠加而成。
Emitted : 一般只发光物体或者光源,这种光不受其它光源的影响。
ambient: 环境光如果射到某个平面,其反射方向为所有方向。Ambient 没有位置方向,只有颜色。
diffuse:当一束平行的入射光线射到粗糙的表面时,因面上凹凸不平,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则地反射,这种反射称之为“漫反射”或“漫射”。这个反射的光则称为漫射光。漫射光射到某个平面时,其反射方向也为所有方向。diffuse 只依赖于光源的方向和法线的方向。
specular : 一般指物体被光源直射的高亮区域,也可以成为镜面反射区,如金属。specular依赖于光源的方向,法线的方向和视角的方向。光源
OpenGL ES中可以最多同时使用八个光源,分别使用0到7表示。
OpenGL ES光源可以分为
平行光源(Parallel light source), 代表由位于无限远处均匀发光体,太阳可以近似控制平行光源。 点光源(Spot light source)? 如灯泡就是一个点光源,发出的光可以指向360度,可以为点光源设置光衰减属性(attenuation)或者让点光源只能射向某个方向(如射灯)。 下面方法可以打开某个光源,使用光源首先要开光源的总开关:gl.glEnable(GL10.GL_LIGHTING);然后可以再打开某个光源如0号光源:gl.glEnable(GL10.GL_LIGHT0);设置光源方法如下:public void glLightfv(int light,int pname, FloatBuffer params) public void glLightfv(int light,int pname,float[] params,int offset) public void glLightf(int light,int pname,float param) light 指光源的序号,OpenGL ES可以设置从0到7共八个光源。 pname: 光源参数名称,可以有如下:GL_SPOT_EXPONENT, GL_SPOT_CUTOFF, GL_CONSTANT_ATTENUATION,? GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION,?GL_AMBIENT, GL_DIFFUSE,GL_SPECULAR, GL_SPOT_DIRECTION, GL_POSITION params 参数的值(数组或是Buffer类型)。 其中为光源设置颜色的参数类型为上述蓝色值,可以分别指定R,G,B,A 的值。指定光源的位置的参数为GL_POSITION,值为(x,y,z,w):平行光将w 设为0.0,(x,y,z)为平行光的方向。?
打开法线数组gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);?
这个方法为后续所有平面设置同样的方向,直到重新设置新的法线为止。
为某个顶点设置法线:public void glNormalPointer(int type,int stride, Buffer pointer)
type? 为Buffer 的类型,可以为GL_BYTE, GL_SHORT, GL_FIXED,或 GL_FLOAT stride: 每个参数之间的间隔。 pointer: 法线值。规范化法向量,比如使用坐标变换(缩放),如果三个方向缩放比例不同的话,顶点或是平面的法线可能就有变化,此时需要打开规范化法线设置:gl.glEnable(GL10.GL_NORMALIZE);经过规范化后法向量为单位向量(长度为1)。同时可以打开缩放法线设置gl.glEnable(GL10.GL_RESCALE_NORMAL);设置物体表面材料(Material)的反光属性(颜色和材质)的方法如下:
? ? ? ? gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, ambient, 0);?? ? ? ? gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, diffuse, 0);?? ? ? ? gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, specular, 0); ??
? ? ? ? gl.glEnable(GL10.GL_COLOR_MATERIAL);??
此外,方法glLightModleXX给出了光照模型的参数
public void glLightModelf(int pname,float param)
public void glLightModelfv(int pname,float[] params,int offset)
public void glLightModelfv(int pname,FloatBuffer params)
最终顶点的颜色由这些参数(光源,材质光学属性,光照模型)综合决定(光照方程计算出)。