1
\$\begingroup\$

I wrote a small particle engine in Java for my Pong clone.

I read that changing a texture is very expensive in OpenGL, so I tried to change the texture as few times as possible. Therefore I change the texture in the render method of the emitter and not in the render method of every particle. Although my framerate drops from about 8000 FPS to 4000 FPS while there are about 60 particles on the screen.

So, is it possible to improve my particle engine when it comes to rendering? I am only asking for the rendering, because when I use the engine, but disable its rendering, nothing changes in the FPS.

This is the render Method of the particle emitter:

public void render() {
    //Initialize....
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    BloodParticle.PARTICLE_TEXTURE.bind();

    for(Integer index : this.getBlockedParticles()){
        this.getParticles()[index].render();
    }

    GL11.glDisable(GL11.GL_TEXTURE_2D);
}

And this is the code for the particle self:

public void render() {
    if(!this.isAlive()){
        return;
    }

    // Store matrix
    GL11.glPushMatrix();

    // Set to particle's position and scale
    GL11.glTranslatef(this.getPosition().getX(), this.getPosition().getY(), 0);
    GL11.glScalef(3.5f, 3.5f, 1.0f);

    // Set the current alpha.
    GL11.glColor4f(1.0f, 1.0f, 1.0f, this.getAlphaFade());

    //Draw the texture on a quad.
    GL11.glBegin(GL11.GL_QUADS);
    {
        GL11.glTexCoord2f(0, 0);
        GL11.glVertex2f(-PARTICLE_TEXTURE.getImageWidth()/2.0f,
                -PARTICLE_TEXTURE.getImageHeight()/2.0f);

        GL11.glTexCoord2f(0, 1);
        GL11.glVertex2f(-PARTICLE_TEXTURE.getImageWidth()/2.0f,
                PARTICLE_TEXTURE.getImageHeight()/2.0f);

        GL11.glTexCoord2f(1, 1);
        GL11.glVertex2f(PARTICLE_TEXTURE.getImageWidth()/2.0f,
                PARTICLE_TEXTURE.getImageHeight()/2.0f);

        GL11.glTexCoord2f(1, 0);
        GL11.glVertex2f(PARTICLE_TEXTURE.getImageWidth()/2.0f, 
                -PARTICLE_TEXTURE.getImageHeight()/2.0f);

    }
    GL11.glEnd();

    //Get the matrix again.
    GL11.glPopMatrix();
}
\$\endgroup\$
  • 1
    \$\begingroup\$ you should calculate PARTICLE_TEXTURE.getImageWidth()/2.0f and PARTICLE_TEXTURE.getImageHeight()/2.0f only once. If PATICLE_TEXTURE is a constant (as the name suggests) it might be a good idea to calculate it on initialization and provide accessor-methods like getHalfImageWidth() and getHalfImageHeight() \$\endgroup\$ – Marco Forberg Jun 17 '13 at 14:31
2
\$\begingroup\$

A few notes:

for(Integer index : this.getBlockedParticles()){
    this.getParticles()[index].render();
}

This should be:

for( Particle particle : getBlockedLivingParticles() ) {
  particle.render();
}

By maintaining a list of living particles, you can eliminate a number unwarranted calls to render and eliminate the following check:

if(!this.isAlive()){
    return;
}

Assuming the width and height cannot change while rendering:

    GL11.glTexCoord2f(0, 0);
    GL11.glVertex2f(-PARTICLE_TEXTURE.getImageWidth()/2.0f,
            -PARTICLE_TEXTURE.getImageHeight()/2.0f);

As Marco commented, that duplicate code can be refactored:

    float width = PARTICLE_TEXTURE.getImageWidth() / 2.0f;
    float height = PARTICLE_TEXTURE.getImageHeight() / 2.0f;

    GL11.glTexCoord2f(0, 0);
    GL11.glVertex2f(-width, -height);

This will reduce the number of divisions (an expensive operation) from 8 to 2. You'll also note that there's a relationship between glTexCoord2f and the sign of the width/height passed to glVertex2f, which can be abstracted.

Architecturally, I'd be concerned that the Particle can only be rendered using the GL11 API. Use an Abstract Factory to decouple the rendering device from the application logic. This will also help determine the slower parts of the code (i.e., you could employ a dummy particle that has no rendering device to quickly and easily tune the other parts of the application).

One other trick to speed things up: if all calculations can be made with integer math, then instead of diving by 2, bit-shift by 1.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.