Hot questions for Using Lightweight Java Game Library in performance

Question:

I am rendering grass with 8 vertices per piece of grass (per object). This brought my game down from 50+ FPS to exactly 31FPS.

Trying to find a solution to this, I stumbled across a Mipmapping tutorial, a way to make the texture less detailed. "Great", I thought! Since the grass is just two flat surfaces with a texture on, it looked like it would solve the issue!

The grass model looks like this (Obviously I then just apply a texture to it and make certain parts transparent using shaders):

However, when I enabled mipmapping, I got 32 FPS - Only 1 more FPS than without mipmapping! I also get some sort of blue tinge on the grass?

Without mipmapping, the grass looks like this:

Why is my Mipmapping not giving me any sort of performance enhancements? Considering my grass is mostly just texture, then why would degrading the texture not increase performance?

And also, why is there a blue tinge being created on the grass? Is it something to do with how mipmapping is lowering the texture resolution?

I currently use this code to generate:

texture = TextureLoader.getTexture("PNG",
                new FileInputStream("res/" + fileName + ".png"));
        GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
        GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, 0);

And I use this code to actually render the grass:

public void render(){
    Main.TerrainDemo.shader.start();
    glPushMatrix();
    glTranslatef(location.x, location.y, location.z);
    TexturedModel texturedModel = TerrainDemo.texModel;
    RawModel model = texturedModel.getRawModel();
    GL30.glBindVertexArray(model.getVaoID());
    GL20.glEnableVertexAttribArray(0);
    GL20.glEnableVertexAttribArray(1);
    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getTexture().getID());
    glScalef(10f, 10f, 10f);
    glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
    GL20.glDisableVertexAttribArray(0);
    GL20.glDisableVertexAttribArray(1);
    GL30.glBindVertexArray(0);
    glPopMatrix();
    Main.TerrainDemo.shader.stop();
}

Answer:

The mip-mapping modifies the texture, but the grass doesn't really do much work in the texture anyway as it is a small object.

Most of the work to render the grass comes in processing all of the vertices, and most especially if the grass are lots of small objects then in processing these objects.

You should combine the grass together into one mesh and then let that be rendered. Graphics cards are great at handling objects with huge numbers of vertices, not so great at huge numbers of objects.

If you were using jMonkeyEngine I could recommend some classes that provides to do the batching for you (most obviously BatchNode although there are some other options too). It might still be worth looking at how jMonkeyEngine does it for ideas.

Question:

I am currently working on a project involving LWJGL. I know that in C and C++ one should call functions like: glDeleteBuffers, glDeleteVertexArrays and such to free memory. However, Java has a Garbage Collector which typically means that all memory is freed when the JVM shuts down. Is it necessary to call glDelete* when using Java? Perhaps I should only call these functions earlier on for objects that are not needed anymore to improve performance.


Answer:

OpenGL objects are not part of Java's garbage collection scheme, and my understanding is that LWJGL does nothing to attempt to wrap them in something that will automatically collect them (since that would be exceedingly difficult).

Anything OpenGL objects that you don't delete will eventually be destroyed when your program terminates, so the main concern would be if you run your application for some length of time and just drop things you don't use on the floor instead of deleting them. For simplistic apps that are just going to load some stuff at the beginning and run, that's fine. For anything of significant complexity, you're going to have to work out a time to delete objects you're not using.

Question:

Im making a game in Java and I want to render about 20000 rectangles at the same time really fast without using shaders. Is this really possible?


Answer:

This depends on how big they are and how much of them are rendered. You can clip the rectangles not facing the camera. You can also stop rendering rectangles that are far away from the camera. You can also try to discard rectangles that won't be shown.

You shouldn't render them in immediate mode. Try using VBOs/VAOs or Display Lists (deprecated) for this. This way the data (vertices and texture coordinates) are sent to the GPU only one time. (When rendered, you just call the id) If some of your geometry has the same shape, you can also use one display list / VAO for many meshes and move them around by translating/rotating/scaling the coordinate system.

Question:

I'm using LWJGL to create sort of a Minecraft Clone.

The problem is that i only get about 20 FPS. (with about 32 blocks in each direction) Also when i change the chunk the view freezes for some milliseconds.

