JOGL
JOGL
JOGL
@for Developers
@author Kai Ruhl
@since 2009-04
Introduction
JOGL is the OpenGL binding for Java (JSR-231), mapping functions as closely as possible from C. OpenGL is
a standardized API used to draw 3D graphics to the screen (similar to DirectX / Direct3D). The primary
difference to 2D is that you need to think about z coordinates and the position of the viewer ("camera",
including viewing angle and such).
I am writing this JOGL tutorial because I did not find another good one. The JOGL homepage is poor in
information, the few tutorials are mostly outdated (not using newer functions, e.g. for textures or fonts), and the
famous NeHe OpenGL tutorials are for pure OpenGL under C (Java port available though). The best API doc I
found is the Python OpenGL API (better than the JOGL javadoc).
My plan for this tutorial (which is based on my experiences while writing Breed Orbiter) is:
1. Open a blank OpenGL window in Java.
2. Set the camera position and direction, looking at a triangle.
3. Create a planet sphere.
4. Add lighting from the sun.
5. Add an earth texture to the planet.
6. Add an orbit with a primitive satellite.
If you like, follow me on this way...
// Global settings.
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glShadeModel(GL.GL_SMOOTH);
gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
gl.glClearColor(0f, 0f, 0f, 1f);
// Perspective.
float widthHeightRatio = (float) getWidth() / (float) getHeight();
glu.gluPerspective(45, widthHeightRatio, 1, 1000);
glu.gluLookAt(0, 0, distance, 0, 0, 0, 0, 1, 0);
Step 4: Lighting
Lighting is where the whole color model is exchanged: That's right, throw glColor3f() away. Instead, we
specify how a rectangle surface reacts to light in its RGB spectrum (like in the real world), and we add light
sources with their own RGB spectrum (also like in the real world).
Before we begin, let me brief you on the kind of lights. We will be using AMBIENT and SPECULAR light, and
our surface "material" will react on this light. Ambient light is just everywhere, with no particular source (no
"3D effect" with this). We will typically use it at strength 0.2 (of 0..1) so that we can see places dimly where no
light spot is shining. Specular light is the one coming from a spot, and reflecting from surfaces; this gives the
typical "3D effect". I normally use it at strength 0.8 across the spectrum.
In standard OpenGL, you can have eight light sources, but we will be only using one. You have to specify them
before drawing (remember that OpenGL is just a stupid pipeline...), otherwise light will not be used correctly.
Once again, we go into the display() method and set everything:
public void display(GLAutoDrawable drawable) {
// Prepare light parameters.
float SHINE_ALL_DIRECTIONS = 1;
float[] lightPos = {-30, 0, 0, SHINE_ALL_DIRECTIONS};
float[] lightColorAmbient = {0.2f, 0.2f, 0.2f, 1f};
float[] lightColorSpecular = {0.8f, 0.8f, 0.8f, 1f};
A lighted sphere
Much better, I would say! The light source from the left illuminates the left side of the sphere with specular 0.8
light, while the darker right side is purely made visible by the ambient 0.2 light.
As always, please follow the code by inspecting the MyJoglCanvasStep4.java source file.
Step 5: Earth Texture
We can do even better: A texture is what brings a form truly alive, by adding a pattern that our human eyes like
so much. In case of planet textures, you can get a good one from Planet Pixel Emporium; the 1000x500 texture
is freeware. So now, how do we apply it to our sphere?
Two steps need to be taken: First, we need to load the texture from a PNG file and assemble it into a form
JOGL can understand. Second, just before drawing the sphere, we have to tell JOGL that the next thing coming
should use the texture ("bind the texture to the GL context").
The first step used to be difficult with OpenGL (see excerpt); in JOGL, we have helper classes such as the
TextureRenderer that do most of the things for us. In the init() method,we load the texture:
public void init(GLAutoDrawable drawable) {
// Load earth texture.
try {
InputStream stream = getClass().getResourceAsStream("earth.png");
TextureData data = TextureIO.newTextureData(stream, false, "png");
earthTexture = TextureIO.newTexture(data);
}
catch (IOException exc) {
exc.printStackTrace();
System.exit(1);
}
}
For this purpose, we retrieve an input stream (standard Java IO: image must be in same package as class) and
command TextureIO to read the texture data; apart from the stream, we specify false to supress generation of
mipmaps ("up/downscaled versions of the texture for different viewing distances"), and supply the file ending.
Then, we generate an OpenGL earthTexture from the data, again using TextureIO.
In the display() method, we put this earthTexture into use, by binding the texture to the GL context before
proceeding with drawing the sphere.
public void display(GLAutoDrawable drawable) {
// Set material properties.
float[] rgba = {1f, 1f, 1f};
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, rgba, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, rgba, 0);
gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 0.5f);
// Apply texture.
earthTexture.enable();
earthTexture.bind();
// Draw sphere.
GLUquadric earth = glu.gluNewQuadric();
glu.gluQuadricTexture(earth, true);
}
Compared to the previous version, you can see three changes: First, we change the material color to white (1f,
1f, 1f), because now the texture shall define the color of each spot on the surface. Then, we enable() textures
globally (switch this off again if you want an untextured surface come next), and then bind() the specific texture
for whatever comes next.
And next comes the GLU sphere! Here, we need to make only one change: Announce that we indeed want to
use the current texture for the next form. This is kind of redundant, and GLU specific: If you draw triangles (or
quads), you wont have to do this.
The rest plays out as before, resulting in the following:
A textured sphere
And this is the earth! Seen from the south pole, and that is because GLU always paints at 0, 0, 0 and along the
z-axis; and we are looking along the z-axis into the monitor. No worry, we can change the zero position
("translation"), and also the alignment of the body ("rotation") -- stuff for the next chapter!
For a review of what we have done so far, have a look at the MyJoglCanvasStep5.java source file.
Conclusion
In this tutorial, we have walked through quite some JOGL functionality. We covered basic structures like
triangles, quads and spheres in three dimensional space; directional lighting and material properties; and
textures, which we all like so much. Finally, we worked some movement into our scene. Personally, I have
worked further on the orbiter, which currently looks like this: