實現一個可滑鼠拖曳旋轉的 3D 線框立方體,包含透視投影、矩陣旋轉變換、即時重繪與雙重緩衝防閃爍。這是 3D 圖形學入門的經典範例,代碼精簡易懂,適合理解 3D 到 2D 投影核心流程。
繼承 JFrame,實作 MouseListener、MouseMotionListener,封裝立方體資料、旋轉角度、顏色陣列與繪製邏輯。
// 假設 Cube 類定義 6 個面的頂點座標
// 每個面 4 個頂點,共 24 個頂點
class Cube {
double[][] x = new double[6][4];
double[][] y = new double[6][4];
double[][] z = new double[6][4];
public Cube() {
// 初始化單位立方體 6 個面頂點 (±0.5, ±0.5, ±0.5)
// 前面 z=0.5
x[0] = new double[]{-0.5, 0.5, 0.5, -0.5};
y[0] = new double[]{-0.5, -0.5, 0.5, 0.5};
z[0] = new double[]{0.5, 0.5, 0.5, 0.5};
// 其餘 5 個面類似...
}
}
final double RAD = Math.PI / 180.0;
double a = angX * RAD, b = angY * RAD;
double sinA = Math.sin(a), sinB = Math.sin(b);
double cosA = Math.cos(a), cosB = Math.cos(b);
for (int i = 0; i < len; i++) {
// Y 軸旋轉
double x1 = x[i] * cosB + z[i] * sinB;
double z0 = -x[i] * sinB + z[i] * cosB;
// X 軸旋轉
double y1 = y[i] * cosA - z0 * sinA;
// 正交投影至螢幕中心 (xp, yp)
xx[i] = xp + (int) Math.rint(x1);
yy[i] = yp - (int) Math.rint(y1); // Y 軸反向
}
g.drawPolygon(xx, yy, len); // 繪製多邊形線框
int doX, doY, angX = 30, angY = 30;
public void mousePressed(MouseEvent e) { doX = e.getX(); doY = e.getY(); }
public void mouseDragged(MouseEvent e) {
angX += e.getY() - doY; // 垂直位移 → X 軸旋轉角度增量
angY += e.getX() - doX; // 水平位移 → Y 軸旋轉角度增量
doX = e.getX(); doY = e.getY();
repaint();
}
// 其餘 MouseListener/ MouseMotionListener 方法留空實作
public void paint(Graphics g) {
// 手動擦除背景(模擬雙重緩衝)
Insets insets = getInsets();
g.setColor(new Color(128, 128, 255));
g.fillRect(insets.left, insets.top, 350, 350);
// 繪製 6 個面
for (int i = 0; i < data.x.length; i++) {
drawPG(g, data.x[i], data.y[i], data.z[i], 150, 150, Col[i]);
}
// 顯示角度
g.setColor(Color.YELLOW);
g.drawString("X=" + angX%360 + " Y=" + angY%360, 10, getSize().height-30);
}
注意:Swing 元件預設支援雙重緩衝,若繼承 JFrame 直接在 paint() 繪製,建議改用 JPanel 覆寫 paintComponent() 並啟用 setDoubleBuffered(true) 獲得更流暢體驗。
javac Gr3d1m.java Cube.java
java Gr3d1m
滑鼠拖曳視窗觀察立方體即時旋轉。可擴展方向:加入 Z 軸旋轉、透視投影(除以 Z)、隱藏線消除、光照著色、載入外部 3D 模型。