利用J2ME开发移动3D游戏之3D图形API

系统 1378 0
    简述

  现在,移动游戏和 移动应用 开发极为热门!游戏中需要有时髦漂亮的图形,其设计标准比以前任何时候都要高。本文将告诉你怎样用酷毙的移动3D图形API为J2ME设备开发3D图形游戏。

  如果你在用MIDP1.0进行用户接口编程,那么有两条路你可以选择:使用高级的UI类或者一切由你自己从头开始。作为游戏开发者,第一种选择往往是不可能的;这是为什么游戏开发者不得不为他们的高级游戏开发自己的3D引擎的原因。无疑,这需要付出大量的时间和努力,而缺乏浮点数支持的CLDC 1.0(MIDP 1.0正是建于其上)对问题的解决没有多大帮助。

  在MIDP 2.0中,有一个可选的叫移动3D图形API的软件包,或者叫JSR 184。该API是第一个基于Java标准开发的移动设备上的 三维图 形软件包。该API既有高级又有低级图形特征;其中,高级特征称为保留模式,低级特征称为立即模式。保留模式使得开发者有可能使用场景图形并使场景中的物体根据虚拟相机和灯光的位置进行自身的着色。立即模式能够允许应用程序直接进行物体绘制。如果需要,可以在同一个应用程序中使用这两种模式。

  本文着重介绍立即模式(在第二篇文章中我们将分析保留模式)。

3D API

  让我们以列举和解释该3D API中的类作为开始。除了这些API外,JSR 184还包含了一个场景图形结构和一个相应的文件格式以有效地管理和配置3D内容。该文件格式定义了一种m3g文件,这种文件典型地从3D建模文件应用程序中转换而来。

  表1.3D API类

描述
AnimationController 控制动画顺序。
AnimationTrack 把一个KeyframeSequence同一个AnimationController相关联。
Appearance 定义一个 网眼 (Mesh)或一个Spring3D的着色属性的一组对象。
Background 定义视图是怎样被清除的。
Camera 一个场景图顶点,它定义了场景中观察者的位置以及从3D到2D的投影。
CompositingMode 一个Appearance类,它封装了每一个像素的合成属性。
Fog 一个Appearance类,它包含了雾化的有关属性。
Graphics3D 一个单独的3D图形上下文。所有的着色操作都是在该类中的render()方法中实现的。
Group 一个场景图形结点,它存储了一个无序的结点集作为它的子结点。
Image2D 一个二维图像,可用于纹理,背景,或者精灵图像。
IndexBuffer 该类定义了如何把顶点连接起来以形成一个 几何 体。
KeyframeSequence 封装了一系列的具有时间戳和矢量值的关键帧的动画数据。
Light 描述了不同类型的光源。
Loader 下载和反串行化图形结点及结点成分,以及整个场景图形。
Material 封装了进行光学计算的材质属性。
Mesh 描述了一个3D对象,它是用多边形面定义的。
MorphingMesh 描述了一个顶点-变形的多边形网眼。
Node 所有场景图形结点的 抽象 基类。其五个具体子类是:Camera,Mesh,Sprite3D,Light和Group。
Object3D 所有可以成为3D世界中组成部分的对象的抽象基类。
PolygonMode 封装了多边形级别属性。
RayIntersection 存储了对于分割的Mesh或Sprite3D的引用,以及有关分割点的信息。
SkinnedMesh 描述了一个框架动画的多边形网眼。
Sprite3D 用3D位置来描述一个2D图像。
Texture2D 封装了一个2D纹理图像和一个属性集合,这些属性指出该图像是如何应用到子网眼上的。
Transform 一个通用的4x4的浮点数矩阵,用来描述一个变换。
Transformable Node和Texture2D类的抽象基类。
TriangleStripArray 定义了一个三角形带数组。
VertexArray 一个整型矢量数组,描述了顶点位置,法线,颜色或者纹理坐标。
VertexBuffer 存储对于VertexArrays的引用,它包含了一个顶点集的位置,颜色,法线,以及纹理坐标。
World 一个特别的Group结点,它作为场景图最顶层的容器。

举例

  我们将开发一个简单的旋转一个多边形的3D应用程序为例。该多边形是一个立方体,它的纹理是一张旧汽车相片。列表1展示了例程midlet的主要类-应用程序的中心类。该类负责创建应用程序并建立起运行MyCanvas的计时器。

  列表1. MIDletMain类

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

public class MIDletMain extends MIDlet {
 static MIDletMain midlet;
 MyCanvas d = new MyCanvas();
 Timer iTimer = new Timer();

 public MIDletMain() {
  this.midlet = this;
 }
 public void startApp() {
  Display.getDisplay(this).setCurrent(d);
  iTimer.schedule( new MyTimerTask(), 0, 40 );
 }
 public void pauseApp() {}
 public void destroyApp(boolean unconditional) {}
 public static void quitApp() {
  midlet.destroyApp(true);
  midlet.notifyDestroyed();
  midlet = null;
 }

 class MyTimerTask extends TimerTask {
  public void run() {
   if( d != null ) {
    d.repaint();
   }
  }
 }
}

  列表2显示了MyCanvas类,该类包含了应用程序的所有图形逻辑。init()方法负责结点的创建,纹理文件的装载并设置纹理,外观和背景也被一起设置。paint()方法负责着色并旋转立方体。图1展示了正在一个模拟器中运行的实际程序。

  列表2. MyCanvas类

