立即模式需手工編寫每個頂點,開發效率低、維護難。保留模式引入場景圖概念:設計師用 3D Max、Blender 等工具構建場景,導出標準 M3G 格式(JSR 184 規定),程序僅需加載並渲染,實現美術與邏輯解耦。
| 工具 | 授權 | M3G 支持 | 適用場景 |
|---|---|---|---|
| 3ds Max | 商業(昂貴) | 原生導出 M3G | 專業團隊、商業項目 |
| Superscape Swerve Studio | 商業 | 深度集成 | 特定廠商項目、高級動畫 |
| Blender | 開源免費 | 需插件/腳本導出 | 獨立開發者、學習研究 |
Blender 雖無官方 M3G 導出器,但開源社區活躍,轉換工具快速迭代中,極具性價比。
World myWorld = (World) Loader.load("/pogoroo.m3g")[0];
Loader.load() 返回對象數組,首個元素通常為 World(場景根容器)。
Group rooGroup = (Group) myWorld.find(POGOROO_ID); // 袋鼠模型組
Group camGroup = (Group) myWorld.find(CAMERA_ID); // 相機組
Group transGroup = (Group) myWorld.find(TRANSFORM_ID); // 動畫變換組
AnimationController animCtrl = (AnimationController) myWorld.find(ANIM_ID); // 動畫控制器
// 計算動畫時長
int animLength = 1000; // 默認 1 秒
AnimationTrack track = transGroup.getAnimationTrack(0);
if (track != null) {
KeyframeSequence ks = track.getKeyframeSequence();
if (ks != null) animLength = ks.getDuration();
}
關鍵點:M3G 文件中對象通過唯一 User ID(整數)標識,導出時由建模工具分配,程序端需硬編碼或讀取配置對應。
void setupAspectRatio() {
viewport_x = 0; viewport_y = 0;
viewport_width = canvas.getWidth();
viewport_height = canvas.getHeight();
Camera cam = myWorld.getActiveCamera();
float[] params = new float[4];
int type = cam.getProjection(params);
if (type != Camera.GENERIC) {
float waspect = (float)viewport_width / viewport_height;
if (waspect > params[1]) { // 以寬為基準
float h = viewport_width / params[1];
viewport_height = (int)h;
viewport_y = (canvas.getHeight() - viewport_height) / 2;
} else { // 以高為基準
float w = viewport_height * params[1];
viewport_width = (int)w;
viewport_x = (canvas.getWidth() - viewport_width) / 2;
}
}
}
確保 3D 投影不變形,畢竟手機屏幕比例千差萬別。
class RefreshTask extends TimerTask {
public void run() {
if (canvas != null && g3d != null && world != null) {
int time = (int)System.currentTimeMillis();
world.animate(time); // 關鍵:推進動畫時間軸
canvas.repaint(viewport_x, viewport_y, viewport_width, viewport_height);
}
}
}
World.animate(time) 根據毫秒時間戳更新所有 AnimationController 狀態,必須在渲染前調用。
核心類 Example3D 繼承 MIDlet 並實現 CommandListener,內部類 ExampleCanvas 轉發 paint() 到外部 paint(Graphics) 方法,實現關注點分離。關鍵渲染代碼:
public void paint(Graphics g) {
// 視口變化時清屏
if (clip 區域不匹配) g.fillRect(0,0,width,height);
if (g3d != null && world != null) {
g3d.bindTarget(g);
g3d.setViewport(viewport_x, viewport_y, viewport_width, viewport_height);
g3d.render(world); // 一鍵渲染整個場景圖
g3d.releaseTarget();
}
}
保留模式下 render(World) 替代了立即模式的手動 render(VertexBuffer,...),場景圖自動遍歷所有可見節點。
模擬器截圖顯示袋鼠模型與場景完美呈現。美術修改模型(如換材質、調動畫)只需重新導出 M3G,**Java 代碼零修改**,極大降低迭代成本。
保留模式是 J2ME 3D 開發的工業化路徑:建模工具 → M3G → Loader → World → render()。掌握 Loader、World.find()、World.animate()、視口適配四大核心 API,即可將 3D 內容生產管線引入項目,實現美術與程序並行開發。