背景编辑本段回目录
OpenGL是用来制图的,速度非常快。大多数场合下,它是硬件加速的。看起来好像OpenGL可以实现一切你想要完成的图形界面。
不幸的是,OpenGL是为C语言而写的。不得不承认,C语言不是用来编写复杂应用程序的流行语言。关于OpenGL一个最大的缺点就是:如果不创建一个窗口(用来把你的图形放入其中),就什么都做不了。但是OpenGL没有提供给创建窗口的方法。这使得OpenGL对于初学者来说显得比较难。
幸运地是,出现了GLUT (OpenGL Utility Toolkit)(OpenGL工具包)。它被用来轻松应对窗口、按钮以及用户事件。尽管如此,对于想要使用面向对象的编程的程序员来说,学习用C或者C++来编写OpenGL程序仍然是一件痛苦的事。
JOGL编辑本段回目录
如今,Sun的游戏开发小组正在开发JOGL。它是以肯·拉塞尔和克里斯·克兰开发的Jungle开始的。拉塞尔是Sun的员工,研发“HotSpot虚拟机”,拥有多年的三维经验。克兰则研发“荒谬的游戏”,对三维图形学也相当有经验。
OpenGL 被用来展示三维模型。它强大、快速,而且可能是自Swing出现以来最棒的一样东西。通过JOGL来使用OpenGL,你可以制作出很酷的游戏或是模型位置什么的,而在这之前创建它们需要非常昂贵的成本。有人写了很厚很厚的书来描述OpenGL,当你熟悉了它们以后这些书会很有用,但现在不行。你必须学习展现在你面前的OpenGL是如何使用Java API的。同样你还得看一下关于net.java.games.jogl.*的基础介绍,可能还得补习一下数学知识。
获取JOGL编辑本段回目录
这个是可以从https://jogl.dev.java.net/找到的,进入网站后点左侧的文档和文件,我下载了Release Builds 2008JSR-231 1.1.1 - May 22 (15)里面的jogl-1.1.1-windows-i586.zip,解压就得到要的jogl.jar和其他文件了。
JOGL的Javadocs编辑本段回目录
如果你浏览一下net.java.games.jogl包,你很快会注意到有些类非常大。GL便是一个完美的例子。别被这个吓跑了,你很快能发现只需一点点JOGL的知识,你就可以完成一些相当复杂的事了。现在你需要扫视一下的类有:
*GLDrawable
*GLCanvas
*GLJPanel
*GLCapabilities
*GLDrawableFactory
这些是连接图形世界基本的接口。如果你还记得,前面我提到对于初学OpenGL的人来说,有一个很大的缺点,那就是缺乏窗口系统的标准。对应于C语 言,GLUT起到了相当大的作用。而我们则有Swing和AWT(抽象窗口工具箱)。很可能你已经使用过AWT或者Swing了,所以你不会感到自己在从 头学起。这是件非常好的事情。在通过了非常简短的关于把JOGL组件放置到屏幕上的介绍以后,我们不需要多长时间就可以运行出一个相当酷而且流行的程序 了。
GlueGen编辑本段回目录
让我们进入JOGL家族看看。他们打算利用C头文件写一些代码来实现一切JNI做的事。他们管这个叫做GlueGen。GlueGen解析C头文件然后魔法般地创建出Java和JNI代码以便连接到本机库。这意味着OpenGL的升级可以迅速地在JOGL里体现。
Hello World!编辑本段回目录
以下是程序:
import net.java.games.jogl.*;首先,这个程序测试了本机库和Java库是否已经安装正确了。只有当jogl.jar和本机库(名字诸如libjogl.jnilib或者 jogl.dll)两者都安装好了的时候,JOGL才算是安装完全的。如果本机库不可用,程序会抛 java.lang.UnsatisfiedLinkError例外。如果classpath里没有安装JAR,程序则根本编译都通不过。Javac编译 器会报诸如此类的错“net.java.games.jogl包不存在”。当这个程序编译通过且运行起来没有异常的话,你可以继续学习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);
}
}
}
一个好的模板编辑本段回目录
这个模板由两个类组成。第一个是如下所示的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 =我们不能创建GLCanvas或者GLJPanel。我们得用GLDrawableFactory来创建它们。所以我们用GLDrawableFactory的静态方法getFactory()取得了GLDrawableFactory。
GLDrawableFactory.getFactory().createGLCanvas(glcaps);
现在我们有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.*;以上就是我们第一个有趣的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
) {}
}

当 你看到GLEventListener的实现时,可能会感到不知所措。如果你有用C语言编写OpenGL程序的经验的话,你也许能猜测出一些东西。如果你 觉得比较茫然,不必担心,也不要担心我会让你记住这些东西,至少现在不必。本书接下来的篇幅将会对这个例子中的 SecondGLEventListener作出解释。现在,你只需要试着去猜测。试着去修改代码,产生两行,或者一行斜的,而不是一行水平线;或是让所 有的点都变成蓝色或红色。尽情娱乐,这就是你接下来学习JOGL的方式。