Problem loading mutiple objects properly in game (full source)

Started by Kaboom, September 14, 2015, 18:40:58

Previous topic - Next topic

Kaboom

Hey guys I need some help with my game rendering engine from someone with a bit more experience than I currently have as I cannot get my models to load properly.

The game is coded in OpenGL and Java and uses GLSL 130 for shader support. What happens is when I load one single object it will render taht object properly and have spectral lighting and ambient lighting and everything else works great. I can load up 1000+ of the same model onto my screen and they all render properly. Sounds good right?

But if I load a second model, the second model that is rendered will come up properly and the first model will be distorted all over its vertexes. I cannot switch to a higher GLSL version so I am currently using #version 130. When I generate my terrain, it loads properly as its the last thing rendered by the engine but all the models for npc and players and the like get scewered verteces.

The game is using lwjgl (latest version 2, legacy) and slicktools2D. I have had it suggested that it could be an issue with the matrix not reseting on the next model but my code looks good. It could also be a hardware problem as i have only opengl 2.1 with some 3.0 capacity on my laptop, but since it does load one model at a time perfectly with this engine, it doesnt make sense it cant load more than one type.

Here is a screen shot of my problem to see what I mean for you guys: 
http://imgur.com/NwKhqeS

Hopefully by submitting my source here someone can go through it and see if they can tell me what I am missing?? I have included all my java files and models in the attachment below.

Here is the source code for my game so far (from eclipse):   
https://www.mediafire.com/?clwgbxwvo605ht1

emris

I see you are using an engine based on ThinMatrix tutorials, cool :)  ..  https://www.youtube.com/playlist?list=PLRIWtICgwaX0u7Rf9zkZhLoLuZVfUksDP

Your download link is not working so i can't take a closer look, but maybe your problem is with the loader, maybe the VAO/VBO id's are getting mixed up, or it could be something totally different. It's very hard to say without the code.
=====================================================
Nothing is impossible....except that the state of your mind makes it so.
=====================================================

Kaboom

Here is my current game engine. And yes it was based on ThinMatrix engine :) Unfortunately even he could not find an issue with my code to see what was causing the issue :(

https://www.mediafire.com/?clwgbxwvo605ht1

and here is my loader.class
package renderEngine;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;

import models.RawModel;
import textures.TextureData;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;

import de.matthiasmann.twl.utils.PNGDecoder;
import de.matthiasmann.twl.utils.PNGDecoder.Format;

public class Loader {

    private List<Integer> vaos = new ArrayList<Integer>();
    private List<Integer> vbos = new ArrayList<Integer>();
    private List<Integer> textures = new ArrayList<Integer>();
    
    public RawModel loadToVAO(float[] positions, float[] textureCoords, float[] normals, int[] indices) {
        int vaoID = createVAO();
        bindIndicesBuffer(indices);
        storeDataInAttributeList(0, 3, positions);
        storeDataInAttributeList(1, 2, textureCoords);
        storeDataInAttributeList(2, 3, normals);
        unbindVAO();
        return new RawModel(vaoID, indices.length);
    }
    
    public RawModel loadToVAO(float[] positions, int dimensions) {
        int vaoID = createVAO();
        storeDataInAttributeList(0, dimensions, positions);
        unbindVAO();
        return new RawModel(vaoID, positions.length / dimensions);
    }
    
    public int loadTexture(String fileName) {
        Texture texture = null;
        try {
            texture = TextureLoader.getTexture("PNG", new FileInputStream("models/"+fileName+".png"));
            //To add mipmapping for objects we need this, doesn't work on my cpu tho
            //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.4f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        textures.add(texture.getTextureID());
        return texture.getTextureID();
    }
    
    public void cleanUp() {
        for (int vao : vaos) {
            GL30.glDeleteVertexArrays(vao);
        }
        for (int vbo : vbos) {
            GL15.glDeleteBuffers(vbo);
        }
        for (int texture : textures) {
            GL11.glDeleteTextures(texture);
        }
    }
    
    public int loadCubeMap(String[] textureFiles) {
        int texID = GL11.glGenTextures();
        GL13.glActiveTexture(GL13.GL_TEXTURE0);
        GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texID);
        for (int i = 0; i < textureFiles.length; i++) {
            TextureData data = decodeTextureFile("models/skybox/" + textureFiles[i] + ".png");
            GL11.glTexImage2D(GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL11.GL_RGBA, data.getWidth(), data.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, data.getBuffer());
        }
        GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL13.GL_TEXTURE_CUBE_MAP, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
        textures.add(texID);
        return texID;
    }
    
    private TextureData decodeTextureFile(String fileName) {
        int width = 0;
        int height = 0;
        ByteBuffer buffer = null;
        try {
            FileInputStream in = new FileInputStream(fileName);
            PNGDecoder decoder = new PNGDecoder(in);
            width = decoder.getWidth();
            height = decoder.getHeight();
            buffer = ByteBuffer.allocateDirect(4 * width * height);
            decoder.decode(buffer, width * 4, Format.RGBA);
            buffer.flip();
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("Tried to load texture " + fileName + ", didn't work");
            System.exit(-1);
        }
        return new TextureData(buffer, width, height);
    }
    
    private int createVAO() {
        int vaoID = GL30.glGenVertexArrays();
        vaos.add(vaoID);
        GL30.glBindVertexArray(vaoID);
        return vaoID;
    }
    
    private void storeDataInAttributeList(int attributeNumber, int coordinateSize, float[] data) {
        int vboID = GL15.glGenBuffers();
        vbos.add(vboID);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
        FloatBuffer buffer = storeDataInFloatBuffer(data);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
        GL20.glVertexAttribPointer(attributeNumber, coordinateSize, GL11.GL_FLOAT, false, 0, 0);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    }
    
    private void unbindVAO() {
        GL30.glBindVertexArray(0);
    }
    
    private void bindIndicesBuffer(int[] indices) {
        int vboID = GL15.glGenBuffers();
        vbos.add(vboID);
        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboID);
        IntBuffer indicesBuffer = storeDataInIntBuffer(indices);
        GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL15.GL_STATIC_DRAW);
    }
    
    private IntBuffer storeDataInIntBuffer(int[] data) {
        IntBuffer buffer = BufferUtils.createIntBuffer(data.length);
        buffer.put(data);
        buffer.flip();
        return buffer;
    }
    
    private FloatBuffer storeDataInFloatBuffer(float[] data) {
        FloatBuffer floatBuffer = BufferUtils.createFloatBuffer(data.length);
        floatBuffer.put(data);
        floatBuffer.flip();
        return floatBuffer;
    }
    
}