I'm loading the textures with Slick. To render the blocks I use VBOs for textures and vertices (no VAOs or Shaders or normals). Each block consists of 6 quads which consist out of 2 triangles. Faces between blocks aren't rendered. Every frame the rendering thread checks for all 32 * 32 chunks if they are loaded into a buffer and if they should be loaded (depending on player position). If they are needed the vbos are created and the handles are saved to a list. If the chunks are too far away, the buffers get deleted. While rendering, all vbos currently in the graphics cards ram (handles saved in list) are drawn.

How can i speed rendering up? Should i have the buffers in "loaded" all the time and draw only the objects needed? Can normals or VAOs or shaders help me get a drastic improvement? Still if i get the frame rate higher there will be mor blocks than just a plate and i'm planning to import .obj.

Minecraft renders in i think DisplayLists. Would that be a solution? Create a display list for every chunk or block and recompile them if block or chunk changes?

Edit: I measured with VisualVM that the most time consuming method is glDrawArrays().

Some source code:

Rendering:

public static void render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    for(VBO vbo : vbos)
    {
        //disable texture smoothing
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glBindTexture(GL_TEXTURE_2D, vbo.texture);
        glBindBuffer(GL_ARRAY_BUFFER, vbo.vertex_handle);
        glVertexPointer(vbo.vertex_size, GL_FLOAT, 0, 0l);
        glBindBuffer(GL_ARRAY_BUFFER, vbo.texture_handle);
        glTexCoordPointer(vbo.texture_size, GL_FLOAT, 0, 0l);

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glDrawArrays(GL_TRIANGLES, 0, vbo.vertices);

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
}

Chunk loading detection:

int chunkX = (int)(camera.getX() * (-1) / GameData.CHUNK_SIZE);
        int chunkZ = (int)(camera.getZ() * (-1) / GameData.CHUNK_SIZE);

        for(int cx = 0;cx < GameData.NUMBER_OF_CHUNKS;cx++)
        {
            for(int cz = 0;cz < GameData.NUMBER_OF_CHUNKS;cz++)
            {
                boolean shouldBeLoaded = (Math.abs(chunkX - cx) <= 2 && Math.abs(chunkZ - cz) <= 2);

                if(GameData.chunks[cx][cz] != shouldBeLoaded)
                {
                    if(shouldBeLoaded)
                        Util.loadChunk(cx, cz);//loads every block in the chunk
                    else
                        Util.unloadChunk(cx, cz);
                }
            }
        }

Block loading:

public void load()
{
    try{
        if(GameData.map[x][y+1][z] == null || GameData.map[x][y+1][z].id == 2)
            top = Util.createQuad(x, y+1, z, 1, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x][y-1][z] == null || GameData.map[x][y-1][z].id == 2)
            bot = Util.createQuad(x, y, z, 1, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x-1][y][z] == null || GameData.map[x-1][y][z].id == 2)
            left = Util.createQuad(x, y, z, 0, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x+1][y][z] == null || GameData.map[x+1][y][z].id == 2)
            right = Util.createQuad(x+1, y, z, 0, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x][y][z-1] == null || GameData.map[x][y][z-1].id == 2)
            front = Util.createQuad(x, y, z, 2, id);
    }catch(IndexOutOfBoundsException e){};

    try{
        if(GameData.map[x][y][z+1] == null || GameData.map[x][y][z+1].id == 2)
            back = Util.createQuad(x, y, z+1, 2, id);
    }catch(IndexOutOfBoundsException e){};
}

Util.createQuad()

