PC's JOGL Blog

Learning the Java JOGL OpenGL Bindings

Thursday, July 13, 2006

JOGL Draw Arrays

Calling the OpenGL drawing primitives in Java, like glVertex() and glNormal(), quickly becomes a bottleneck for rendering scenes. The function call overhead, although small, when multiplied a million times for each polygon is a problem very quickly, however, this can be overcome using glDrawArrays (commonly known as vertex arrays). Vertices, normals, colours and texture coordinates can be loaded into an IntBuffer, FloatBuffer or a DoubleBuffer (depending on what you want to use) and then sent to the rendering engine using a single glDrawArrays() function call.

import java.nio.DoubleBuffer ;
DoubleBuffer verticesBuffer = BufferUtil.newDoubleBuffer(3 * 3) ;
verticesBuffer.put(c0.x) ;
verticesBuffer.put(c0.y) ;
verticesBuffer.put(c0.z) ;
verticesBuffer.put(c1.x) ;
verticesBuffer.put(c1.y) ;
verticesBuffer.put(c1.z) ;
verticesBuffer.put(c2.x) ;
verticesBuffer.put(c2.y) ;
verticesBuffer.put(c2.z) ;
gl.glEnableClientState (GL.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL.GL_DOUBLE, 0, verticesBuffer);
gl.glDrawArrays(GL.GL_TRIANGLES, 0, 3);

Sadly, there is still a function call overhead loading the values into the DoubleBuffer, however, this is less that the overhead of calling glVertex() multiple times. Make sure you rewind the location in the buffer using verticesBuffer.rewind() or verticesBuffer.position(0) before calling glVertexPointer() otherwise you will load the current location in the buffer into OpenGL instead of the starting location and you’ll end up only seeing a new vertices each call.

I found that loading the values into a local array and the calling the put(double[], int, int) function to load multiple values at once was much slower that calling multiple put(double) functions, even if the array was pre-allocated and reused. I could not find any way to load values into the buffers without doing it thought a function call… so if you know how to do please let me know.

// Really slow for some reason.
double array[] = new double[9] ;
array[0] = c0.x ;
array[1] = c0.y ;
verticesBuffer.put(array, 0, 9) ;

Rendering tip… remember to set gl.glEnable(GL.GL_NORMALIZE) when using matrixes to translating and scaling groups of vertices, otherwise the vertices normals passed to OpenGL get transformed as well, but they don’t get re-normalized, so you end up of unexpected lighting results.

Here is some good example code but make sure you add that rewind calling glColorPointer().


At 9:12 PM, Anonymous Stephen said...

Do you have to use doubles?

Isn't that going to require twice as much data to be sent to the card as a floats?

At 9:15 PM, Anonymous Anonymous said...


At 8:27 AM, Blogger PC said...

You can use doubles, floats or int's. I use doubles in this demo code because I find doubles easier to type in Java (you don't have to put an "f" on the end of each constant) and I find that "holes" in the floating point number sequence annoying. Also, I find working in int's a pain because you have to scale things if you want to work in fractions of units.

But it's a good point... you do have to be careful about memory usage and you really need to decide what is best to use where. These days I find no performance problems with using doubles, but your right about space.


Post a Comment

<< Home