Huge lag in voxel engine using lwjgl

everyone ! First of all, please excuse my english, i’m just a poor frenche programer who’s fighting for a project maybe a little to big for him. :smiley:

So, let me explain : I start developing a voxel engine using lwjgl. To do so, i implemented several class such as chunk, chunkManger (which of course manage all the chunks in the game) and of course cubes. There’s a lot more but this is the basics.

To draw my cubes i use VBO (Vertex buffer Object), the chunk have the main vbo an i update it for every cube i have to draw at each frame of the game. As you can think, it’s result of massive lags for nothing more than 400 cubes to draw. I’ve of course enable face-culling and i have a function that make sure to render only the visible cubes.

So me question is if anybody have the patience and the kindness to look at my sources (https://github.com/Akinesis/DinoSurvive/) and tell me what i do wrong (though i already have an idea why).

Well thank you for reading me and maybe thank you for helping me.

P.S: I’m not sure to be in the right section so sorry if i’m not.

Put all the cubes in one VBO instead of one VBO per cube

I figured it was the solution but if i do so, i could i be able to map the associate texture to the cube. I still need to draw the texture (wich difere for a cube to an other) .

Or maybe ther’s somthing i’ved miss about VBOs ?

You will need to work with spritesheets, but other that that…

I’ll looking for it, it seems interesting. But I already a-handle texturing with a unique png file. For now here what it’s look like :

http://image.noelshack.com/fichiers/2014/14/1396755269-capture-d-ecran-2014-04-06-a-05-33-53.png

(i draw the texture myself so it’s not very nice …)

What i do when i draw is this :
-Put the coordinates of the cube in the vbo
-Take the coordinate of the associate texture in a second vbo
-draw the cube
-Back to step 1 with another cube.

But if i use a single vbo per chunk (aka a big array of float) how can i say which cube i want to draw (or i am drawing) at a particular moment to load the good coordinates ?

You can not really access data in a VBO after you passed it. Thats the point. You send everything one-way as a big packet to the GPU to avoid traffic.

So if i want performance but being able to draw each cube with is specific texture i have to make a vbo per potential texture ?

That seems litle bit hardore does’nt it ? What if i have (i a bright future) 100+ type of cubes ? It’s mean each chunk will have 100 different vbo ?

It will always be less than 4096 but …

Use spritesheets. Then you can have 1 vbo for the whole chunk.

You give every vertex in you VBO a texture coord on your spritesheet.
Everything in the VBO, but you need to pass the texture coordinates.

Hi guys, first of all, thanks for your advices. With them i managed to do much better but i’m stuck again and maybe you could help (i could make a new post but the problem is related to the first one so …).

Anyway ! I put all my cubes coordinate into one and only vbo (on the chunk) and to bind each cube with the specific location of the texture, i stored the coordinate into the same vbo (the same float buffer on the vbo). For as much as i understand, i must “intervaled” my vbo rendering passing in argument many things so i will work. But right know all i have i my display and nothing in it. My cube wont render anymore.

So if someone could try to explain me how all of this work (i can show you the function i’m using), it would be verry nice.

Thanks.

Well, showing what you have would probably be the best for now…

Every time someone talks about VBO’s I have to post this post as it explains more or less anything in a simple way:

It’s almost the same for textures and colors, so it should give you a good beginning.

Mike

@Mike : Yup i’ve already find this (really helpful) post but i must have messed up something by trying to reproduce it.

I’ll put there my generating and rendering methods and if you want to watch the full project, chek the “problem” branch on the github link (https://github.com/Akinesis/DinoSurvive/tree/problem)

The chunk class (handling the vbo):

//call befor the rendering loop
public void genVBO(){
		vboVertexHandleChunk = GL15.glGenBuffers();
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexHandleChunk);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, interleavedBuffer, GL15.GL_STATIC_DRAW);

		// -- Now we can split our interleaved data over 2 attribute lists
		// First up is our positional information in list 0
		GL20.glVertexAttribPointer(0, positionFloatCount, GL11.GL_FLOAT, false,
				vertexFloatSizeInBytes, 0);

		// Second is our texture information in list 1, for this we also need the offset
		int byteOffset = floatByteSize * 2;
		GL20.glVertexAttribPointer(1, positionFloatCount, GL11.GL_FLOAT, false, vertexFloatSizeInBytes, byteOffset);

		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		GL30.glBindVertexArray(0);

	}

//put each cube int the Buffer 
//the two genCUbe method return an array of float (the coordinates of the cube and the texture's one)
public void genCubes(TextureManager texMan){
		interleavedBuffer = BufferUtils.createFloatBuffer(renderCubes.size()*3*2*36);
		for(Cube3dVbo cube : renderCubes){
			interleavedBuffer.put(cube.genCubes());
			interleavedBuffer.put(texMan.genText(cube.getType(), cube.getTextX(), cube.getTextY()));
		}
		interleavedBuffer.flip();
	}