public static VBO createQuad(float x, float y, float z, int axis, int id)
{
    boolean xA = axis == 0;
    boolean yA = axis == 1;//senkrecht
    boolean zA = axis == 2;

    FloatBuffer vertex_data = BufferUtils.createFloatBuffer(6 * 3);
    if(xA)
    {
        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x, y, z+1, });
        vertex_data.put(new float[] { x, y+1, z+1, });

        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x, y+1, z, });
        vertex_data.put(new float[] { x, y+1, z+1, });
    }
    if(yA)
    {
        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x, y, z+1, });
        vertex_data.put(new float[] { x+1, y, z+1, });

        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x+1, y, z, });
        vertex_data.put(new float[] { x+1, y, z+1, });
    }
    if(zA)
    {
        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x+1, y, z, });
        vertex_data.put(new float[] { x+1, y+1, z, });

        vertex_data.put(new float[] { x, y, z, });
        vertex_data.put(new float[] { x, y+1, z, });
        vertex_data.put(new float[] { x+1, y+1, z, });
    }

    FloatBuffer texture_data = BufferUtils.createFloatBuffer(6 * 2);
    texture_data.put(new float[] { 0f, 0f, });
    texture_data.put(new float[] { 1f, 0f, });
    texture_data.put(new float[] { 1f, 1f, });

    texture_data.put(new float[] { 0f, 0f, });
    texture_data.put(new float[] { 0f, 1f, });
    texture_data.put(new float[] { 1f, 1f, });


    vertex_data.flip();
    texture_data.flip();

    int vbo_vertex_handle = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo_vertex_handle);
    glBufferData(GL_ARRAY_BUFFER, vertex_data, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    int vbo_texture_handle = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo_texture_handle);
    glBufferData(GL_ARRAY_BUFFER, texture_data, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

    VBO vbo = new VBO(vbo_vertex_handle, vbo_texture_handle, renderEngine.textures.get(id), 6, 3, 2);

    if(id == 2)//transparent
        renderEngine.vbos.add(vbo);
    else
        renderEngine.vbos.add(0, vbo);;

    return vbo;
}

Answer:

I am currently using display lists because I'm still new to lwjgl and found VBO's pretty confusing, What I do is only check if the player moved 16 blocks or more, or removed/placed a block And that's when I update my lists, Otherwise I don't update the lists, You should also stop rendering any faces that you cannot see, So while checking for which faces to draw, You should also check if they are not in your view range, Here's an example of what I do; This example checks if I should render the top face of a certain block: if(PlayerY < BlockY) { then return false; }, This way you don't need to render something that you probably can't see.

Using display lists I get around 200 - 300 FPS for a view range of 48*48, At 128 you would get around 20 - 100 FPS. EDIT: You should also start using a texture atlas if you're not already, That reduces the bind() calls, Which makes it SO MUCH faster.

So good luck, And hope I helped :)

Question:

I'm creating a game where you pick a nation and you have to manage it, but I can't find a way to load the map without crashing the program due to massive computation (lack of performance).

I made an algorithm that loops trough every pixel of an image containing the provinces (the spatial unit in the game) of the map, each has their own color, this way, when I encounter a color not yet seen in a pixel, I know that's a new province, and I can therefor load it the new Province() instance with the information from a file.

Everything above said works just fine and takes almost no time at all, but to edit the map when various nations attack each other I need a way to render singularly every province to give it its nation's color with a shader.

I've added this piece of code that gets the current pixel position and it scales it down to openGL coordinates, saving it in an arrayList (currVertices), this is then put into an another ArrayList (provinceVertices) of float[] once a new province is found.

(I know the code is not beautiful and I'm not an expert programmer (also I'm 14) so please try to be kind when telling me what I did wrong, I've tried just storing a vertex every 4 pixel to make the list smaller, but it still crashes)

List<Float> currVertices = new ArrayList<Float>(); // the vertices of the current province          
for (int y = 0; y < worldImage.getHeight(); y++) {
    for (int x = 0; x < worldImage.getWidth(); x++) {
        if (!currColors.contains(worldImage.getRGB(x, y))) {
            if (!currVertices.isEmpty())
                provinceVertices.add(Utils.toFloatArray(currVertices)); // store the current province's vertices into the total database
            currVertices.clear();
        }
        if (x % 4 == 0)
            currVertices.add((float) (x) / EngineManager.getWindowWidth());
        if (y % 4 == 0)
            currVertices.add((float) (y) / EngineManager.getWindowHeight());
    }
}

I've only included the code representing the loading of the vertices

public static float[] toFloatArray(List<Float> list) {
    float[] array = new float[list.size()];
    ListIterator<Float> iterator = list.listIterator();
    while (iterator.hasNext()) {
        array[iterator.nextIndex()] = list.get(iterator.nextIndex());
    }
    return array;
}

the goal would be for the second ArrayList to have all the vertices in the right order, but when I try and add the currVertices to the provinceVertices the game just crashes with no error message, which is why I'm guessing the problem is performance-related. (The vertices load fine into the currVertices list)


Answer:

Using nextIndex() doesn't increse the index. Try to use instead:

while (iterator.hasNext()) {
    array[iterator.nextIndex()] = iterator.next();
}