簡述
現在,移動游戲和移動應用開發極為熱門!游戲中需要有時髦漂亮的圖形,其設計標准比以前任何時候都要高。本文將告訴你怎樣用酷斃的移動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();
}
}
圖1 正在一個模擬器中運行的應用程序
小結
JSR 184對於可以運行MIDP 2.0的設備來說,是一個節省時間和空間的可選的軟件開發包。它允許開發者使用兩種圖形方式-保留模式和立即模式-來產生3D圖形。本文集中講述了立即模式,並給出一個例子程序來說明怎樣使用3D API。