JSR 184 (Mobile 3D Graphics API) 為 MIDP 提供保留模式 3D 渲染。本文示範最小可運行範例:載入 swerve.m3g 場景,設定攝影機視口,啟動線程循環呼叫 World.animate() 並 Graphics3D.render()。
apps/Demo3D/res/com/superscape/m3g/wtksamples/retainedmode/content/swerve.m3g 複製至專案 res/ 目錄。First3DCanvaspublic class First3DCanvas extends Canvas implements Runnable {
private World myWorld;
private Graphics3D g3d = Graphics3D.getInstance();
private Camera cam;
private int viewport_x, viewport_y, viewport_width, viewport_height;
private long worldStartTime;
public First3DCanvas() {
new Thread(this).start();
try {
myWorld = (World) Loader.load("/swerve.m3g")[0];
viewport_width = getWidth(); viewport_height = getHeight();
cam = myWorld.getActiveCamera();
// 依投影類型調整視口長寬比
float[] params = new float[4];
if (cam.getProjection(params) != Camera.GENERIC) {
float waspect = (float)viewport_width / viewport_height;
if (waspect < params[1]) {
viewport_height = (int)(viewport_width / params[1]);
viewport_y = (getHeight() - viewport_height) / 2;
} else {
viewport_width = (int)(viewport_height * params[1]);
viewport_x = (getWidth() - viewport_width) / 2;
}
}
worldStartTime = System.currentTimeMillis();
} catch (Exception e) { e.printStackTrace(); }
}
protected void paint(Graphics g) {
g.setColor(0); g.fillRect(0, 0, getWidth(), getHeight());
g3d.bindTarget(g);
g3d.setViewport(viewport_x, viewport_y, viewport_width, viewport_height);
int validity = myWorld.animate((int)(System.currentTimeMillis() - worldStartTime));
try { g3d.render(myWorld); } finally { g3d.releaseTarget(); }
}
public void run() {
while (true) {
repaint(viewport_x, viewport_y, viewport_width, viewport_height);
try { Thread.sleep(30); } catch (InterruptedException ignored) {}
}
}
}
Loader.load() 返回 Object[],首個元素通常為 World。World.animate(time) 更新場景動畫狀態,返回有效時間。Graphics3D.bindTarget/releaseTarget 必須成對調用,綁定 2D Graphics 作為渲染目標。repaint(),實際幀率受裝置效能影響。public class First3DMIDlet extends MIDlet {
private First3DCanvas canvas = new First3DCanvas();
public void startApp() { Display.getDisplay(this).setCurrent(canvas); }
public void pauseApp() {}
public void destroyApp(boolean u) {}
}