2014年2月1日 星期六

Java Bindings for OpenGL

處理3D之API較著名的有OpenGL、PHIGS、DirectX等,以Java開發,則可使用Java 3D API。此外,針對處理3D繪圖及音效,Java另有Java Bindings for OpenGL、Java Bindings for OpenAL、Lightweight Java Game Library、Processing、AgentFX、Xith3D、jME、jgeom、jPCT等API。

在Java中,欲處理3D可使用Java 3D API,除此之外,對於習慣OpenGL的開發者而言,Java Bindings for OpenGL (JOGL) 則是另一個不錯的選擇。

OpenGL其前身為IRIS GL,IRIS GL是Silicon Graphics Inc. (SGI) 為改進另一3D公開標準PHIGS (Programmer's Hierarchical Interactive Graphics System) 所開發的API,但由於SGI在開發IRIS GL時,其部份API並非與3D有關,而是與非標準之視窗、鍵盤及滑鼠有關,且由於牽涉到專利權的關係,因此SGI並未將IRIS GL定位為開放標準。至1992年,SGI以IRIS GL為基礎,宣佈成立OpenGL Architecture Review Board (OpenGL ARB),以開發及訂定OpenGL規格書。1995年,由於Microsoft發表Direct3D成為SGI OpenGL的最大競爭對手,此舉對SGI造成不少威脅,因此雙方於1997達成協議,試圖於兩者間建立標準的介面,但此計劃後來亦不了了之。

基本上,JOGL並非以Java重新開發OpenGL (雖然部份OpenGL的方法確實以Java改寫),而是在Java與OpenGL之間擔任中間銜接的角色,如同其名稱Binding一般,以下為各類程式語言與OpenGL間之銜接函式庫,JOGL則為其中之一:
  • Delphi: Delphi OpenGL Toolkit (DOT).
  • Fortran: Fortran 90 Bindings for OpenGL (F90GL).
  • Java: Java Bindings for OpenGL (JOGL).
  • Lightweight Java Game Library (LWJGL).
  • Perl: Perl OpenGL (POGL).
  • Python: Python OpenGL Bindings (PyOpenGL).
  • Ruby: ruby-opengl.
  • Visual Basic: OpenGL 1.1 ActiveX Control.
以Microsoft Windows作業系統 (586 CPU) 為例,待下載JOGL ZIP檔案及解壓縮之後,可在其lib目錄找到以下執行JOGL所需的檔案,其中GlueGen為透過JNI (Java Native Interface) 建立JOGL及JOAL (Java Bindings for OpenAL) 與OpenGL及OpenAL函式庫間之介面:
  • jogl.jar
  • jogl.dll
  • jogl_awt.dll
  • jogl_cg.dll
  • gluegen-rt.jar
  • gluegen-rt.dll
以JDK 7.0及Microsoft Windows作業系統為例,將上述檔案複製至C:\jdk1.7.0\jre\lib\ext目錄下,並需設定CLASSPATH、PATH與java.library.path環境變數,分別設定上述Java Archive檔案、DLL檔案與其所在之目錄,例如:
  • JAVA_EXT=C:\jdk1.7.0\jre\lib\ext
  • CLASSPATH=%CLASSPATH%;%JAVA_EXT%\jogl.jar;%JAVA_EXT%\gluegen-rt.jar
  • PATH=%PATH%;%JAVA_EXT%\jogl.dll;%JAVA_EXT%\gluegen-rt.dll
  • java.library.path=%JAVA_EXT%
至於JOGL API說明文件,除了標準的JOGL API文件之外,在使用JOGL時,可同時參考OpenGL規格書及使用手冊。OpenGL規格書可自http://www.opengl.org/documentation/specs/下載,此外以下為筆者常參考的使用手冊,其中第一、二、三本分別俗稱Red Book、Blue Book與Orange Book:
  • OpenGL Architecture Review Board, Dave Shreiner, Mason Woo, Jackie Neider, “OpenGL Programming Guide: The Official Guide to Learning OpenGL, Version 2 (5th Edition)”, Addison-Wesley Professional, 2005.
  • OpenGL Architecture Review Board, Dave Shreiner, “OpenGL Reference Manual: The Official Reference Document to OpenGL, Version 1.4 (4th Edition)”, Addison-Wesley Professional, 2004.
  • Randi J. Rost, "OpenGL Shading Language (2nd Edition)”, Addison-Wesley Professional, 2006.
  • Richard S. Wright, Benjamin Lipchak, "OpenGL SuperBible (3rd Edition)”, SAMS, 2004.
  • Tom McReynolds, David Blythe, "Advanced Graphics Programming Using OpenGL”, Morgan Kaufmann, 2005.
  • Dave Astle, Kevin Hawkins, "Beginning OpenGL Game Programming", Course Technology PTR, 2004.
  • Kevin Hawkins, Dave Astle, Andre LaMothe, "OpenGL Game Programming", Course Technology PTR, 2002.
  • Dave Astle, "More OpenGL Game Programming", Course Technology PTR, 2005.
JOGL的主要套件包括:
  • javax.media.opengl
  • javax.media.opengl.glu
  • com.sun.opengl.cg
  • com.sun.opengl.util
  • com.sun.opengl.util.j2d
  • com.sun.opengl.util.texture
  • com.sun.opengl.util.texture.spi
其中,javax.media.opengl套件包括所有OpenGL 2.0的方法,並支援Java AWT與Java Swing繪圖及事件之API。javax.media.opengl.glu套件為支援OpenGL Graphics System Utility (GLU) 之API套件。com.sun.opengl.util套件為支援OpenGL Utility Toolkit (GLUT) 之API套件,GLUT此公用函式庫提供OpenGL 2.0額外繪製3D幾何圖形與動畫等功能。

在介紹JOGL的程式架構之前,首先介紹如何以C語言開發OpenGL程式,藉此比較C與Java兩者間之差異,請參考以下範例:


/* 以C語言開發OpenGL程式 */
/* DrawRect.c         */

#include <windows.h>
#include <gl/glut.h>

/* 主程式 */
void main(void) {
  /* 設定顯示模式 */
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
  /* 建立視窗 */
  glutCreateWindow("DrawRect");
  /* 定義繪圖函式為自訂之RenderScene */
  glutDisplayFunc(RenderScene);
  /* 定義當視窗大小改變時所呼叫之函式 */
  glutReshapeFunc(ChangeSize);
  /* 自訂函式以初始化環境 */
  Initialize();
  /* 進入OpenGL迴圈 */
  glutMainLoop();
}

/* 初始化環境 */
void Initialize(void) {
  /* 以指定顏色清除背景 */
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}

/* 繪圖 */
void RenderScene(void) {
  /* 以目前之顏色清除視窗 */
  glClear(GL_COLOR_BUFFER_BIT);
  /* 設定目前繪圖顏色為紅色 */
  glColor3f(1.0f, 0.0f, 0.0f);
  /* 繪製矩形並以目前顏色填滿面積 */
  glRectf(100.0f, 150.0f, 150.0f, 100.0f);
  /* 即刻執行OpenGL指令 */
  glFlush();
}

/* 當視窗大小改變時 */
void ChangeSize(GLsizei w, GLsizei h) {
  /* 設定視界大小為視窗之大小 */
  glViewport(0, 0, w, h);
  /* 重設座標系統*/
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  if (w <= h) 
    glOrtho (0.0f, 250.0f, 0.0f, 250.0f*h/w, 1.0, -1.0);
  else 
    glOrtho (0.0f, 250.0f*w/h, 0.0f, 250.0f, 1.0, -1.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}


以C語言開發OpenGL程式,其中較重要的方法為:
  • glutDisplayFunc():設定自訂的繪圖函式,為GLUT方法。
  • glutReshapeFunc():設定當視窗大小改變時所呼叫的函式,為GLUT方法。
  • glutMainLoop():進入OpenGL迴圈以偵測OpenGL相關狀態的改變,為GLUT方法。
在JOGL中,則是將上述的方法包裝成為javax.media.opengl.GLEventListener介面,如同Java Event Listener一般,其方法包括:
  • init(GLAutoDrawable drawable)初始化JOGL,可在此方法中定義JOGL之環境,如設定光源位置 (Light Position)、透視度 (Perspective) 等、或載入貼圖所需之圖像檔案,init()方法會在初次建立OpenGL Context之後執行,如同上述範例的Initialize()自訂函式般。
  • display(GLAutoDrawable drawable)如同上述範例的glutDisplayFunc()方法中所定義的RenderScene()函式般,用以繪製圖形。
  • reshape(GLAutoDrawable drawable, int x, int y, int width, int height)如同上述範例的glutReshapeFunc()方法中所定義之ChangeSize()函式般,當視窗大小改變時所呼叫的方法,通常在此方法中重設透視度 (Perspective) 及視界 (Viewport)。
  • displayChanged(GLAutoDrawable drawable, boolean mode, boolean device)當顯示模式 (Display Mode) 或顯示裝置 (Display Device) 改變時所呼叫的方法,例如由16位元改為32位元顯示模式、或在支援虛擬多螢幕的顯示裝置中由一個螢幕移至另一螢幕。因此若無前述之改變,通常不需實作此方法之內容。
因此在Java中,可透過實作javax.media.opengl.GLEventListener介面及其所提供的方法設計JOGL程式。欲註冊GLEventListener介面,可使用GLCanvasGLJPanel類別的addGLEventListener()方法建立其事件Listener,兩者之差別在於前者繼承自java.awt.Canvas類別,以支援Java AWT之繪圖,後者則繼承自javax.swing.JPanel類別,以支援Java Swing之繪圖。

GLCanvas類別實作GLEventListener介面的程式架構大致如下:


import java.awt.*;
import java.awt.event.*;

// JOGL
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import com.sun.opengl.util.*;

public class JOGLDemo extends Frame implements GLEventListener {
  ...
  // 建構函式
  public JOGLDemo(){
    ...
    // 建立GLCanvas物件 
    GLCanvas canvas = new GLCanvas();

    // 註冊GLEventListener
    canvas.addGLEventListener(this);

    // 將GLCanvas物件加入Frame中
    this.add(canvas);
    ...
  }

  // 實作GLEventListener介面的方法
  // 初始化JOGL
  public void init(GLAutoDrawable drawable){...}

  // 繪製圖形
  public void display(GLAutoDrawable drawable){...}

  // 當視窗大小改變時
  public void reshape(GLAutoDrawable drawable,
    int x, int y, int width, int height){...}

  // 當顯示模式或裝置改變時
  public void displayChanged(GLAutoDrawable drawable, 
    boolean modeChanged, boolean deviceChanged){...}
}


GLJPanel類別實作GLEventListener介面的程式架構大致如下:


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

// JOGL
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import com.sun.opengl.util.*;

public class JOGLDemo extends JFrame implements GLEventListener {
  ...
  // 建構函式
  public JOGLDemo(){
    ...
    // 建立GLJPanel物件
    GLJPanel glpanel = new GLJPanel();

    // 註冊GLEventListener
    glpanel.addGLEventListener(this);

    // 將GLJPanel物件加入JFrame中
    this.add(glpanel);
    ...
  }

  // 實作GLEventListener介面的方法
  // 初始化JOGL
  public void init(GLAutoDrawable drawable){...}

  // 繪製圖形
  public void display(GLAutoDrawable drawable){...}

  // 當視窗大小改變時
  public void reshape(GLAutoDrawable drawable,
    int x, int y, int width, int height){...}

  // 當顯示模式或裝置改變時
  public void displayChanged(GLAutoDrawable drawable, 
    boolean modeChanged, boolean deviceChanged){...}
}


【執行結果】


【參考資料】

[1] Java Platform, Standard Edition 7, API Specification.
[2] Lance Williams, "Pyramidal Parametrics", Computer Graphics, Vol. 17 No.3, July 1983.
[3] Randi J. Rost, "OpenGL Shading Language (2nd Edition)", Addison-Wesley, 2006.
[4] Richard S. Wright, Benjamin Lipchak, "OpenGL SuperBible (3rd Edition)", SAMS, 2004.
[5] Delphi OpenGL Toolkit.
[6] Fortran 90 Bindings for OpenGL.
[7] GlueGen.
[8] JOAL.
[9] JOGL.
[10] LWJGL.
[11] OpenGL.
[12] Perl OpenGL.
[13] Python OpenGL Bindings.
[14] ruby-opengl.
[15] 黃嘉輝,完全探索網路程式設計 - 使用Java,上奇資訊。

© Chia-Hui Huang

沒有留言:

張貼留言