import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class MyCanvas extends Canvas {

 private Graphics3D graphics3d;
 private Camera camera;
 private Light light;
 private float angle = 0.0f;
 private Transform transform = new Transform();
 private Background background = new Background();
 private VertexBuffer vbuffer;
 private IndexBuffer indexbuffer;
 private Appearance appearance;
 private Material material = new Material();
 private Image image;

 public MyCanvas() {
  // 创建Displayable对象以探听命令事件
  setCommandListener(new CommandListener() {
   public void commandAction(Command c, Displayable d) {
    if (c.getCommandType() == Command.EXIT) {
     MIDletMain.quitApp();}}
   });
   try { init();}
   catch(Exception e) { e.printStackTrace();}
 }

 /**
 * 组件的初始化
 */
 private void init() throws Exception {
  addCommand(new Command("Exit", Command.EXIT, 1));
  graphics3d = Graphics3D.getInstance();

  camera = new Camera();
  camera.setPerspective( 60.0f,(float)getWidth()/ (float)getHeight(), 1.0f, 1000.0f );

  light = new Light();
  light.setColor(0xffffff);
  light.setIntensity(1.25f);

  short[] vert = {
   5, 5, 5, -5, 5, 5, 5,-5, 5, -5,-5, 5,
   -5, 5,-5, 5, 5,-5, -5,-5,-5, 5,-5,-5,
   -5, 5, 5, -5, 5,-5, -5,-5, 5, -5,-5,-5,
   5, 5,-5, 5, 5, 5, 5,-5,-5, 5,-5, 5,
   5, 5,-5, -5, 5,-5, 5, 5, 5, -5, 5, 5,
   5,-5, 5, -5,-5, 5, 5,-5,-5, -5,-5,-5 };

  VertexArray vertArray = new VertexArray(vert.length / 3, 3, 2);
  vertArray.set(0, vert.length/3, vert);

  //立方体的各个结点法线
  byte[] norm = {
   0, 0, 127, 0, 0, 127, 0, 0, 127, 0, 0, 127,
   0, 0,-127, 0, 0,-127, 0, 0,-127, 0, 0,-127,
   -127, 0, 0, -127, 0, 0, -127, 0, 0, -127, 0, 0,
   127, 0, 0, 127, 0, 0, 127, 0, 0, 127, 0, 0,
   0, 127, 0, 0, 127, 0, 0, 127, 0, 0, 127, 0,
   0,-127, 0, 0,-127, 0, 0,-127, 0, 0,-127, 0 };

  VertexArray normArray = new VertexArray(norm.length / 3, 3, 1);
  normArray.set(0, norm.length/3, norm);

  //各个结点的纹理坐标
  short[] tex = {
   1, 0, 0, 0, 1, 1, 0, 1,
   1, 0, 0, 0, 1, 1, 0, 1,
   1, 0, 0, 0, 1, 1, 0, 1,
   1, 0, 0, 0, 1, 1, 0, 1,
   1, 0, 0, 0, 1, 1, 0, 1,
   1, 0, 0, 0, 1, 1, 0, 1 };

  VertexArray texArray = new VertexArray(tex.length / 2, 2, 2);
  texArray.set(0, tex.length/2, tex);

  int[] stripLen = { 4, 4, 4, 4, 4, 4 };

  // 对象的VertexBuffer
  VertexBuffer vb = vbuffer = new VertexBuffer();
  vb.setPositions(vertArray, 1.0f, null);
  vb.setNormals(normArray);
  vb.setTexCoords(0, texArray, 1.0f, null);

  indexbuffer = new TriangleStripArray( 0, stripLen );

  //纹理图像
  image = Image.createImage( "/pic1.png" );
  Image2D image2D = new Image2D( Image2D.RGB, image );
  Texture2D texture = new Texture2D( image2D );
  texture.setFiltering(Texture2D.FILTER_NEAREST,
  Texture2D.FILTER_NEAREST);
  texture.setWrapping(Texture2D.WRAP_CLAMP,Texture2D.WRAP_CLAMP);
  texture.setBlending(Texture2D.FUNC_MODULATE);

  // 创建外观(Appearance)对象
  appearance = new Appearance();
  appearance.setTexture(0, texture);
  appearance.setMaterial(material);
  material.setColor(Material.DIFFUSE, 0xFFFFFFFF);
  material.setColor(Material.SPECULAR, 0xFFFFFFFF);
  material.setShininess(100.0f);

  background.setColor(0xffffcc);
 }

 protected void paint(Graphics g) {
  graphics3d.bindTarget(g, true,
   Graphics3D.DITHER |
   Graphics3D.TRUE_COLOR);
   graphics3d.clear(background);

  //设置照相机
  Transform transform = new Transform();
  transform.postTranslate(0.0f, 0.0f, 30.0f);
  graphics3d.setCamera(camera, transform);

  //设置灯光
  graphics3d.resetLights();
  graphics3d.addLight(light, transform);

  //设置旋转
  angle += 1.0f;
  transform.setIdentity();
  transform.postRotate(angle, 1.0f, 1.0f, 1.0f);

  graphics3d.render(vbuffer, indexbuffer, appearance, transform);
  graphics3d.releaseTarget();
 }
}

利用J2ME开发移动3D游戏之3D图形API
图1 正在一个模拟器中运行的应用程序

小结

  JSR 184对于可以运行MIDP 2.0的设备来说,是一个节省时间和空间的可选的软件开发包。它允许开发者使用两种图形方式-保留模式和立即模式-来产生3D图形。本文集中讲述了立即模式,并给出一个例子程序来说明怎样使用3D API。

利用J2ME开发移动3D游戏之3D图形API


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论