emris

I just downloaded and tried your code, and everything looks fine for me. No strange graphical glitches that i can see.
=====================================================
Nothing is impossible....except that the state of your mind makes it so.
=====================================================

Kaboom

Thats because your gpu is doing something to render the models correctly while mine cannot since it only supports opengl 2.1 with some support for 3.2 stuff. Thats why I cannot use mipmapping on my code at all. I am missing something gpu specific to tell my gfx card to render the models correctly because it doesnt understand the buffering or something and is distorting models when it loads the next one. It is programmed perfectly for a gpu supporitng opengl 3+ but sadly not 2.1+ and since most normal laptops (mine included) run 2.1 varients, I need to be able to run in those gpus as well to support my game (and continue coding it without a new pc).

If you can see anything I am missing to render multiple objects on older gpus please let me know! :) thanks.

Kaboom

glbindVertexarray using opengl 2.1 to use my vbo and vao is apparently unsupported so its messing up my model rendering :( I dont know  a way to work around this

Kai

Quote from: Kaboom on October 01, 2015, 03:57:01
glbindVertexarray using opengl 2.1 to use my vbo and vao is apparently unsupported so its messing up my model rendering :( I dont know  a way to work around this
If you currently rely on using VAOs to encapsulate vertex array state, such as vertex bindings and array enablings, then there is no easy way to work around this.
However, OpenGL VAOs do not require a full OpenGL 3.0 capable graphics cards.
The extension itself is written against OpenGL 2.1, and the functionality should be purely server-side book-keeping.
So please update your graphics card driver and/or see whether you have the ARB_vertex_array_object extension available, and use that.
(I have an Nvidia GeForce 6200 LE, with driver 309.08 right now here, that also only supports OpenGL 2.1.2, but does have that extension available.)
If that does not help, then I would probably build my own abstraction of a VAO and delegate all vertex array state functions (glVertexAttribPointer, glEnableVertexAttrib, ...) through it.
That abstract VAO class then handles whether it can use a real OpenGL VAO or must emulate it by using many OpenGL vertex array state functions when switching from one VAO to another.

Kaboom

Quote from: Kai on October 01, 2015, 08:56:06
If you currently rely on using VAOs to encapsulate vertex array state, such as vertex bindings and array enablings, then there is no easy way to work around this.
However, OpenGL VAOs do not require a full OpenGL 3.0 capable graphics cards.
The extension itself is written against OpenGL 2.1, and the functionality should be purely server-side book-keeping.
So please update your graphics card driver and/or see whether you have the ARB_vertex_array_object extension available, and use that.
(I have an Nvidia GeForce 6200 LE, with driver 309.08 right now here, that also only supports OpenGL 2.1.2, but does have that extension available.)
If that does not help, then I would probably build my own abstraction of a VAO and delegate all vertex array state functions (glVertexAttribPointer, glEnableVertexAttrib, ...) through it.
That abstract VAO class then handles whether it can use a real OpenGL VAO or must emulate it by using many OpenGL vertex array state functions when switching from one VAO to another.

I have the latest drivers for my pc, I thought maybe I could get a better one and fix the problem but my pc doesnt support the binding function from gl30 so it returns all the vaos vertexes as the same and it distorts my models. I can load them without the use of the vao since all the model data is stored in vbos and only load vaos if the driver support is over 3.0, but it adds a lot more code for me so I was kind of syked to use the vao system to load my models. Ill have a look and see if I have support for the ARB version, but if I do, what would I use instead in my renderer to load the models using arb extensions if I am using lwjgl? I've never used them before.

Kai

Well, just use:

import static org.lwjgl.opengl.ARBVertexArrayObject.*;


instead of:

import static org.lwjgl.opengl.GL30.*;


You can check whether the driver supports that extension by doing (LWJGL 3 latest nightly build):

GLCapabilities caps = GL.createCapabilities();
boolean hasThatExtension = caps.GL_ARB_vertex_array_object;
if (hasThatExtension) {
  // use it
} else {
  // emulate it
}


So, if the driver does not export that extension, then I would build another class containing the static vertex array state functions, and do the bookkeeping of the vertex array state myself.
So, you would just not call GL30.glBindVertexArray anymore, but your own GL30Emulation.glBindVertexArray, as well as the GL15 functions.
Then you would not have to update your current application/engine code, except switch the static import.

It is however a pity that all the GLxx classes in LWJGL 3 are final. Because otherwise one could just extend those classes and override or rather "hide" the vertex array functions by implementing new ones. This way, one would not have to choose between either GL15 functions unrelated to vertex array state and the GL30Emulation (and GL15Emulation) classes which also disallows static imports, because of ambiguous methods.

Kaboom

I did a quick print out from my code and this is what my pc has:

OpenGL Version: 2.1.0 - Build 8.15.10.2869
GPU Chipset: Mobile Intel(R) 4 Series Express Chipset Family
Chip Type: Intel
Supported Extentions:
GL_EXT_blend_minmax
GL_EXT_blend_subtract 
GL_EXT_blend_color 
GL_EXT_abgr 
GL_EXT_texture3D 
GL_EXT_clip_volume_hint 
GL_EXT_compiled_vertex_array 
GL_SGIS_texture_edge_clamp 
GL_SGIS_generate_mipmap 
GL_EXT_draw_range_elements 
GL_SGIS_texture_lod 
GL_EXT_rescale_normal 
GL_EXT_packed_pixels 
GL_EXT_texture_edge_clamp 
GL_EXT_separate_specular_color 
GL_ARB_multitexture 
GL_EXT_texture_env_combine 
GL_EXT_bgra 
GL_EXT_blend_func_separate 
GL_EXT_secondary_color 
GL_EXT_fog_coord 
GL_EXT_texture_env_add 
GL_ARB_texture_cube_map 
GL_ARB_transpose_matrix 
GL_ARB_texture_env_add 
GL_IBM_texture_mirrored_repeat 
GL_EXT_multi_draw_arrays 
GL_NV_blend_square 
GL_ARB_texture_compression 
GL_3DFX_texture_compression_FXT1 
GL_EXT_texture_filter_anisotropic 
GL_ARB_texture_border_clamp 
GL_ARB_point_parameters 
GL_ARB_texture_env_combine 
GL_ARB_texture_env_dot3 
GL_ARB_texture_env_crossbar 
GL_EXT_texture_compression_s3tc 
GL_ARB_shadow 
GL_ARB_window_pos 
GL_EXT_shadow_funcs 
GL_EXT_stencil_wrap 
GL_ARB_vertex_program 
GL_EXT_texture_rectangle 
GL_ARB_fragment_program 
GL_EXT_stencil_two_side 
GL_ATI_separate_stencil 
GL_ARB_vertex_buffer_object 
GL_EXT_texture_lod_bias 
GL_ARB_occlusion_query 
GL_ARB_fragment_shader 
GL_ARB_shader_objects 
GL_ARB_shading_language_100 
GL_ARB_texture_non_power_of_two 
GL_ARB_vertex_shader 
GL_NV_texgen_reflection 
GL_ARB_point_sprite 
GL_EXT_blend_equation_separate 
GL_ARB_depth_texture 
GL_ARB_texture_rectangle 
GL_ARB_draw_buffers 
GL_ARB_color_buffer_float 
GL_ARB_half_float_pixel 
GL_ARB_texture_float 
GL_ARB_pixel_buffer_object 
GL_EXT_framebuffer_object 
GL_ARB_draw_instanced 
GL_ARB_half_float_vertex 
GL_EXT_draw_buffers2 
GL_WIN_swap_hint 
GL_EXT_texture_sRGB 
GL_EXT_packed_float 
GL_EXT_texture_shared_exponent 
GL_ARB_texture_rg 
GL_ARB_texture_compression_rgtc 
GL_NV_conditional_render 
GL_EXT_texture_swizzle 
GL_ARB_framebuffer_sRGB 
GL_EXT_packed_depth_stencil 
GL_ARB_depth_buffer_float 
GL_EXT_transform_feedback 
GL_EXT_framebuffer_blit 
GL_ARB_vertex_array_object


I switched all my gl30 calls to ARB:
//GL30.glDeleteVertexArrays(vao);
ARBVertexArrayObject.glDeleteVertexArrays(vao);


//int vaoID = GL30.glGenVertexArrays();
int vaoID = ARBVertexArrayObject.glGenVertexArrays();
vaos.add(vaoID);
//GL30.glBindVertexArray(vaoID);
ARBVertexArrayObject.glBindVertexArray(vaoID);


My models are still not rendering properly on my machine though and it says it supports the arb functions :( So i am at a loss..

Kaboom

I set up a way to check the opengl version of the pc and then set it to load the code based on wether or not the user has opengl 3+ support or is running less then they use the arb versions. While this doesnt solve my issue with my pc, it might add engine support to other computers that can run it. I did so as follows:

if (DisplayManager.OPENGL < 300) {
    ARBVertexArrayObject.glBindVertexArray(0);
} else {
    GL30.glBindVertexArray(0);
}


I check the version by implementing a check on the opengl string for GL_VERSION in my Display manager as follows:
public static int OPENGL = 0;

//Load the openGL version from string as "2.1.0" and set result to 0
String gl_Version = GL11.glGetString(GL11.GL_VERSION);
String result = "";
            
//Because it loads int . int . int we need to have the first 5
for (int i = 0; i < 5; i++) {
    Character character = gl_Version.charAt(i);
    if (Character.isDigit(character)) {
        result += character;
        Integer.parseInt(result);
    }
}
            
OPENGL = Integer.parseInt(result);

quew8

I'd suggest a more reliable way to ascertain the OpenGL version is by using LWJGL's GLCapabilities class. Check out this code:

boolean isGL33 = GL.getCapabilities().OpenGL33;


That class also contains information on supported extensions, which would also be useful to you. For example if you wanted to check for the ARB framebuffers extension.

boolean ihasFramebuffers = GL.getCapabilities().GL_ARB_framebuffer_object;

Kaboom


SHC

In LWJGL 2.9, that is GLContext.getCapabilities().OpenGL33;

http://legacy.lwjgl.org/javadoc/org/lwjgl/opengl/GLContext.html#getCapabilities()
http://legacy.lwjgl.org/javadoc/org/lwjgl/opengl/ContextCapabilities.html#OpenGL33

That makes the previous code to this.

boolean isGL33 = GLContext.getCapabilities().OpenGL33;
boolean ihasFramebuffers = GLContext.getCapabilities().GL_ARB_framebuffer_object;


The only change is the class name, GLContext is replaced by GL in LWJGL 3.

Kaboom

Quote from: SHC on October 27, 2015, 13:48:25
In LWJGL 2.9, that is GLContext.getCapabilities().OpenGL33;

...

The only change is the class name, GLContext is replaced by GL in LWJGL 3.

Thanks for the response but I found out that method shortly after I had replied to him and forgot to check back in :P Unfortunately, while I also am using the LWJGL function to check for ARB function support on clients PC and use those extensions where available, it is still rendering strange on my laptop supporting openGL 2.1 but works well on my friends PC who runs opengl 3. As far as I can tell on my code it should be showing properly on my laptop as well but it is not.

Here is an updated picture of whats happening to the models:
http://i.imgur.com/7OysbUa.png

I will also give you a link to the newer source code here, I have been changing some stuff up and added support for icons and what not as well as some other things to make the layout nicer but I am still having that issue on this PC shown in the image above and I really want to fix it. Thanks to some awesome users here, my shaders running version 130 also support an inverse function now that isn't core until 150 so I can do proper texturing now. Just wish the models kept proper vertices and normals on this pc like they do on a better one :(

Newer source code:
http://www.megafileupload.com/5ofy/Redwall_v30.rar


Here is a video of the problem I have
https://www.youtube.com/watch?v=FJcTVu2eXQk