然后出现了JOGL
Java也许是最流行的真正的面向对象的编程语言有许多用Java去结合OpenGL的尝试但是第一个被大家认可并注意的是Java对于OpenGl的绑定(Java Bindings for OpenGL) 或者称为JOGL理由是它得到Sun(Java的创建者)和SGI(OpenGL的创建者)的支持
如今Sun的游戏开发小组正在开发JOGL它是以肯拉塞尔和克里斯克兰开发的Jungle开始的拉塞尔是Sun的员工研发HotSpot虚拟机拥有多年的三维经验克兰则研发荒谬的游戏对三维图形学也相当有经验
我个人对他们以及所有其它工作在JOGL上的人表示感谢曾经有许多想通过友好的Java API来使用OpenGL的尝试——其中包括Java D OpenGL for Java Technology (gljava)(用于Java技术的OpenGL)Lightweight Java Game Library (LWJGL)(轻量级的Java游戏库)JOGL是第一个使我感到满意的
JOGL是Sun支持的对于OpenGl的Java类绑定哇!这句话说得太妙了
OpenGL被用来展示三维模型它强大快速而且可能是自Swing出现以来最棒的一样东西通过JOGL来使用OpenGL你可以制作出很酷的游戏或是模型位置什么的而在这之前创建它们需要非常昂贵的成本有人写了很厚很厚的书来描述OpenGL当你熟悉了它们以后这些书会很有用但现在不行你必须学习展现在你面前的OpenGL是如何使用Java API的同样你还得看一下关于netjavagamesjogl*的基础介绍可能还得补习一下数学知识
获取JOGL?
如果你想使用JOGL你需要得到jogljar以及附带的本机代码我希望有一天它可以成为Java的标准安装但现在它只是一个梦想
第一步是要找到你的操作系统所对应的包并进行解压缩我是在/l上找到的不同的操作系统有所区别但需要安装个部分系统的classpath里一定要有jogljar而且binary库必须放在和你操作系统的库同一个地方如果比较幸运的话安装程序可以为你完成这些如果你没有安装程序而且不知道该上哪里去寻找关于设置计算机的信息的话你可以从我提供一个链接Resources开始搜索我们的第一篇代码是特别用来测试环境是否安装正确的所以对于测试安装你不必紧张
JOGL的Javadocs
同样可以在和JOGL 的binary 发布版一样的位置获得JavadocsJavadocs将会以类似joglusrdoctar的名字而命名
如果你浏览一下netjavagamesjogl包你很快会注意到有些类非常大GL便是一个完美的例子别被这个吓跑了你很快能发现只需一点点JOGL的知识你就可以完成一些相当复杂的事了现在你需要扫视一下的类有*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做的事他们管这个叫做GlueGenGlueGen解析C头文件然后魔法般地创建出Java和JNI代码以便连接到本机库这意味着OpenGL的升级可以迅速地在JOGL里体现
Hello World!
我是一个很传统的人所以当然我们将从你好世界程序开始这个你好世界程序将检验我们的安装是否全部或者一部分安装正确回忆一下安装JOGL有个部分分别是jar文件里的Java库以及其它库的本机代码
以下是我们的程序import netjavagamesjogl*public class HelloWorld { public static void main (String args[]) { try { SystemloadLibrary(jogl) Systemoutprintln( Hello World! (The native libraries are installed) ) GLCapabilities caps = new GLCapabilities() Systemoutprintln( Hello JOGL! (The jar appears to be available) ) } catch (Exception e) { Systemoutprintln(e) } }}
首先这个程序测试了本机库和Java库是否已经安装正确了只有当jogljar和本机库(名字诸如libjogljnilib或者jogldll)两者都安装好了的时候JOGL才算是安装完全的如果本机库不可用程序会抛javalangUnsatisfiedLinkError例外如果classpath里没有安装JAR程序则根本编译都通不过Javac编译器会报诸如此类的错netjavagamesjogl包不存在当这个程序编译通过且运行起来没有异常的话你可以继续学习JOGL了
一个好的模板当你对JOGL感到思维混乱的时候让我们来继续看几个类你可以把它们当成有用的模板来使用我已经不止一次把它们当成模板用了你可以随心所欲地使用它们
这个模板由两个类组成第一个是如下所示的SimpleJoglApp第二个是在简短说明之后的SimpleGLEventListener你必须输入两个类来编译模板主程序如下import javaawt*import javaawtevent*import javaxswing*import netjavagamesjogl*/** * 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 weve done //看一下我们做了什么 SwingUtilitiesinvokeLater ( new Runnable() { public void run() { appsetVisible(true) } } ) } public SimpleJoglApp() { //set the JFrame title //设置JFrame标题 super(Simple JOGL Application) //kill the process when the JFrame is closed //当JFrame关闭的时候结束进程 setDefaultCloseOperation(JFrameEXIT_ON_CLOSE) //only three JOGL lines of code …… and here they are //只有三行JOGL代码 …… 如下 GLCapabilities glcaps = new GLCapabilities() GLCanvas glcanvas = GLDrawableFactorygetFactory()createGLCanvas(glcaps) glcanvasaddGLEventListener(new SimpleGLEventListener()) //add the GLCanvas just like we would any Component //像其它组件一样把GLCanvas加入 getContentPane()add(glcanvas BorderLayoutCENTER) setSize( ) //center the JFrame on the screen //使JFrame显示在屏幕中央 centerWindow(this) } public void centerWindow(Component frame) { Dimension screenSize = ToolkitgetDefaultToolkit()getScreenSize() Dimension frameSize = framegetSize() if (frameSizewidth > screenSizewidth ) frameSizewidth = screenSizewidth if (frameSizeheight > screenSizeheight) frameSizeheight = screenSizeheight framesetLocation ( (screenSizewidth frameSizewidth ) >> (screenSizeheight frameSizeheight) >> ) }}
代码就是这些让我们把注意力集中在第一个类中与JOGL相关的三行代码上首先
这决定了我们的JOGL库和JVM可以使用哪些OpenGL/图形特色
接着GLCanvas glcanvas = GLDrawableFactorygetFactory()createGLCanvas(glcaps)
我们不能创建GLCanvas或者GLJPanel我们得用GLDrawableFactory来创建它们所以我们用GLDrawableFactory的静态方法getFactory()取得了GLDrawableFactory
现在我们有GLDrawableFactory了所以我们用createGLCanvas()方法来创建了可以往上画画的GLCanvas如果我们不需要AWT组件而是Swing组件则可以用createGLJPanel()方法
注意我们把先前创建的GLCapabilities对象传了进去这可以使我们创建的GLDrawable适当的所创建
最后我们准备往GLCanvas上加GLEventListener
我们对GLEventListener的实现是SimpleGLEventListener它负责当接到GLDrawable或我们的或只是GLCanvas的调用时所需要完成的所有绘图工作你将会看到我不打算在这个程序里画任何东西下面是GLEventListener的代码import javaawt*import javaawtevent*import netjavagamesjogl*/*** 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 * wont 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 doesnt 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但不要那样称呼它我们加入了SimpleGLEventListenerSimpleGLEventListener实现了对于GLCanvas的GLEventListener这样当它想执行任何的OpenGL 工作的时候GLCanvas就可以知道GLDrawables能自动执行所以你确实得使你的GLEventListener最优化
这个程序运行起来可能会根据你的操作系统显得有点乱七八糟这是预料之中的因为你在这里只是往屏幕上显示随机的内存所以恭喜你具有了图形创新的才能了
准备实战
当你熟悉了前面的例子以后我们来画一张漂亮的图
这就是你接下来的程序请确保你输入了所有的代码到你的编辑器中调试这些程序可以快速地使你明白它们的工作原理
import javaawt*import javaawtevent*import javaxswing*import netjavagamesjogl*/*** 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 weve done //看一下我们做了什么 SwingUtilitiesinvokeLater ( new Runnable() { public void run() { appsetVisible(true) } } ) } public SecondJoglApp() { //set the JFrame title //设置JFrame标题 super(Second JOGL Application) //kill the process when the JFrame is closed //当JFrame关闭的时候结束进程 setDefaultCloseOperation(JFrameEXIT_ON_CLOSE) //only three JOGL lines of code …… and here they are //只有三行JOGL代码 …… 如下 GLCapabilities glcaps = new GLCapabilities() GLCanvas glcanvas = GLDrawableFactorygetFactory()createGLCanvas(glcaps) glcanvasaddGLEventListener(new SecondGLEventListener()) //add the GLCanvas just like we would any Component //像其它组件一样把GLCanvas加入 getContentPane()add(glcanvas BorderLayoutCENTER) setSize( ) //center the JFrame on the screen //使JFrame显示在屏幕中央 centerWindow(this) } public void centerWindow(Component frame) { Dimension screenSize = ToolkitgetDefaultToolkit()getScreenSize() Dimension frameSize = framegetSize() if (frameSizewidth > screenSizewidth ) frameSizewidth = screenSizewidth if (frameSizeheight > screenSizeheight) frameSizeheight = screenSizeheight framesetLocation ( (screenSizewidth frameSizewidth ) >> (screenSizeheight frameSizeheight) >> ) }}
请注意这个类对于第一个类所作的改动改动只有类名frame名以及GLEventListener名希望你能够阅读代码中的注释否则你会搞不清它要做什么
我们实现的GLEventListener确实相对于前面一个例子有了一些改进它允许我们画出一些漂亮的图来
import netjavagamesjogl*/*** 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 = gldgetGL() GLU glu = gldgetGLU() glglClearColor(f f f f) glglViewport( ) glglMatrixMode(GLGL_PROJECTION) glglLoadIdentity() glugluOrthoD( ) } /** * Take care of drawing here * 注意这里的绘图 */ public void display(GLDrawable drawable) { float red = f float green = f float blue = f GL gl = drawablegetGL() glglClear(GLGL_COLOR_BUFFER_BIT) glglPointSize(f) for (int i= i< i++) { red = f green = f blue = f if (red < ) red = f if (green < ) green = f if (blue < ) blue = f glglColorf(red green blue) glglBegin(GLGL_POINTS) glglVertexi((i*) ) glglEnd() }}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作出解释现在你只需要试着去猜测试着去修改代码产生两行或者一行斜的而不是一行水平线或是让所有的点都变成蓝色或红色尽情娱乐这就是你接下来学习JOGL的方式