在 Java 3D 圖形程式開發系列的第一篇中,我們已探討如何建立基本形狀、光源與背景。本文將深入實作 Checkers3D 程式的核心場景——浮動球體,並完整解析從地板建構、觀察者定位到場景圖視覺化的完整流程。
地板由交錯的藍綠磁磚與座標軸標籤組成,場景圖結構如圖 5 所示。透過 CheckerFloor 類別封裝建構邏輯,只需一行程式碼即可加入場景:
sceneBG.addChild(new CheckerFloor().getBG()); // 添加地板
CheckerFloor 建構子使用雙重迴圈初始化兩個 ArrayList:blueCoords 儲存藍色磁磚座標,greenCoords 儲存綠色磁磚座標。座標與顏色一併傳遞給 ColouredTiles 物件(繼承自 Shape3D),直接加入地板分支圖:
floorBG.addChild(new ColouredTiles(blueCoords, blue));
floorBG.addChild(new ColouredTiles(greenCoords, green));
原點處的紅色標記方格同樣以四個 Point3f 定義頂點(逆時針順序),並稍微抬高(Y=0.01)以避免與磁磚重疊產生 Z-fighting。
ColouredTiles 繼承 Shape3D,使用 QuadArray 描述一系列四邊形幾何體。建構子指定頂點格式為座標與顏色:
plane = new QuadArray(coords.size(), GeometryArray.COORDINATES | GeometryArray.COLOR_3);
createGeometry() 方法將 ArrayList 轉為陣列並設定幾何資料:
Point3f[] points = new Point3f[numPoints];
coords.toArray(points);
plane.setCoordinates(0, points);
Color3f[] cols = new Color3f[numPoints];
for (int i = 0; i < numPoints; i++) cols[i] = col;
plane.setColors(0, cols);
關鍵點:四邊形頂點必須按逆時針順序排列,確保前面朝向 Y 軸正方向,才能正確接受光照與背面剔除。因不包含法線資訊,故直接在幾何體設定固定顏色(setColors),不受光源影響。
透過 PolygonAttributes 關閉背面剔除(CULL_NONE),使磁磚雙面可見:
Appearance app = new Appearance();
PolygonAttributes pa = new PolygonAttributes();
pa.setCullFace(PolygonAttributes.CULL_NONE);
app.setPolygonAttributes(pa);
setAppearance(app);
使用 Java 3D 內建 Text2D 工具類建立 2D 文字貼圖,預設隱藏背面。標籤位置由 TransformGroup 控制:
TransformGroup tg = new TransformGroup();
Transform3D t3d = new Transform3D();
t3d.setTranslation(vertex); // 標籤位置
tg.setTransform(t3d);
tg.addChild(message);
floorBG.addChild(tg);
建議:避免在 Text2D 建構子使用過大字體大小,改以 TransformGroup 縮放調整。
視圖分支圖(圖 7)由 SimpleUniverse 自動建構。觀察者位置透過 ViewingPlatform 的 TransformGroup 設定:
ViewingPlatform vp = su.getViewingPlatform();
TransformGroup steerTG = vp.getViewPlatformTransform();
Transform3D t3d = new Transform3D();
steerTG.getTransform(t3d);
t3d.lookAt(USERPOSN, new Point3d(0,0,0), new Vector3d(0,1,0));
t3d.invert();
steerTG.setTransform(t3d);
lookAt() 參數依序為:觀察者位置 USERPOSN (0,5,20)、注視點原點、向上向量 Y 軸。因座標系相對關係,必須呼叫 invert() 反轉變換矩陣。
採用 OrbitBehavior 實現滑鼠/鍵盤導航:
OrbitBehavior orbit = new OrbitBehavior(canvas3D, OrbitBehavior.REVERSE_ALL);
orbit.setSchedulingBounds(bounds);
vp.setViewPlatformBehavior(orbit);
REVERSE_ALL 使觀察點移動方向與滑鼠一致。註:FPS 類遊戲需更精確控制,後續將自行實作行為類別。
使用 Dan Selman 的 Java3dTree 套件(j3dtree.jar)生成文字模式場景圖樹狀圖(圖 9)。整合步驟:
Java3dTree j3dTreej3dTree = new Java3dTree();j3dTree.recursiveApplyCapability(sceneBG);j3dTree.updateNodes(su);注意:僅對內容分支圖調整權限,視圖分支圖會產生警告但不影響功能。編譯執行時需將 j3dtree.jar 加入 classpath。