




已阅读5页,还剩29页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
J2ME3D游戏开发UI图形设计随着各种手持设备的性能提升和对3D技术的支持,越来越多的3D游戏出现在了各种手持设备上,3D游戏不仅能渲染出非常漂亮的图形,最重要的是能够给玩家带来更真实的体验,那么本文将分析如何通过JavaME环境来构建一个3D游戏开发框架。寻梦2011-3-18目录JavaME 3D游戏开发框架2JavaME 3D游戏开发基本图形渲染10JavaME 3D游戏开发3D图形渲染13JavaME 3D游戏开发光效16JavaME 3D游戏开发材质20JavaME 3D游戏开发纹理22JavaME 3D游戏开发纹理映射25JavaME 3D游戏开发模型30 Gc JavaME 3D游戏开发框架随着各种手持设备的性能提升和对3D技术的支持,越来越多的3D游戏出现在了各种手持设备上,3D游戏不仅能渲染出非常漂亮的图形,最重要的是能够给玩家带来更真实的体验,那么本文将分析如何通过JavaME环境来构建一个3D游戏开发框架。JavaME所支持的3D开发包主要有:jsr184和jsr239,其中jsr184是Mobile 3D Graphics API 简称M3G,M3G的直接访问模式是建立在OpenGL的基础上的,作为它的一个子集和精简部分,保留了很多有效的功能。JSR 239则定义了一个几乎与OpenGL ES的C 接口相同的 Java API,使现有OpenGL内容的移植更为容易,OpenGL ES是专为内嵌和移动设备设计的一个2D/3D轻量图形库,它是基于OpenGL API设计的。OpenGL ES 1.0版基于OpenGL 1.3,而OpenGL ES 1.1则是基于OpenGL 1.5的。现在主要由Khronos Group来负责管理OpenGL ES的开发维护,它几乎已经成为移动设备3D技术的一个事实标准。因此本文将采用该规范,使用JSR 239开发包来构建3D游戏。在使用Opengl ES开发游戏之前,我们首先需要分析几个名词、概念及其功能。EGL是OpenGL ES和底层Native平台视窗系统之间的接口。是为 OpenGL ES 提供平台独立性而设计。OpenGL ES 为附加功能和可能的平台特性开发提供了扩展机制,但仍然需要一个可以让 OpenGL ES 和本地视窗系统交互且平台无关的层。 OpenGL ES 本质上是一个图形渲染管线的状态机,而 EGL 则是用于监控这些状态以及维护 Frame buffer 和其他渲染 Surface 的外部层。图1-1是一个典型的 EGL 系统布局图。图1-1 典型的 EGL 系统布局图OpenGL ES 本质上是一个图形渲染管线的状态机,而 EGL 则是用于监控这些状态以及维护帧缓冲和其他渲染面的外部层。EGL视窗设计是基于人们熟悉的用于 Microsoft Windows ( WGL )和 UNIX ( GLX )上的 OpenGL 的 Native 接口,与后者比较接近。 OpenGL ES 图形管线的状态被存储于 EGL 管理的一个上下文中。帧缓冲和其他绘制渲染面通过 EGL API 创建、管理和销毁。 EGL 同时也控制和提供了对设备显示和可能的设备渲染配置的访问。EGL包括一下几个类,分别是EGLDisplay:显示句柄EGLConfig:配置类;EGLContext:渲染上下文;的类和EGLSurface:可渲染的视图类。OpenGL ES需要一个渲染上下文和渲染面。渲染上下文中存储OpenGL ES的状态信息,渲染面用于图元的绘制。编写OpenGL ES之前需要EGL的操作有:查询设备可以支持的显示句柄,并初始化。创建渲染面,绘制OpenGL ES图形。创建渲染上下文。EGL需要创建OpenGL ES渲染上下文用于关联到某个渲染面。这里我们将初始化EGL的操作整理到一个init函数中,如下代码所示。public void init() /获得egl实例 this.egl = (EGL10) EGLContext.getEGL(); /创建EGLDisplay this.eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int major_minor = new int2; /初始化EGLDispla,获得版本号 egl.eglInitialize(eglDisplay, major_minor); int num_config = new int1; /得到所有的cofig,数量 egl.eglGetConfigs(eglDisplay, null, 0, num_config); System.out.println(num_config0 = + num_config0); /设置配置列表 int redSize = getProperty(jsr239.redSize, 8); int greenSize = getProperty(jsr239.greenSize, 8); int blueSize = getProperty(jsr239.blueSize, 8); int alphaSize = getProperty(jsr239.alphaSize, 0); int depthSize = getProperty(jsr239.depthSize, 32); int stencilSize = getProperty(jsr239.stencilSize, EGL10.EGL_DONT_CARE); /配置属性列表 int s_configAttribs = EGL10.EGL_RED_SIZE, redSize, EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE, blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize, EGL10.EGL_DEPTH_SIZE,depthSize, EGL10.EGL_STENCIL_SIZE, stencilSize, EGL10.EGL_NONE ; EGLConfig eglConfigs = new EGLConfignum_config0; /取得最佳配置 egl.eglChooseConfig(eglDisplay, s_configAttribs, eglConfigs, eglConfigs.length, num_config); System.out.println(num_config0 = + num_config0); /最终选择的最佳配置 this.eglConfig = eglConfigs0; /创建EGLContext实例 this.eglContext = egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, null); /取得gl编程接口 this.gl = (GL10) eglContext.getGL(); /创建渲染面 this.eglWindowSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, g, null); /自定义的初始化标记 this.initialized = true; 们要初始化图形并配置色深和其他与 OpenGL 相关的属性,即上面代码中的init函数。也就是说在EGL确定渲染面的类型只前,EGL需要和底层的窗口系统进行通讯。因为在不同的操作系统上的窗口系统的不同,EGL提供一个透明窗口类型,即EGLDisplay。它抽象了各种窗口系统。所以首先需要使用EGLContext.getEGL()创建、初始化一个EGLDisplay对象。每个EGLDisplay 在使用前都需要使用eglInitialize函数初始化。初始化EGLDisplay的同时能够得到系统中 EGL的实现版本号。这样就可以通过版本号,合理运用相应OpenGL ES API,可以编写兼容性良好的程序,以适应更多的设备以及提供最大限度的移植性。初始化EGLDisplay的函数eglInitialize其中的display参数是一个有效的EGLDisplay实例。函数调用完成时,major_minor将被赋予当前 EGL版本号。比如EGL1.0 ,major_minor0为1,major_minor1为0。EGLSurface包含了EGL渲染面相关的所有信息。查询EGLSurface配置信息有两种方法,一是查询所有的配置信息,从中选择一个最为适合的;二是指定好配置信息,由系统给出最佳匹配结果。一般采用第二种方法(上面的代码中也采用了第二种)。用户通过configSpec指定出希望获得的配置,函数eglChooseConfig通过参数Configs返回最佳的配置列表。之后利用已获得的Configs,调用eglCreateContext创建一个渲染上下文,该函数返回EGLContext结构。渲染面EGLSurface的创建通过函数eglCreateWindowSurface完成。一个应用程序可以创建多个EGLContext。 eglMakeCurrent就是将某个渲染上下文绑定到渲染面。查询函数 eglGetCurrentContext, eglGetCurrentDisplay和eglGetCurrentSurface 分别用于获得当前系统的渲染上下文、显示句柄和渲染面。最后EGLContext的静态方法getGL获得OpenGL ES的编程接口gl。好了,到这里,我们已经完成了EGL的初始化,取得了渲染上下文、渲染面、GL编程接口,但是在真正渲染图形之前还需要进行一些设置,另外,我们可能需要通过J2ME API来展示3D游戏中的2D界面,如何才能同时使用J2ME API和GL编程接口进行渲染呢?下一篇文章我们将进行介绍,并通过GL来渲染一个窗口,准备好一个完整的3D游戏开发框架继续上一篇文章的内容,我们完成了EGL的初始化工作,现在我们已经获得了显示句柄eglDisplay、渲染上下文eglContext、渲染面eglWindowSurface以及进行GL编程所需的接口gl。本文将分析如何使用GL API来进行3D渲染和使用J2ME Graphics实例来绘制2D图形界面。首先需要解决的问题,我们的图形如何才能绘制到渲染面eglWindowSurface上?Opengl为我们提供了eglMakeCurrent函数用来绑定渲染上下文到渲染面。其函数原型定义如下:boolean javax.microedition.khronos.egl.EGL10.eglMakeCurrent(EGLDisplay arg0, EGLSurface arg1, EGLSurface arg2, EGLContext arg3)函数的4个参数就分别是上面所说的在初始化EGL时获得的实例,即如下代码所示:egl.eglMakeCurrent(eglDisplay, eglWindowSurface, eglWindowSurface,eglContext);绑定了渲染上下文之后就需要通过eglWaitNative函数来将2D图形和3D图形结合,代码如下,其中g表示Graphics对象。/ 将2D图形和3D图形结合egl.eglWaitNative(EGL10.EGL_CORE_NATIVE_ENGINE, g);eglWaitNative 方法必须在每个渲染层捕获设备的图形之前调用。完成此操作后还必须释放设备并最后调用 flushGraphics 来显示新帧。使用 eglWaitNative 和 eglWaitGL 我们可以将普通 Java ME 2D 图形与 JSR-239 结合起来,还可以将 JSR-239 与其他图形 API 结合起来,如 Mobile 3D API (JSR-184) 或 Scalable Vector Graphics (JSR-226)。最后,需要根据具体的要求来设置Opengl的某些属性、状态开关等,代码如下:private void updateState(int width, int height) float aspect = (height != 0) ? (float) width / (float) height) : 1.0f; /设置视口大小 gl.glViewport(0, 0, width, height); /设置裁剪区域 gl.glScissor(0, 0, width, height); /设置、重置模型视图矩阵 gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); /打开状态 gl.glEnable(GL10.GL_NORMALIZE); gl.glEnable(GL10.GL_COLOR_MATERIAL); gl.glEnable(GL10.GL_CULL_FACE); /对透视进行修正 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); /启用阴影平滑 gl.glShadeModel(GL10.GL_SMOOTH); /取消抖动 gl.glDisable(GL10.GL_DITHER); /设置清理屏幕的颜色 gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f); /设置、重置投影矩阵 gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); /透视处理 perspective(90.f, aspect, 0.1f, 100.f); /完成 gl.glFinish();其中glViewport函数用于设置GL的视口大小,函数原型如下所示:void glViewport( GLint x,GLint y,GLsizei width,GLsizei height)参数x,y用于指定视口矩形的左下角坐标,单位为像素,缺省值为(0,0)。这里需要说明一下Opengl所采用的坐标系和J2ME MIDP的不一样,其远点位于左下角,所以坐标角的坐标即为(0,0),x轴从左向右依次增加,y从下到上依次递增。参数width,height为指定视口矩形的宽度和高度。这样构成的举行区域就是Opengl的视口区域。glScissor函数用来设置剪裁区域,如果启用了GL_SCISSOR_TEST,绘制的内容只能在剪裁区域中显示。glMatrixMode()函数用于指定哪一个矩阵是当前矩阵,其参数mode指定哪一个矩阵堆栈是下一个矩阵操作的目标,可选值:GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE,其功能描述如下:GL_MODEVIEW:是对模型视景矩阵堆栈应用随后的矩阵操作。说明接下来的语句将描绘一个以模型为基础的适应,这样来设置参数,接下来用到的就是类似于gluLookAt()这样的函数。GL_PROJECTION:是对投影矩阵应用随后的矩阵操作。也就是把物体投影到一个平面上,就像我们照相一样,把3维物体投到2维的平面上。这样,接下来的语句可以是跟透视相关的函数,比如glFrustum()或gluPerspective()。GLTEXTURE:是对纹理矩阵堆栈应用随后的矩阵操作。OpenGL里面的操作,很多是基于对矩阵的操作的,比如位移,旋转,缩放等,操作之前都需要使用glMatrixMode()函数来设置当前被操作的矩阵。设置完成之后通常会调用glLoadIdentity()重置当前指定的矩阵为单位矩阵。实际上将当前点移到了屏幕中心,X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。glEnable()用于打开某个Opengl状态,参数就为需要打开的状态的常量。与之相对应的则为glDisable()函数,用于关闭某个状态,比如下面用到的“glDisable(GL10.GL_DITHER)”表示关闭取消抖动。这类状态参数非常多,这里不能一一列举,在后卖弄具体使用时在分析,上面代码中updateState函数中所使用的几个说明如下:GL_NORMALIZE:自动归一化法向量GL_COLOR_MATERIAL:允许颜色材质GL_CULL_FACE:启用表面剔除功能,通常需要和glCullFace函数配合来进行剔除然后,“gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);”主要是告诉系统需要对透视进行修正,其参数GL_PERSPECTIVE_CORRECTION_HINT是指定颜色和纹理坐标的插值质量。GL_FASTEST表示将使用速度最快的模式。如果使用GL_NICEST则表示将使用质量最好的模式。当然这会和性能有关,需要根据设备的性能来具体设置。glShadeModel函数用于控制opengl中绘制指定两点间其他点颜色的过渡模式,可以设置的着色模型有:GL_SMOOTH和GL_FLAT,其中GL_FLAT为单调着色,即对点、直线或多边形采用一种颜色进行绘制,整个图元的颜色就是它的任何一点的颜色。而GL_SMOOTH为平滑着色,用多种颜色进行绘制,每个顶点都是单独进行处理的,各顶点和各图元之间采用均匀插值。opengl默认将制定的两点颜色进行插值,绘制之间的其他点,如果两点的颜色相同,使用两个参数效果相同,如果两点颜色不同,GL_SMOOTH会出现过渡效果,GL_FLAT 则只是以指定的某一点的单一色绘制其他所有点。下图为这两种模式渲染的结果。其中,上面的效果是平滑着色,下面为单调着色。Opengl默认就是平滑着色,而单调着色通常会用来实现某些特殊效果,比如复古的特效等。glClearColor函数非常简单,就是指定清理屏幕的颜色,参数分别为颜色的r,g,b,a通道。通过该函数设置的颜色通常调用glClear函数时,就会使用这里指定的颜色清理屏幕。最后,将当前矩阵设置为投影矩阵GL_PROJECTION,并重置,然后调用我们自定义的函数perspective来处理透视,该函数实现代码如下:private void perspective(float fovy, float aspect, float zNear, float zFar) float xmin; float xmax; float ymin; float ymax; ymax = zNear * (float) Math.tan(fovy * Math.PI) / 360.0); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; /设置透视视口 gl.glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar);这里我们使用glFrustumf函数来设置一个透视视口,在OpenGL中我们可以使用gluPerspective来设置视椎体。但是在OpenGL ES中却没有提供这样的实用库支持,因此上面的函数perspective即是自己实现的一个类似gluPerspective的函数。需要确保在使用该函数之前要将矩阵设置为透视投影矩阵GL_PROJECTION,并重置。现在可以开始绘制图形了,看看我们如何同时绘制2D和3D图形,代码如下:gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);gl.glFinish();/ 等待GL处理完成egl.eglWaitGL();/ 绘制2D图形/ 使用GL接口绘图egl.eglWaitNative(EGL10.EGL_CORE_NATIVE_ENGINE, g);/设置并重置模型视图矩阵gl.glMatrixMode(GL10.GL_MODELVIEW);gl.glLoadIdentity();/渲染3D图形/ 等待GL处理完成egl.eglWaitGL();代码中首先通过glClear来清理颜色缓冲区和深度缓冲区,然后使用eglWaitGL函数等待GL处理完成,这是就可以绘制2D图形了,在使用GL接口绘图之前需要调用eglWaitNative函数并将当前矩阵设置为模型视图矩阵GL_MODELVIEW,绘制完成3D图形之后调用eglWaitGL函数来等待GL处理完成,最后,当需要退出渲染线程时,比如游戏结束,就需要销毁之前创建的对象实例,代码如下:public void shutdown() / 解绑eglContext与渲染面 egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); /销毁eglContext egl.eglDestroyContext(eglDisplay, eglContext); /销毁eglWindowSurface egl.eglDestroySurface(eglDisplay, eglWindowSurface); /终止egl egl.eglTerminate(eglDisplay);前面我们说过eglMakeCurrent函数可以绑定渲染上下文和渲染面,那么同样它还可以配合EGL_NO_CONTEXT参数来解绑渲染上下文和渲染面,因为在销毁过程中,首先需要解绑,才能销毁eglContext和eglWindowSurface,最后调用eglTerminate函数来种植EGL即可。运行效果如下图所示,只是出现一个蓝色的窗口,和一行用J2ME API绘制的2D文字,后面我们继续学习JavaME 3D开发的其他部分。下面附上框架部分源码,为了便于大家理解。public class AppCanvas extends GameCanvas implements Runnable public void drawScene() updateState(width, height); /省略部分. public void run() if (!initialized) init(); try while (!cube.isFinished() if (!cube.paused) Thread.sleep(2); drawScene(); flushGraphics(); catch (InterruptedException e) e.printStackTrace(); shutdown(); MIDlet子类AppMidlet中如下:private Display display;private AppCanvas appCanvas;/构建Canvasthis.display = Display.getDisplay(this);this.appCanvas = new AppCanvas(this);/设置显示Canvas并开启渲染线程display.setCurrent(appCanvas);drawThread = new Thread(appCanvas);drawThread.start();JavaME 3D游戏开发基本图形渲染通过前面两篇文章的学习,我们都能在JavaME环境上通过JSR239开发包构建一个3D游戏开发框架,但是在实际的游戏开发过程中,大部分时间会都会进行图形渲染,因此这篇文章将学习几种基本图形渲染的方式,以及图形颜色模式。在Opengl ES中不管多么复杂的物体或者模型,都是由三角形所组成的,因此本文我们将先学习绘制一个三角形,首先展示一下,我们要绘制的三角形如下图所示。其中蓝色的窗口是昨天我们已经创建好了的,在这里就不在重复叙述了。要绘制一个三角形,我们首先需要知道三角形的三个顶点的坐标(当然你也可以有其他的条件,比如:两点和一个夹角等),下面是我们定义的图中这个三角形的三个顶点坐标。private static final floattriangle = 0.0f, 1.0f, -3.0f, /上顶点 1.0f, 0.0f, -3.0f, /右顶点 -1.0f, 0.0f, -3.0f;/左顶点FloatBuffer triangleVertices;这里将三角形的三个顶点的数据放入到一个float数组中,每个顶点都由(x,y,z)坐标构成,原点(0,0,0)位于屏幕的中心,现在大家可以想象一下这个三角形在坐标系中的位置。另外,在代码中还有一个FloatBuffer类型的缓冲区,它将用来储存顶点数组triangle,然后提供给Opengl进行渲染。转换过程如下代码所示。triangleVertices = ByteBuffer.allocateDirect(triangle.length*4).asFloatBuffer();triangleVertices.put(triangle);triangleVertices.rewind();由于在JSR239中Opengl所支持的缓冲区必须是直接缓冲区,而我们的数据是浮点类型的,并不能直接通过allocateDirect函数来创建,这里就先通过allocateDirect创建一个ByteBuffer,然后调用asFloatBuffer()将其转换为FloatBuffer类型。绘制该三角形的具体代码如下所示。gl.glMatrixMode(GL10.GL_MODELVIEW);gl.glLoadIdentity();gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleVertices);gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);gl.glFinish();要渲染图形首先需要通过glMatrixMode将矩阵转换为模型视图矩阵,并重置初始化操作;glColor4f函数用于设置将要绘制的图形采用什么颜色,参数分别为r,g,b,a,可以看出代码中的颜色就是全红色的,在这里设定的颜色将会持续到下一次改变Opengl渲染染色之前,也就是说在该函数后面的所有图形都将采用这种颜色来绘制。前面我们已经准备好了顶点数组和缓冲区,但是Opengl并不知道,glVertexPointer函数则用于设置顶点数组,告诉Opengl将要绘制的图形的顶点数据,这样Opengl才知道怎么去绘制。其中第一个参数指示了多少个float数据代表一个顶点。根据是在进行二维或三维绘图,可以传递2或者3。尽管我们的物体是存在于一个平面的,我们仍然将其绘制在三维虚拟世界中,因此每个顶点用三个数值表示,所以我们传递3给函数。然后,我们传递一个枚举值告诉OpenGL顶点是由float构成。OpenGL ES允许你在当地数组中使用大部分的数据类型,但除GL_FLOAT外,其他都很少见。其三个参数是一个偏移量,一般情况下避免混乱都会设置为0,最后一个参数当然就是顶点缓冲区了。通常在设置顶点数组之前需要调用如下函数来打开状态。glEnableClientState(GL_VERTEX_ARRAY);该函数和前面讲的glEnable比较类似,用于启用某个状态,对应的禁止某个状态的函数为glDisableClientState,其中的参数就说明了要启用的状态,代码中的GL_VERTEX_ARRAY即表示允许设置顶点数组,通常情况下,会在设置顶点数组之前启用,然后再绘制结束之后调用glDisableClientState将其禁用;然当还有很多这样的状态,比如法线数组、颜色数组等,后面会介绍。glDrawArrays才是真正的绘制函数,其中第一个参数就是要绘制的图形,尽管OpenGL ES不支持绘制三角形之外的四边形或其他多边形,但它仍然支持一些其他绘图模式,如绘制点(GL_POINTS),线(GL_LINES),线回路(GL_LINE_LOOP),三角形条(GL_TRIANGLE_STRIP)和三角形扇(GL_TRIANGLE_FAN),后面将详细分析。第二个参数暂时设置为0,第三个参数为要绘制的顶点的数量。现在想想,我们如何绘制一个正方形(四边形)呢?最简单的方式就是绘制两个三角形来组合而成,但是这样就需要有6个顶点,实际上一个四边形它之后4和顶点,因此采用这种方式就会有两个顶点是重合的,当要绘制的图形量较大时,就会浪费很多不必要的内存,这时就可以采用绘制三角形扇(GL_TRIANGLE_STRIP)来解决这一问题,具体代码如下所示,其中省略了部分相同的代码。private static final floatvertices = 0.0f, 1.0f, -3.0f, 1.0f, 0.0f, -3.0f, -1.0f, 0.0f, -3.0f, 0.0f, -1.0f, -3.0f;FloatBuffer verticesFloat;verticesFloat = ByteBuffer.allocateDirect(vertices.length*4).asFloatBuffer();verticesFloat.put(vertices);verticesFloat.rewind();gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);其中首先定义了四边形的四个顶点到vertices数组中,然后同样将顶点数组放置到verticesFloat中,最后在调用glDrawArrays绘制时,采用了GL_TRIANGLE_STRIP,绘制的顶点数为4个顶点即可。最后,附上Opengl ES所支持的绘图模式,首先假设我们定义如下一个顶点数组。const GLfloat squareVertices = -1.0,1.0, -6.0, / Top left -1.0, -1.0, -6.0, / Bottom left 1.0,-1.0, -6.0, / Bottom right 1.0, 1.0, -6.0/ Top right;GL_POINTS :单独的将顶点画出来,绘制出来的图形将是耽搁点的形式存在。GL_TRIANGLES:这个参数意味着OpenGL使用三个顶点来组成图形。所以,在开始的三个顶点,将用顶点1,顶点2,顶点3来组成一个三角形。完成后,在用下一组的三个顶点(顶点4,5,6)来组成三角形,直到数组结束。GL_LINES:单独地将直线画出来。行为和 GL_TRIANGLES 类似。GL_LINE_STRIP:连贯地将直线画出来。行为和 GL_TRIANGLE_STRIP 类似。GL_LINE_LOOP:连贯地将直线画出来。行为和 GL_LINE_STRIP 类似,但是会自动将最后一个顶点和第一个顶点通过直线连接起来。GL_TRIANGLE_STRIP:OpenGL的使用将最开始的两个顶点出发,然后遍历每个顶点,这些顶点将使用前2个顶点一起组成一个三角形。所以squareVertices681.0, -1.0, 6.0将与squareVerticies02-1.0, 1.0, -6.0和 squareVerticies35-1.0, -1.0, -6.0 生成一个三角形。 squareVertices9111.0, 1,0, -6.0将与squareVertices35-1.0, -1.0, -6.0和squareVertices681.0, -1.0, 6.0 生成三角形。也就是说,P0,P1,P2这三个点组成一个三角形,P1,P2,P3这三个点也组成一个三角形。GL_TRIANGLE_FAN:在跳过开始的2个顶点,然后遍历每个顶点,让OpenGL将这些顶点于它们前一个,以及数组的第一个顶点一起组成一个三角形。 squareVertices681.0, -1.0, 6.0 将与 squareVerticies35-1.0, -1.0, -6.0 (前一个)和 squareVerticies02-1.0, 1.0, -6.0(第一个).生成一个三角形。也就是说,同样是P0,P1,P2,P3 这4个顶点。l在 GL_TRIANGLE_STRIP 状态下是: P2、P1、P0 ; P3、P2、P1 这2个三角形。l在 GL_TRIANGLE_FAN 状态下是: P2、P1、P0 ; P3、P2、P0 这2个三角形。大家可以分别使用这些不同的模式来绘制同一个物体,比较其效果的变化,上面绘制了三角形和四边形,看上去都是平面图形,下一篇文章,我们将开始学习3D图形的渲染。大家可以先思考一下,3D图形的顶点数据通常会比较多,那么其渲染方式和上面的三角形和四边形的渲染方式是否一样呢?JavaME 3D游戏开发3D图形渲染上一篇文章我们学习了使用JSR239开发包来绘制一些基本的图形,并且通过glColor4f函数为图形设置了颜色,但是到目前为止,我们并没有接触到3D图形,本文将绘制一个真正的3D物体(立方体),并对其进行各种变换操作,比如:旋转、平移、缩放等。绘制3D物体的思路和三角形类似,都需要设置顶点数组及其缓冲区,对于复杂的3D物体,可能有多个顶点,我们除了可以采用上一篇所说的绘制三角形扇之外,还可以通过索引的方式来绘制,既然是索引,就说明我们首先需要定义好所有的顶点,然后这些顶点都会对应一个索引,在绘制的时候我们可以指定每个三角形的三个顶点分别对应于顶点数组中的哪一个索引的坐标。通过索引方式绘制立方体首先,和绘制三角形一样,需要指定立方体的每一个顶点的坐标,代码如下:private static final byte s_cubeVertices = -10, 10, 10, 10, -10, 10, 10, 10, 10, -10, -10, 10, -10, 10, -10, 10, -10, -10, 10, 10, -10, -10, -10, -10, -10, -10, 10, 10, -10, -10, 10, -10, 10, -10, -10, -10, -10, 10, 10, 10, 10, -10, 10, 10, 10, -10, 10, -10, 10, -10, 10, 10, 10, -10, 10, 10, 10, 10, -10, -10, -10, -10, 10, -10, 10, -10, -10, 10, 10, -10, -10, -10;上面的代码中指定了一个立方体的所有顶点的坐标,其中每一行代表一个面的4个顶点,当然这里为了大家能更好的理解,还是有很多重复的点,但是绘制的时候我们会采用索引的方式,多出的点也不会被使用。然后,采用同样的方式将顶点数组中的数据存放到顶点缓冲区中,代码如下:this.cubeVertices = ByteBuffer.allocateDirect(s_cubeVertices.length);cubeVertices.put(s_cubeVertices);cubeVertices.rewind();按照前面所讲的内容,现在我们可以启用顶点缓冲区,然后设置,将该立方体绘制出来,但是这里我们将学习如何采用索引方式来绘制。和顶点缓冲区方式一样,首先需要创建一个索引数组,然后将索引数组转存到索引缓冲区中,代码如下:private static final byte s_cubeIndices = 0, 3, 1, 2, 0, 1, /* front */ 6, 5, 4, 5, 7, 4, /* back */ 8, 11, 9, 10, 8, 9, /* top */ 15, 12, 13, 12, 14, 13, /* bottom */ 16, 19, 17, 18, 16, 17, /* right */ 23, 20, 21, 20, 22, 21 /* left */;this.cubeIndices = ByteBuffer.allocateDirect(s_cubeIndices.length);cubeIndices.put(s_cubeIndices);cubeIndices.rewind();其中每一行都表示一个立方体的一个面,被标注“front”的为前面,其中的前三个数据分别对应s_cubeVertices数组中的元素,也就是说前三个数“0,3,1”表示一个三角形的三个顶点,可以看出每一个顶点都由两个三角形构成。怎么来使用这个索引来绘制立方体呢?代码如下所示。gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glVertexPointer(3, GL10.GL_BYTE, 0, cubeVertices);gl.glDrawElements(GL10.GL_TRIANGLES, 6 * 6, GL10.GL_UNSIGNED_BYTE,cubeIndices);gl.glFinish();大家可以看出,这里除了将绘制函数改成了glDrawElements之外,就没有其他变化,下面我们就重点分析这个函数。glDrawElements 是一个OPENGL的图元绘制函数,从数组中获得数据并渲染图元。函数原型为:void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices );其中:mode:指定绘制图元的类型,可以使用的类型包括上一篇文章所分析的,比如:点,线,三角形扇等。count:为绘制图元的数量。type:为索引数组(indices)中元素的类型,只能是下列值之一: GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INTindices:指向索引数组的指针。glDrawElements函数能够通过较少的函数调用绘制多个几何图元,而不是通过OPENGL函数调用来传递每一个顶点,法线,颜色信息。可以事先准备一系列分离的顶点、法线、颜色数组,并且调用一次glDrawElements把这些数组定义成一个图元序列。当调用glDrawElements函数的时候,它将通过索引使用count个成序列的元素来创建一系列的几何图元。glDrawElements修改的顶点属性在glDrawElements调用返回后的值具有不确定性。
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 专业选择测试题库及答案
- 中职建筑专业试题及答案
- 医药工程专业试题及答案
- 黑龙江省大庆市2025-2026学年高三第一次教学质量检测历史试题(含答案)
- 河北省唐山市2025-2026学年高三上学期开学语文试题(含答案)
- 特种专业试题及答案
- 贵州省毕节市梁才学校2024-2025学年七年级上学期期末定时训练数学试卷(含答案)
- 广东省2025-2026年高三上9月月考地理试卷(部分解析)
- 女神节女装活动策划方案
- 安徽省六安市独山中学2024-2025学年高二上学期11月期中地理试卷(含答案)
- 高考历史一轮复习 阶段性检测卷01 中国古代史(一)(原卷版)
- 贵州省贵阳市2025年中考数学试卷(含解析)
- (2025)社区工作者面试题库及答案
- 民法总则 培训课件
- 村级妇幼专干培训课件
- 教育与心理健康相互促进的双重保障
- 软件项目开发跨部门协作流程
- 2025至2030中国木片加工行业深度研究及发展前景投资评估分析
- 2024年中国电子级硅烷气行业市场调查报告
- 陕西省专业技术人员继续教育2024公需课《专业技术人员能力素质提升》8学时题库及答案
- 产妇护理全套课件
评论
0/150
提交评论