Hello,
I’ve been getting to know JOGL over some time and has been putting together some reuseable components.
I am however not experiencing the performance that I would expect.
I this example, I am rendering a multitextured terrain (2 texture units) and some basic textures. This is crudely done per terrain tile and sprite through a helper class.
On this rather recent laptop I am achieving ~60 fps with around 500 tiles and 200 vegetation sprites.
I think I recall great optimization to be available through vertex arrays or something similar. Could someone please assist me with general pointers to how to reach more potential from openGL?
In my first example, 60 fps is stable
http://dl.getdropbox.com/u/63422/Posted/Javagaming%20-%20Performance%20-%20Okay.jpg
[DEBUG] 13:19:45 :: TestVegetation - ----- Frame -----
[DEBUG] 13:19:45 :: TestVegetation - LightSources took 0.1 ms
[DEBUG] 13:19:45 :: TestVegetation - Terrain: 468 tiles
[DEBUG] 13:19:45 :: TestVegetation - Terrain took 4 ms
[DEBUG] 13:19:45 :: TestVegetation - Vegetation: 155 items
[DEBUG] 13:19:45 :: TestVegetation - Vegetation took 0.9 ms
In my second example, I am not achieving 60 fps.
http://dl.getdropbox.com/u/63422/Posted/Javagaming%20-%20Performance%20-%20Poor.jpg
[DEBUG] 13:17:48 :: TestVegetation - ----- Frame -----
[DEBUG] 13:17:48 :: TestVegetation - LightSources took 0.1 ms
[DEBUG] 13:17:48 :: TestVegetation - Terrain: 468 tiles
[DEBUG] 13:17:48 :: TestVegetation - Terrain took 4 ms
[DEBUG] 13:17:48 :: TestVegetation - Vegetation: 1557 items
[DEBUG] 13:17:48 :: TestVegetation - Vegetation took 5 ms
Obviously vegetation is the cause here.
I have plenty of references here to custom stuff but hopefully it can be of assistance somehow.
I am not asking for a step to step guide or source code, just hints and ideas… anything off the top of your heads
Known probably sources;
- I am using 24 bit transparent PNG which could perhaps be a problem (as compared to non-alpha channel ones)
- Turning on and off texturing units for each tile ?
- Low performance logic surrounding the render
Thank you for reading.
Related code snippets
Rendering tiles:
for (int iy = vTileOffsetY; iy < vTileOffsetY + vScreenTileHeight + 2; iy++) {
for (int ix = vTileOffsetX; ix < vTileOffsetX + vScreenTileWidth
+ 2; ix++) {
// Fetch tile
TerrainTile tile = mTerrainMap.get(ix, iy);
if (tile == null) {
continue;
}
// Calculate window coordinates
float x = ((float) ix * sTILE_WIDTH - mScrollX) - sTILE_WIDTH
/ 2;
float y = ((float) iy * sTILE_HEIGHT - mScrollY) - sTILE_HEIGHT
/ 2;
// Calculate texture coordinates
float tx = ix * tw;
float ty = iy * th;
g.drawMultiTexture(x, y, sTILE_WIDTH, sTILE_HEIGHT, tile
.getTextureId1(), tile.getTextureId2(), tile
.isPrimary(), new float[] { tx, ty, tw, th },
new float[][] { mLightMap.get(ix - 1, iy - 1).getRGB(),
mLightMap.get(ix, iy - 1).getRGB(),
mLightMap.get(ix - 1, iy).getRGB(),
mLightMap.get(ix, iy).getRGB() });
}
}
Rendering Vegetation:
for (Vegetation v : mVegetation) {
float x = toScreenCoord(v.getX(), Orientation.HORIZONTAL);
float y = toScreenCoord(v.getY(), Orientation.VERTICAL);
if (!g.inView(x, y, sFRAME_LIGHTMAP_MARGIN)) {
continue;
}
RGB rgb = mLightMap.get((int) v.getX(), (int) v.getY());
g.drawFrames(x, y + 16, v.getFrames(), Alignment.LOWER_MIDDLE,
(float) v.getScale(), rgb.getRGB(), BlendMode.ALPHA);
}
Render multitextured tile
public void drawMultiTexture(float x, float y, float w, float h,
Long textureId1, Long textureId2, boolean[] isPrimary,
float textureOffset[], float[][] color) {
y = height - y;
/* Enable Multitexturing */
Texture tex1 = textureManager.getTexture(textureId1);
Texture tex2 = textureManager.getTexture(textureId2);
// Set up the first texture unit to interpolate using crossbar extension
gl.glActiveTexture(GL.GL_TEXTURE0);
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glBindTexture(GL.GL_TEXTURE_2D, tex1.getTextureObject());
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_COMBINE);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_RGB, GL.GL_INTERPOLATE);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SOURCE0_RGB, GL.GL_TEXTURE1);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SOURCE1_RGB, GL.GL_TEXTURE0);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SOURCE2_RGB, GL.GL_PRIMARY_COLOR);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_OPERAND2_RGB, GL.GL_SRC_ALPHA);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_ALPHA, GL.GL_INTERPOLATE);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SOURCE0_ALPHA, GL.GL_TEXTURE1);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SOURCE1_ALPHA, GL.GL_TEXTURE0);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SOURCE2_ALPHA,
GL.GL_PRIMARY_COLOR);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_OPERAND2_ALPHA, GL.GL_SRC_ALPHA);
// Set up the second texture unit for primary color tinting
gl.glActiveTexture(GL.GL_TEXTURE1);
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glBindTexture(GL.GL_TEXTURE_2D, tex2.getTextureObject());
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_COMBINE);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_RGB, GL.GL_MODULATE);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SOURCE0_RGB, GL.GL_PRIMARY_COLOR);
float[] constant = { 1, 1, 1, 1 };
gl.glTexEnvfv(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_COLOR, constant, 0);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_ALPHA, GL.GL_REPLACE);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_SOURCE0_ALPHA, GL.GL_CONSTANT);
/*
* Triangle Fan Rendering
*
* Center, Lower Left, Upper Left, Upper Right, Lower Right
*/
float tx1 = textureOffset[0];
float tx2 = textureOffset[0] + textureOffset[2];
float ty1 = textureOffset[1];
float ty2 = textureOffset[1] + textureOffset[3];
// Calculate blending of the center vertex
float p = 0.0f;
for (int i = 0; i < isPrimary.length; i++) {
if (!isPrimary[i])
p += 0.25f;
}
// Calculate color of the center vertex
float midColor[] = new float[] {
(color[0][0] + color[1][0] + color[2][0] + color[3][0]) / 4,
(color[0][1] + color[1][1] + color[2][1] + color[3][1]) / 4,
(color[0][2] + color[1][2] + color[2][2] + color[3][2]) / 4 };
gl.glBegin(GL.GL_TRIANGLE_FAN);
{
gl.glColor4f(midColor[0], midColor[1], midColor[2], p);
gl.glMultiTexCoord2f(GL.GL_TEXTURE0, (tx2 + tx1) / 2,
(ty2 + ty1) / 2);
gl.glMultiTexCoord2f(GL.GL_TEXTURE1, (tx2 + tx1) / 2,
(ty2 + ty1) / 2);
gl.glVertex2f(x + w / 2, y - h / 2);
gl.glColor4f(color[2][0], color[2][1], color[2][2],
isPrimary[2] ? 0.0f : 1.0f);
gl.glMultiTexCoord2f(GL.GL_TEXTURE0, tx1, ty2);
gl.glMultiTexCoord2f(GL.GL_TEXTURE1, tx1, ty2);
gl.glVertex2f(x, y - h);
gl.glColor4f(color[0][0], color[0][1], color[0][2],
isPrimary[0] ? 0.0f : 1.0f);
gl.glMultiTexCoord2f(GL.GL_TEXTURE0, tx1, ty1);
gl.glMultiTexCoord2f(GL.GL_TEXTURE1, tx1, ty1);
gl.glVertex2f(x, y);
gl.glColor4f(color[1][0], color[1][1], color[1][2],
isPrimary[1] ? 0.0f : 1.0f);
gl.glMultiTexCoord2f(GL.GL_TEXTURE0, tx2, ty1);
gl.glMultiTexCoord2f(GL.GL_TEXTURE1, tx2, ty1);
gl.glVertex2f(x + w, y);
gl.glColor4f(color[3][0], color[3][1], color[3][2],
isPrimary[3] ? 0.0f : 1.0f);
gl.glMultiTexCoord2f(GL.GL_TEXTURE0, tx2, ty2);
gl.glMultiTexCoord2f(GL.GL_TEXTURE1, tx2, ty2);
gl.glVertex2f(x + w, y - h);
gl.glColor4f(color[2][0], color[2][1], color[2][2],
isPrimary[2] ? 0.0f : 1.0f);
gl.glMultiTexCoord2f(GL.GL_TEXTURE0, tx1, ty2);
gl.glMultiTexCoord2f(GL.GL_TEXTURE1, tx1, ty2);
gl.glVertex2f(x, y - h);
}
gl.glEnd();
// Turn the second multitexture pass off
gl.glActiveTexture(GL.GL_TEXTURE1);
gl.glDisable(GL.GL_TEXTURE_2D);
// Turn the first multitexture pass off
gl.glActiveTexture(GL.GL_TEXTURE0);
gl.glDisable(GL.GL_TEXTURE_2D);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);
}
Render sprite (“frame”)
public void drawFrames(float x, float y, Frames frames, Alignment align,
float scale, float[] rgb, BlendMode mode) {
long textureId = frames.getNextFrame();
Texture tex = textureManager.getTexture(textureId);
float w = tex.getImageWidth() * scale;
float h = tex.getImageHeight() * scale;
x = applyHorizontalAlignment(x, w, align);
y = applyVerticalAlignment(y, h, align);
drawTexture(x, y, w, h, frames.getNextFrame(), mode, rgb);
}
Draw Texture (used in above)
public void drawTexture(float x, float y, float w, float h, Long textureId,
BlendMode mode, float[] rgb) {
Texture tex = textureManager.getTexture(textureId);
tex.enable();
tex.bind();
y = height - y;
setBlendMode(mode);
gl.glBegin(GL.GL_POLYGON);
gl.glColor4f(rgb[0], rgb[1], rgb[2], rgb[3]);
gl.glTexCoord2f(0f, 0f);
gl.glVertex2f(x, y);
gl.glTexCoord2f(1f, 0f);
gl.glVertex2f(x + w, y);
gl.glTexCoord2f(1f, 1f);
gl.glVertex2f(x + w, y - h);
gl.glTexCoord2f(0f, 1f);
gl.glVertex2f(x, y - h);
gl.glEnd();
tex.disable();
}