`
wo_deqing
  • 浏览: 60298 次
文章分类
社区版块
存档分类
最新评论

OpenGL ES绘制3D图形

 
阅读更多
OpenGL ES是OpenGL三维图形API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。 Ophone目前支持OpenGL ES 1.0 ,OpenGL ES 1.0 是以 OpenGL 1.3 规范为基础的,OpenGL ES 1.1 是以 OpenGL 1.5 规范为基础的。本文主要介绍利用OpenGL ES绘制图形方面的基本步骤。
本文内容由三部分构成。首先通过EGL获得OpenGL ES的编程接口;其次介绍构建3D程序的基本概念;最后是一个应用程序示例。
EGL
OpenGL ES 本质上是一个图形渲染管线的状态机,而 EGL 则是用于监控这些状态以及维护帧缓冲和其他渲染面的外部层。图1 是一个典型的 EGL 系统布局图。EGL 视窗设计是基于人们熟悉的用于 Microsoft Windows ( WGL )和 UNIX ( GLX )上的 OpenGL 的 Native 接口,与后者比较接近。 OpenGL ES 图形管线的状态被存储于 EGL 管理的一个上下文中。帧缓冲和其他绘制渲染面通过 EGL API 创建、管理和销毁。 EGL 同时也控制和提供了对设备显示和可能的设备渲染配置的访问。
图1
OpenGL ES 需要一个渲染上下文和渲染面。渲染上下文中存储OpenGL ES的状态信息,渲染面用于图元的绘制。编写OpenGL ES之前需要EGL的操作有:
  • 查询设备可以支持的显示句柄,并初始化。
  • 创建渲染面,绘制OpenGL ES图形。
  • 创建渲染上下文。EGL需要创建OpenGL ES渲染上下文用于关联到某个渲染面。
Ophone中EGL包括4个类,分别是EGLDisplay:显示句柄、EGLConfig:配置类;EGLContext:渲染上下文;的类和EGLSurface:可渲染的视图类。
EGL可以认为成OpenGL ES和本地窗口系统之间的中间层。 本地窗口系统指GNU/Linux上X窗口系统,或者Mac OX X's Quartz等。在EGL确定渲染面的类型前,EGL需要和底层的窗口系统进行通讯。因为在不同的操作系统上的窗口系统的不同,EGL提供一个透明窗口类型,即EGLDisplay。它抽象了各种窗口系统。所以首先要创建、初始化一个EGLDisplay对象。
  1. //EGLContext的静态方法getEGL获得EGL实例
  2. EGL10egl=(EGL10)EGLContext.getEGL();
  3. //创建EGLDisplay,EGL_DEFAULT_DISPLAY获得缺省的本地窗口系统类型
  4. EGLDisplaydpy=egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
  5. //初始化EGLDispla的同时获得版本号
  6. int[]version=newint[2];
  7. egl.eglInitialize(dpy,version);
每个 EGLDisplay 在使用前都需要初始化。初始化 EGLDisplay 的同时能够得到系统中 EGL 的实现版本号。通过版本号,合理运用相应OpenGL ES API,可以编写兼容性良好的程序,以适应更多的设备以及提供最大限度的移植性。初始化函数原型:
  1. booleaneglInitialize(EGLDisplaydisplay,int[]major_minor)
其中的display是一个有效的 EGLDisplay实例。函数调用完成时, major_minor将被赋予当前 EGL 版本号。比如 EGL1.0 , major_minor[0]为1,major_minor[1]为0。EGLSurface包含了EGL渲染面相关的所有信息。查询EGLSurface配置信息有两种方法,一是查询所有的配置信息,从中选择一个最为适合的;二是指定好配置信息,由系统给出最佳匹配结果。一般采用第二种方法。用户通过configSpec指定出希望获得的配置,函数eglChooseConfig通过参数Configs返回最佳的配置列表。之后利用已获得的Configs,调用eglCreateContext创建一个渲染上下文,该函数返回EGLContext结构。渲染面EGLSurface的创建通过函数eglCreateWindowSurface完成。一个应用程序可以创建多个EGLContext。 eglMakeCurrent就是将某个渲染上下文绑定到渲染面。查询函数eglGetCurrentContext,eglGetCurrentDisplay和eglGetCurrentSurface分别用于获得当前系统的渲染上下文、显示句柄和渲染面。最后EGLContext的静态方法getGL获得OpenGL ES的编程接口。下面的程序片段总结了上述内容。
  1. EGL10egl=(EGL10)EGLContext.getEGL();
  2. EGLDisplaydpy=egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);int[]version=newint[2];
  3. egl.eglInitialize(dpy,version);
  4. int[]configSpec={
  5. EGL10.EGL_RED_SIZE,5,
  6. EGL10.EGL_GREEN_SIZE,6,
  7. EGL10.EGL_BLUE_SIZE,5,
  8. EGL10.EGL_DEPTH_SIZE,16,
  9. EGL10.EGL_NONE
  10. };
  11. EGLConfig[]configs=newEGLConfig[1];
  12. int[]num_config=newint[1];
  13. egl.eglChooseConfig(dpy,configSpec,configs,1,num_config);
  14. EGLConfigconfig=configs[0];
  15. EGLContextcontext=egl.eglCreateContext(dpy,config,
  16. EGL10.EGL_NO_CONTEXT,null);
  17. EGLSurfacesurface=egl.eglCreateWindowSurface(dpy,config,
  18. sHolder,null);
  19. egl.eglMakeCurrent(dpy,surface,surface,context);
  20. GL10gl=(GL10)context.getGL();
构建3D图形
点是构建3D模型的基础。 OpenGL ES的内部计算是基于点的。 用点也可以表示光源的位置,物体的位置。一般我们用一组浮点数来表示点。 例如一个正方形的4个顶点可表示为:
  1. floatvertices[]={
  2. -1.0f,1.0f,0.0f,//左上
  3. -1.0f,-1.0f,0.0f,//左下
  4. 1.0f,-1.0f,0.0f,//右下
  5. 1.0f,1.0f,0.0f,//右上
  6. };
为了提高性能, 需要将浮点数组存入一个字节缓冲中。 所以有了下面的操作:
  1. ByteBuffervbb=ByteBuffer.allocateDirect(vertices.length*4);
  2. vbb.order(ByteOrder.nativeOrder());
  3. FloatBuffervertexBuffer=vbb.asFloatBuffer();
  4. vertexBuffer.put(vertices);
  5. vertexBuffer.position(0);
其中ByteOrder.nativeOrder()是获取本机字节顺序。OpenGL ES有操作图形渲染管线的函数,在默认情况下这些函数功能的使用状态是处于关闭的。 启用和关闭这些函数可以用glEnableClientState、glDisableClientState来完成。
  1. //指定需要启用定点数组
  2. gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  3. //说明启用数组的类型和字节缓冲,类型为GL_FLOAT
  4. gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexBuffer);
  5. //不再需要时,关闭顶点数组
  6. gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
边是连接两个点的一条线,是多边形面的边缘。

多边形
多边形是由边构成的单闭合环。 OpenGL ES中的多边形必须是凸多边形,即在多边形的内部任意取两点, 如果连接这两个点的线段都在多变的内部,这个多边形就是凸多边形。 绘制多边形时需要指定渲染的方向, 分为顺时针和逆时针。 因为方向决定了多边形的朝向, 即正面和背面。 避免渲染那些被遮挡的部分可以了有效提高程序性能。 函数glFrontFace定义了渲染顶点的方向。
  1. //设置CCW方向为“正面”,CCW即CounterClockWise,逆时针
  2. glFrontFace(GL_CCW);
  3. //设置CW方向为“正面”,CW即ClockWise,顺时针
  4. glFrontFace(GL_CW);
渲染
有了以上的概念讲解后,现在要进行最主要的工作—渲染。渲染是把物体坐标所指定的图元转化成帧缓冲区中的图像。图像和顶点坐标有着密切的关系。这个关系通过绘制模式给出。常用到得绘制模式有GL_POINTS、GL_LINE_STRIP、GL_LINE_LOOP、GL_LINES、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。下面分别介绍:
GL_POINTS:把每一个顶点作为一个点进行处理,顶点n即定义了点n,共绘制n个点。
GL_LINES:把每一个顶点作为一个独立的线段,顶点2n-1和2n之间共定义了n个线段,总共绘制N/2条线段。,如果N为奇数,则忽略最后一个顶点。
GL_LINE_STRIP:绘制从第一个顶点到最后一个顶点依次相连的一组线段,第n和n+1个顶点定义了线段n,总共绘制N-1条线段。
GL_LINE_LOOP:绘制从定义第一个顶点到最后一个顶点依次相连的一组线段,然后最后一个顶点与第一个顶点相连。第n和n+1个顶点定义了线段n,然后最后一个线段是由顶点N和1之间定义,总共绘制N条线段。
GL_TRIANGLES:把每三个顶点作为一个独立的三角形。顶点3n-2,3n-1和3n定义了第n个三角形,总共绘制N/3个三角形。
GL_TRIANGLE_STRIP:绘制一组相连的三角形。对于奇数点n,顶点n,n+1和n+2定义了第n个三角形;对于偶数n,顶点n+1,n和n+2定义了第n个三角形,总共绘制N-2个三角形。
 GL_TRIANGLE_FAN:绘制一组相连的三角形。三角形是由第一个顶点及其后给定的顶点所确定。顶点1,n+1和n+2定义了第n个三角形,总共绘制N-2个三角形。
绘制函数:
void glDrawArrays(int mode, int first, int count)
void glDrawElements(int mode, int count, int type, Buffer indices)
glDrawArrays创建一个几何图元序列,使用每个被的数组中从first开始,到first + count – 1结束的数组元素, mode为绘制模式。
glDrawElements使用count个元素定义一个图元序列,type是indices数组中的数据类型,mode为绘制模式,indices数组存储顶点的索引值。
应用举例
利用上面讲解的内容给出一个Ophone上绘制一个3D球形的程序。效果图如下:
图2 球形示例
主要的绘制程序:
  1. staticprivateFloatBuffervertex;//顶点对应的字节缓冲
  2. staticprivateFloatBuffernormal;//法向量对应的字节缓冲
  3. float[]lightPos=newfloat[]{10.0f,10.0f,10.0f,1.0f};//光源的坐标
  4. privatestaticfinalintSTEP=24;//
  5. privatestaticfinalfloatRADIUS=1.0f;//半径
  6. protectedvoidinit(GL10gl){
  7. gl.glClearColor(0.0f,0.0f,0.0f,1.0f);//设置背景颜色
  8. gl.glLightfv(GL10.GL_LIGHT0,GL10.GL_POSITION,lightPos,0);
  9. gl.glEnable(GL10.GL_LIGHTING);//启用光照
  10. gl.glEnable(GL10.GL_LIGHT0);//打开光源
  11. gl.glClearDepthf(1.0f);//设置深度缓存
  12. gl.glDepthFunc(GL10.GL_LEQUAL);//设置深度缓存比较函数,GL_LEQUAL表示新的像素的深度缓存值小于等于当前像素的深度缓存值时通过深度测试
  13. gl.glEnable(GL10.GL_DEPTH_TEST);//启用深度缓存
  14. gl.glEnable(GL10.GL_CULL_FACE);
  15. gl.glShadeModel(GL10.GL_SMOOTH);//设置阴影模式GL_SMOOTH
  16. }
  17. protectedvoiddrawFrame(GL10gl){
  18. gl.glClear(GL10.GL_COLOR_BUFFER_BIT|
  19. GL10.GL_DEPTH_BUFFER_BIT);
  20. gl.glMatrixMode(GL10.GL_MODELVIEW);
  21. gl.glLoadIdentity();
  22. GLU.gluLookAt(gl,0,0,7f,0f,0f,0f,0f,1.0f,0.0f);//
  23. drawSphere(gl,RADIUS,STEP,STEP);//绘制球形
  24. }
public static voidgluLookAt(GL10gl, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float
centerZ, float upX, float upY, float upZ)
它共接受三组坐标,分别为eye、 center和up。eye表示我们眼睛在"世界坐标系"中的位置,center表示眼睛"看"的那个点的坐标,up坐标表示观察者本身的方向,如果将观察点比喻成我们的眼睛,那么这个up则表示我们是正立还是倒立异或某一个角度在看,这里是正立方式,所以是{0,1,0}。
  1. privatestaticvoiddrawSphere(GL10gl,floatradius,
  2. intstacks,intslices){
  3. vertex=allocateFloatBuffer(4*6*stacks*(slices+1));
  4. normal=allocateFloatBuffer(4*6*stacks*(slices+1));
  5. inti,j,triangles;
  6. floatslicestep,stackstep;
  7. stackstep=((float)Math.PI)/stacks;
  8. slicestep=2.0f*((float)Math.PI)/slices;
  9. for(i=0;i<stacks;++i)
  10. {
  11. floata=i*stackstep;
  12. floatb=a+stackstep;
  13. floats0=(float)Math.sin(a);
  14. floats1=(float)Math.sin(b);
  15. floatc0=(float)Math.cos(a);
  16. floatc1=(float)Math.cos(b);
  17. floatnv;
  18. for(j=0;j<=slices;++j)
  19. {
  20. floatc=j*slicestep;
  21. floatx=(float)Math.cos(c);
  22. floaty=(float)Math.sin(c);
  23. nv=x*s0;
  24. normal.put(nv);
  25. vertex.put(nv*radius);
  26. nv=y*s0;
  27. normal.put(nv);
  28. vertex.put(nv*radius);
  29. nv=c0;
  30. normal.put(nv);
  31. vertex.put(nv*radius);
  32. nv=x*s1;
  33. normal.put(nv);
  34. vertex.put(nv*radius);
  35. nv=y*s1;
  36. normal.put(nv);
  37. vertex.put(nv*radius);
  38. nv=c1;
  39. normal.put(nv);
  40. vertex.put(nv*radius);
  41. }
  42. }
  43. normal.position(0);
  44. vertex.position(0);
  45. gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertex);
  46. gl.glNormalPointer(GL10.GL_FLOAT,0,normal);
  47. gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  48. gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
  49. triangles=(slices+1)*2;
  50. for(i=0;i<stacks;i++)
  51. gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,
  52. i*triangles,triangles);
  53. gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
  54. gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
  55. }
  56. privatestaticFloatBufferallocateFloatBuffer(intcapacity){
  57. ByteBuffervbb=ByteBuffer.allocateDirect(capacity);
  58. vbb.order(ByteOrder.nativeOrder());
  59. returnvbb.asFloatBuffer();
  60. }
分享到:
评论

相关推荐

    android openGl绘制3d图形

    构建3D图形,OpenGl ES 绘制3D图形的放回绘制2D的图形的大致方法

    Android开发 OpenGL ES绘制3D 图形实例详解

    主要介绍了Android开发 OpenGL ES绘制3D 图形实例详解的相关资料,需要的朋友可以参考下

    论文研究-基于OpenGLES的3D图形绘制管线优化问题.pdf

    采用最新的图形管线理论,将OpenGL ES的3D图形管线绘制过程划分为七个管线绘制部分(这七个部分归属于三个绘制阶段),分析每个绘制部分的主要工作,在此基础上针对各个阶段提出了相应的优化方法。

    基于OpenGL ES的3D图形绘制管线优化问题* (2007年)

    采用最新的图形管线理论,将OpenGL ES的3D图形管线绘制过程划分为七个管线绘制部分(这七个部分归属于三个绘制阶段),分析每个绘制部分的主要工作,在此基础上针对各个阶段提出了相应的优化方法。

    OpenGL ES应用开发实践 指南 iOS卷.pdf

    第1章介绍了使用嵌入式图形硬件绘制3d图形的最新方法;第2章讲解了如何使用苹果xcode开发工具和cocoa touch面向对象的框架在iphone、ipod touch和ipad中开发包括3d图形的程序;第3章涵盖了纹理的底层概念和常用选项...

    OpenGL ES 3.0编程指南第2版[中文][PDF]

    详细讲解OpenGL ES 3.0中的应用程序接口(API)和图形管线,既涵盖简单图形的渲染方法,又深入介绍逐像素照明和粒子系统等高级渲染技术,并且包含大量有效使用API和硬件的实用技巧,为手持设备的各种高性能3D应用...

    Android开发之OpenGL绘制2D图形的方法分析

    Android为OpenGL ES支持提供了GLSurviceView组建,这个组建用于显示3D图形。GLSurviceView本身并不提供绘制3的图形的功能,而是由GLSurfaceView.Renderer来完成了SurviceView中3D图形的绘制。 归纳起来,在android中...

    OpenGL ES绘图迷你太阳系

    android平台下使用OpenGL ES绘制的模拟太阳系(日,地,月)运行的图形。 太阳自转,地球自转并绕太阳公转,月亮自转并绕地球公转。

    OpenGL ES 3.0

     第2章介绍绘制三角形的一个简单OpenGL ES 3.0示例。我们的目的是说明OpenGL ES 3.0程序的样子,向读者介绍一些API概念,并说明如何构建和运行OpenGL ES 3.0示例程序。  第3章——EGL简介  第3章介绍EGL——为...

    android(下)复习总结

    二、 OpenGL ES绘制2D图形 8 三、 OpenGL ES应用纹理贴图 12 四、 OpenGL ES旋转、光照、透明 15 第三章网络应用 17 一、 基于TCP协议的网络通信 17 二、 使用URL访问网络资源 21 三、 使用HTTP访问网络 22 四、 ...

    ES2.0编程指南(中文版).pdf

    华章 OpenGL ES 3.0编程指南(原书第2版)由资深OpenGL技术专家亲笔撰写,全面介绍OpenGL ES 3.0的各种特性及新增功能,通过大量已经编译和测试过的实例,详细讲解OpenGL ES 3.0中的应用程序接口(API)和图形管线,...

    SweetRide:OpenGL Android 3D图形引擎。 主线程中的代码,GL线程中的绘图

    甜蜜的骑基于opengl es 2.0构建的Android 3d图形引擎。 在主线程中编码ui,让引擎在gl线程中绘制。 已有2个月没有进行此工作了,请上传此文件以确保安全,直到我决定/觉得自己再次进行此工作为止。 对于许多其他正在...

    OpenGL小白入门知识点详解

    OpenGL ES:是手持嵌入式设备的3DAPI,跨平台的、功能完善的2D和3D图形应用程序接口API,有一套固定渲染管线流程. OpenGL ES详解 格栅化 是 将图片等矢量资源,转化为一格格像素点的像素图,显示到屏幕上。 垂直同步...

    疯狂Android讲义(第2版)源代码 第10章~第13章

    12.4、绘制3D图形: 第13章、Android的网络应用 13.1、基于TCP协议的网络通信(套接字Socket):Socket; ServerSocket; 13.2、使用URL访问网络资源:URL; URLConnection; 13.3、使用HTTP访问网络:...

    Android高薪之路:Android程序员面试宝典 李宁

    12 5 绘制3D图形 12 6 光照效果 第13章 Android系统的资源 13 1 资源的基础问题 13 2 本地化 13 3 字符串资源 13 4 布局资源 13 5 图像资源 13 6 其他资源 第14章 其他面试例题 14 1 NDK编程 14 2 传感器 14 3 语音...

    iPhone游戏开发入门

    何在iPhone的屏幕上高效地绘制2D和3D图形;使用Core Animation的游戏专用动画技术; 通过OpenGL ES构建更复杂、更真实的游戏背景和游戏动作;多种添加音乐增强游戏体验 的方式;让用户在游戏中访问iPhone音乐库;...

    Android应用开发从入门到精通 android studio code 11-17章

     Camera、地图、GPS、传感器、录音、WiFi设备等,OpenGL ES的应用,着色和3D图形的绘制和纹理贴图,Android NDK和Android网络编程,Android进程间通信机制Binder原理等,通过一个完整项目的开发,帮助读者把所学的...

    Android应用开发从入门到精通 android studio code 1-10章

     Camera、地图、GPS、传感器、录音、WiFi设备等,OpenGL ES的应用,着色和3D图形的绘制和纹理贴图,Android NDK和Android网络编程,Android进程间通信机制Binder原理等,通过一个完整项目的开发,帮助读者把所学的...

    Android应用开发从入门到精通 code 1-12章

     Camera、地图、GPS、传感器、录音、WiFi设备等,OpenGL ES的应用,着色和3D图形的绘制和纹理贴图,Android NDK和Android网络编程,Android进程间通信机制Binder原理等,通过一个完整项目的开发,帮助读者把所学的...

Global site tag (gtag.js) - Google Analytics