然后出現了JOGL Java也許是最流行的真正的面向對象的編程語言。有許多用Java去結合OpenGL的嘗試,但是第一個被大家認可并注意的是Java對于OpenGl的綁定(Java Bindings for OpenGL), 或者稱為JOGL.理由是它得到Sun(Java的創建者)和SGI(OpenGL的創建者)的支持。 如今,Sun的游戲開發小組正在開發JOGL.它是以肯。拉塞爾和克里斯??颂m開發的Jungle開始的。拉塞爾是Sun的員工,研發“HotSpot虛擬機”,擁有多年的三維經驗??颂m則研發“荒謬的游戲”,對三維圖形學也相當有經驗。 我個人對他們以及所有其它工作在JOGL上的人表示感謝。曾經有許多想通過友好的Java API來使用OpenGL的嘗試――其中包括Java 3D, OpenGL for Java Technology (gl4java)(用于Java技術的OpenGL),Lightweight Java Game Library (LWJGL)(輕量級的Java游戲庫)。JOGL是第一個使我感到滿意的。 JOGL是Sun支持的對于OpenGl的Java類綁定。哇!這句話說得太妙了。 OpenGL被用來展示三維模型。它強大、快速,而且可能是自Swing出現以來最棒的一樣東西。通過JOGL來使用OpenGL,你可以制作出很酷的游戲或是模型位置什么的,而在這之前創建它們需要非常昂貴的成本。有人寫了很厚很厚的書來描述OpenGL,當你熟悉了它們以后這些書會很有用,但現在不行。你必須學習展現在你面前的OpenGL是如何使用Java API的。同樣你還得看一下關于net.java.games.jogl.*的基礎介紹,可能還得補習一下數學知識。 獲取JOGL? 如果你想使用JOGL,你需要得到jogl.jar以及附帶的本機代碼。我希望有一天它可以成為Java的標準安裝,但現在它只是一個夢想。 第一步是要找到你的操作系統所對應的包,并進行解壓縮。我是在http://www.javaworld.com/javaworld/jw-02-2005/jw-0221-jogl.html#resources上找到的。不同的操作系統有所區別,但需要安裝2個部分。系統的classpath里一定要有jogl.jar,而且binary庫必須放在和你操作系統的庫同一個地方。如果比較幸運的話,安裝程序可以為你完成這些。如果你沒有安裝程序而且不知道該上哪里去尋找關于設置計算機的信息的話,你可以從我提供一個鏈接Resources開始搜索。我們的第一篇代碼是特別用來測試環境是否安裝正確的,所以對于測試安裝你不必緊張。 JOGL的Javadocs 同樣可以在和JOGL 的binary 發布版一樣的位置獲得Javadocs.Javadocs將會以類似jogl-1.0-usrdoc.tar的名字而命名。 如果你瀏覽一下net.java.games.jogl包,你很快會注意到有些類非常大。GL便是一個完美的例子。別被這個嚇跑了,你很快能發現只需一點點JOGL的知識,你就可以完成一些相當復雜的事了?,F在你需要掃視一下的類有:*GLDrawable *GLCanvas *GLJPanel *GLCapabilities *GLDrawableFactory 這些是連接圖形世界基本的接口。如果你還記得,前面我提到對于初學OpenGL的人來說,有一個很大的缺點,那就是缺乏窗口系統的標準。對應于C語言,GLUT起到了相當大的作用。而我們則有Swing和AWT(抽象窗口工具箱)。很可能你已經使用過AWT或者Swing了,所以你不會感到自己在從頭學起。這是件非常好的事情。在通過了非常簡短的關于把JOGL組件放置到屏幕上的介紹以后,我們不需要多長時間就可以運行出一個相當酷而且流行的程序了。 GlueGen……幾乎和JOGL一樣酷? 你應該意識到,OpenGL是為C程序員而寫的。這意味著Java想要利用它,必須要用到本機接口。不那么有趣的JNI(Java本機接口)必須用來進行此連接。OpenGL太大了,手寫所有的連接太費時。想稍微做出一點復雜的程序,有許多特別出售的特性,OpenGL則保持改進,那意味著得有相應的變化來跟上OpenGL的步伐。簡而言之,對于任何試著寫與OpenGL保持同步,包含所有Java到本機的接口的代碼的嘗試,是非常困難的。 讓我們進入JOGL家族看看。他們打算利用C頭文件寫一些代碼來實現一切JNI做的事。他們管這個叫做GlueGen.GlueGen解析C頭文件然后魔法般地創建出Java和JNI代碼以便連接到本機庫。這意味著OpenGL的升級可以迅速地在JOGL里體現。 Hello World! 我是一個很傳統的人,所以當然我們將從“你好世界”程序開始。這個“你好世界”程序將檢驗我們的安裝是否全部或者一部分安裝正確?;貞浺幌掳惭bJOGL有2個部分,分別是jar文件里的Java庫以及其它庫的本機代碼。 以下是我們的程序:import net.java.games.jogl.*;public class HelloWorld { public static void main (String args[]) { try { System.loadLibrary("jogl"); System.out.println( "Hello World! (The native libraries are installed.)" ); GLCapabilities caps = new GLCapabilities(); System.out.println( "Hello JOGL! (The jar appears to be available.)" ); } catch (Exception e) { System.out.println(e); } }} 首先,這個程序測試了本機庫和Java庫是否已經安裝正確了。只有當jogl.jar和本機庫(名字諸如libjogl.jnilib或者jogl.dll)兩者都安裝好了的時候,JOGL才算是安裝完全的。如果本機庫不可用,程序會拋java.lang.UnsatisfiedLinkError例外。如果classpath里沒有安裝JAR,程序則根本編譯都通不過。Javac編譯器會報諸如此類的錯“net.java.games.jogl包不存在”。當這個程序編譯通過且運行起來沒有異常的話,你可以繼續學習JOGL了。 一個好的模板 這個模板由兩個類組成。第一個是如下所示的SimpleJoglApp,第二個是在簡短說明之后的SimpleGLEventListener.你必須輸入兩個類來編譯模板。主程序如下:import java.awt.*;import java.awt.event.*;import javax.swing.*;import net.java.games.jogl.*;/** * This is a basic JOGL app. Feel free to * reuse this code or modify it. * 這是個基礎的JOGL程序,你可以隨意重用該代碼或者修改它。 */public class SimpleJoglApp extends JFrame { public static void main(String[] args) { final SimpleJoglApp app = new SimpleJoglApp(); // show what we've done //看一下我們做了什么 SwingUtilities.invokeLater ( new Runnable() { public void run() { app.setVisible(true); } } ); } public SimpleJoglApp() { //set the JFrame title //設置JFrame標題 super("Simple JOGL Application"); //kill the process when the JFrame is closed //當JFrame關閉的時候,結束進程 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //only three JOGL lines of code …… and here they are //只有三行JOGL代碼 …… 如下 GLCapabilities glcaps = new GLCapabilities(); GLCanvas glcanvas = GLDrawableFactory.getFactory()。createGLCanvas(glcaps); glcanvas.addGLEventListener(new SimpleGLEventListener()); //add the GLCanvas just like we would any Component //像其它組件一樣把GLCanvas加入 getContentPane()。add(glcanvas, BorderLayout.CENTER); setSize(500, 300); //center the JFrame on the screen //使JFrame顯示在屏幕中央 centerWindow(this); } public void centerWindow(Component frame) { Dimension screenSize = Toolkit.getDefaultToolkit()。getScreenSize(); Dimension frameSize = frame.getSize(); if (frameSize.width > screenSize.width ) frameSize.width = screenSize.width; if (frameSize.height > screenSize.height) frameSize.height = screenSize.height; frame.setLocation ( (screenSize.width - frameSize.width ) >> 1, (screenSize.height - frameSize.height) >> 1 ); }} 代碼就是這些。讓我們把注意力集中在第一個類中與JOGL相關的三行代碼上。首先: 這決定了我們的JOGL庫和JVM可以使用哪些OpenGL/圖形特色。 接著:GLCanvas glcanvas = GLDrawableFactory.getFactory()。createGLCanvas(glcaps); 我們不能創建GLCanvas或者GLJPanel.我們得用GLDrawableFactory來創建它們。所以我們用GLDrawableFactory的靜態方法getFactory()取得了GLDrawableFactory. 現在我們有GLDrawableFactory了。所以我們用createGLCanvas()方法來創建了可以往上畫畫的GLCanvas.如果我們不需要AWT組件,而是Swing組件,則可以用createGLJPanel()方法。 注意我們把先前創建的GLCapabilities對象傳了進去。這可以使我們創建的GLDrawable適當的所創建。 最后,我們準備往GLCanvas上加GLEventListener. 我們對GLEventListener的實現是SimpleGLEventListener.它負責當接到GLDrawable或我們的或只是GLCanvas的調用時,所需要完成的所有繪圖工作。你將會看到,我不打算在這個程序里畫任何東西。下面是GLEventListener的代碼:import java.awt.*;import java.awt.event.*;import net.java.games.jogl.*;/*** For our purposes only two of the* GLEventListeners matter. Those would* be init() and display()。* 為了達到我們的目的,GLEventListener中只有兩個方法有用。* 它們是init()和display()。*/public class SimpleGLEventListener implements GLEventListener{ /** * Take care of initialization here. * 注意這里的初始化。 */ public void init(GLDrawable drawable) { } /** * Take care of drawing here. * 注意這里的繪圖。 */ public void display(GLDrawable drawable) { } /** * Called when the GLDrawable (GLCanvas * or GLJPanel) has changed in size. We * won't need this, but you may eventually * need it ―― just not yet. * 當GLDrawable(GLCanvas或GLJPanel)大小改變時被調用。 * 我們不需要它,但你可能最后會用到――雖然現在并不需要。 */ public void reshape( GLDrawable drawable, int x, int y, int width, int height ) {} /** * If the display depth is changed while the * program is running this method is called. * Nowadays this doesn't happen much, unless * a programmer has his program do it. * 當程序運行時顯示深度被改變的時候此方法被調用。 * 現在這種事發生得不多,除非程序里面觸發此事。 */ public void displayChanged( GLDrawable drawable, boolean modeChanged, boolean deviceChanged ) {}} 以上就是我們要完成的JOGL核心工作。注意下面的UML圖。SimpleJoglApp是一個JFrame.它容納了GLDrawable,實際上是一個GLCanvas,但不要那樣稱呼它。我們加入了SimpleGLEventListener.SimpleGLEventListener實現了對于GLCanvas的GLEventListener,這樣當它想執行任何的OpenGL 工作的時候,GLCanvas就可以知道。GLDrawables能自動執行,所以你確實得使你的GLEventListener最優化。 這個程序運行起來可能會根據你的操作系統顯得有點亂七八糟。這是預料之中的,因為你在這里只是往屏幕上顯示隨機的內存。所以恭喜你具有了圖形創新的才能了。 準備實戰 當你熟悉了前面的例子以后,我們來畫一張漂亮的圖。 這就是你接下來的程序。請確保你輸入了所有的代碼到你的編輯器中。調試這些程序可以快速地使你明白它們的工作原理。 import java.awt.*;import java.awt.event.*;import javax.swing.*;import net.java.games.jogl.*;/*** This is a basic JOGL app. Feel free to* reuse this code or modify it.* 這是個基礎的JOGL程序,你可以隨意重用該代碼或者修改它。*/public class SecondJoglApp extends JFrame { public static void main(String[] args) { final SecondJoglApp app = new SecondJoglApp(); //show what we've done //看一下我們做了什么 SwingUtilities.invokeLater ( new Runnable() { public void run() { app.setVisible(true); } } ); } public SecondJoglApp() { //set the JFrame title //設置JFrame標題 super("Second JOGL Application"); //kill the process when the JFrame is closed //當JFrame關閉的時候,結束進程 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //only three JOGL lines of code …… and here they are //只有三行JOGL代碼 …… 如下 GLCapabilities glcaps = new GLCapabilities(); GLCanvas glcanvas = GLDrawableFactory.getFactory()。createGLCanvas(glcaps); glcanvas.addGLEventListener(new SecondGLEventListener()); //add the GLCanvas just like we would any Component //像其它組件一樣把GLCanvas加入 getContentPane()。add(glcanvas, BorderLayout.CENTER); setSize(500, 300); //center the JFrame on the screen //使JFrame顯示在屏幕中央 centerWindow(this); } public void centerWindow(Component frame) { Dimension screenSize = Toolkit.getDefaultToolkit()。getScreenSize(); Dimension frameSize = frame.getSize(); if (frameSize.width > screenSize.width ) frameSize.width = screenSize.width; if (frameSize.height > screenSize.height) frameSize.height = screenSize.height; frame.setLocation ( (screenSize.width - frameSize.width ) >> 1, (screenSize.height - frameSize.height) >> 1 ); }} 請注意這個類對于第一個類所作的改動。改動只有類名、frame名、以及GLEventListener名。希望你能夠閱讀代碼中的注釋,否則你會搞不清它要做什么。 我們實現的GLEventListener確實相對于前面一個例子有了一些改進,它允許我們畫出一些漂亮的圖來。 import net.java.games.jogl.*;/*** For our purposes only two of the GLEventListeners matter.* Those would be init() and display()。* 為了達到我們的目的,GLEventListener中只有兩個方法有用。* 它們是init()和display()。*/public class SecondGLEventListener implements GLEventListener{ /** * Take care of initialization here. * 注意這里的初始化。 */ public void init(GLDrawable gld) { GL gl = gld.getGL(); GLU glu = gld.getGLU(); gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.glViewport(0, 0, 500, 300); gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); glu.gluOrtho2D(0.0, 500.0, 0.0, 300.0); } /** * Take care of drawing here. * 注意這里的繪圖。 */ public void display(GLDrawable drawable) { float red = 0.0f; float green = 0.0f; float blue = 0.0f; GL gl = drawable.getGL(); gl.glClear(GL.GL_COLOR_BUFFER_BIT); gl.glPointSize(5.0f); for (int i=0; i<50; i++) { red -= .09f; green -= .12f; blue -= .15f; if (red < 0.15) red = 1.0f; if (green < 0.15) green = 1.0f; if (blue < 0.15) blue = 1.0f; gl.glColor3f(red, green, blue); gl.glBegin(GL.GL_POINTS); gl.glVertex2i((i*10), 150); gl.glEnd(); }}public void reshape( GLDrawable drawable, int x, int y, int width, int height ) {}public void displayChanged( GLDrawable drawable, boolean modeChanged, boolean deviceChanged ) {}} 以上就是我們第一個有趣的JOGL程序。下圖是輸出,有很多好看的顏色。 當你看到GLEventListener的實現時,可能會感到不知所措。如果你有用C語言編寫OpenGL程序的經驗的話,你也許能猜測出一些東西。如果你覺得比較茫然,不必擔心,也不要擔心我會讓你記住這些東西,至少現在不必。本書接下來的篇幅將會對這個例子中的SecondGLEventListener作出解釋?,F在,你只需要試著去猜測。試著去修改代碼,產生兩行,或者一行斜的,而不是一行水平線;或是讓所有的點都變成藍色或紅色。盡情娛樂,這就是你接下來學習JOGL的方式。
當你對JOGL感到思維混亂的時候,讓我們來繼續看幾個類,你可以把它們當成有用的模板來使用。我已經不止一次把它們當成模板用了。你可以隨心所欲地使用它們。