//a monkey with a keyboard would have done something better than this.
//this is the method called in the rendering loop
public void draw(TextureManager texMan){
		//texMan.bindBuffer();
		GL13.glActiveTexture(GL13.GL_TEXTURE0);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, texMan.getTextVBO());
		
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexHandleChunk);
		
		glDrawArrays(GL_TRIANGLES, 0, 36*renderCubes.size());
		GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
	}

The textureManager class:

//the constructor, also, i do not know what i am doing here, at least for half of the code
public TextureManager() {
		tWidth = 0;
		tHeight = 0;
		try {
			// Open the PNG file as an InputStream
			InputStream in = new FileInputStream("res/text.png");
			// Link the PNG decoder to this stream
			PNGDecoder decoder = new PNGDecoder(in);
			
			// Get the width and height of the texture
			tWidth = decoder.getWidth();
			tHeight = decoder.getHeight();
			// Decode the PNG file in a ByteBuffer
			buf = ByteBuffer.allocateDirect(
					4 * decoder.getWidth() * decoder.getHeight());
			decoder.decode(buf, decoder.getWidth() * 4, Format.RGBA);
			buf.flip();
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(-1);
		}

		textureData = BufferUtils.createFloatBuffer(36 * 2);
		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		
		textVBO = GL11.glGenTextures();
		GL13.glActiveTexture(GL13.GL_TEXTURE0);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, textVBO);

		// All RGB bytes are aligned to each other and each component is 1 byte
		GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
		
		// Upload the texture data and generate mip maps (for scaling)
		GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, tWidth, tHeight, 0,
		GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);
		GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);

		// Setup the ST coordinate system
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
		
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
				GL11.GL_NEAREST);
				GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
				GL11.GL_LINEAR_MIPMAP_LINEAR);
	}


Here, i think you got everything. If you not hate me after seeing what i’m doing here and still wanna help, thank you. Otherwise thank you for at least reading me.

That code looks messy :slight_smile: The first thing that pops out is that you first draw all vertrices and then all textures for each cube, instead of splitting them up in triangles. Why don’t you try to first get a single triangle on the screen and then add another one and then expand that to all the cubes? I think that will be a lot easier for you.

Mike

That a good advice but the thing is … I don’t understand all of what i am doing.

So yeah i really need help sorry. I just tryed random thinks based on what i could find on textured vbo and intervaling but it’s not all clear to me.

I don’t heaven see how am i drawing all the cube then the textured and not a triangle at a time.

Sorry and thanks for the answer.


GL20.glVertexAttribPointer(0, positionFloatCount, GL11.GL_FLOAT, false, vertexFloatSizeInBytes, 0);
GL20.glVertexAttribPointer(1, positionFloatCount, GL11.GL_FLOAT, false, vertexFloatSizeInBytes, byteOffset);

What is this ‘positionFloatCount’ variable?

The 2nd parameter (‘size’) specifies how many components your vertex attribute has.
3 for 3D vertex
2 for 2D vertex
2 for regular texcoords
4 for RGBA colors
etc, etc

Additionally, it seems your [icode]int byteOffset = floatByteSize * 2;[/icode] is probably off, because presumably you start your interleaved geometry with the vertex position, which is 3D (you’re rendering cubes), so the offset for the 2nd vertex attribute should be 3 floats, not 2 floats.

Hi,

so ‘positionFloatCount’ is 3 which i change in 2 for the the call of glVertexAttribPointer. I also try several combination with the offset but i still have a clear screen with nothing drawn on it.

Hi,

That is (also?) because you aren’t adding vertex,vertex,vertex,texCoord,texCoord,vertex,vertex,vertex,texCoord,texCoord and so on.

You are adding first all vertices from each cube and then all texture coordinates, like this: vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,vertex,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord,texcoord

That’s not going to work, which is why I suggested that you start with just drawing a single triangle and then work your way up from that :slight_smile:

Mike

Hello,

so i try what you said to me, so i intervaled mes triangle like so : VVVTTVVVTTVVVTT …
but nothing change. I’m sorry i do not test with only one but it would to longue to figure out to rearrange my code to make a single triangle.

Here what i did:

public void genCubes(TextureManager texMan){
		interleavedBuffer = BufferUtils.createFloatBuffer(renderCubes.size()*3*2*36);
		float[] textArray, cubeArray;
		int i;

		for(Cube3dVbo cube : renderCubes){
			textArray = texMan.genText(cube.getType(), cube.getTextX(), cube.getTextY());
			cubeArray = cube.genCubes();
			int j = 0;
			
			for(i =0; i<108; i+=3){
				interleavedBuffer.put(cubeArray[i]);
				interleavedBuffer.put(cubeArray[i+1]);
				interleavedBuffer.put(cubeArray[i+2]);
				
				interleavedBuffer.put(textArray[j]);
				interleavedBuffer.put(textArray[j+1]);
				System.out.println(i +" " + j);
				j+=2;
			}
	
		}
		interleavedBuffer.flip();
	}

As it appears you can’t figure it out while having it integrated in your game, do just like Mike said:

  • render 1 triangle
  • render 2 triangles
  • render 3 triangles
  • render 1 cube
  • render 2 cubes
  • integrate in your engine