Let's Play With Cubes!

I have recently started to create a voxel engine to learn more about 3d and LibGDX. I thought I would post my discoveries, as well as questions here to hopefully help future LibGDX/3D users on their journey.

Well I started simple, just rendering a small 1x1x1 cube using a MeshPartBuilder:


http://i1173.photobucket.com/albums/r594/Slyth2727/Screenshotfrom2013-08-15220633.png

Then I decided to render a simple “chunk” just using 3 for loops:


http://i1173.photobucket.com/albums/r594/Slyth2727/Screenshotfrom2013-08-15220717.png

Why not make them smaller? Remind you of a particular minecraft map?


http://i1173.photobucket.com/albums/r594/Slyth2727/Screenshotfrom2013-08-15221135.png

Do you like candy?


http://i1173.photobucket.com/albums/r594/Slyth2727/Screenshotfrom2013-08-15221213.png

Next I would like to optimize, make a chunk system, as well as implement noise of some sort.(I’m running at 10-20 FPS and I have a rather nice computer :wink: )

Here is my current create and render code:

Create:


		ModelBuilder modelBuilder = new ModelBuilder();
		MeshPartBuilder builder;
		for (float x = GRID_MIN; x <= GRID_MAX; x += 1) {
			for (float y = GRID_MIN; y <= GRID_MAX; y += 1) {
				for (float z = GRID_MIN; z <= GRID_MAX; z += 1) {
					modelBuilder.begin();

					builder = modelBuilder.part("grid", GL10.GL_TRIANGLES, Usage.Position | Usage.Normal, new Material(ColorAttribute.createDiffuse(new Color(MathUtils.random(0, 1), MathUtils.random(0, 1), MathUtils.random(0, 1), 0))));
					builder.setColor(Color.GREEN);
					builder.box(x, y, z, .1f, .1f, .1f);
					models.add(modelBuilder.end());

					instances.add(new ModelInstance(models.get(models.size() - 1)));
				}
			}
		}

Render:


		logger.log();
		if (loading && assets.update()) {
			loading = false;
			onLoaded();
		}

		if (Gdx.input.isKeyPressed(Keys.CONTROL_LEFT)) {
			inputController.setVelocity(25);
		} else {
			inputController.setVelocity(5);
		}

		inputController.update();

		Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

		modelBatch.begin(cam);
		modelBatch.render(instances, lights);
		modelBatch.end();

What do you think I can do for optimization?

Alright, I have implemented a chunk system :smiley: it was… interesting. What I did was in the constructor of Chunk I defined an OFFSETX and OFFSETZ. These were the multiplied by CHUNK_SIZE (10 for now) and in the chunks’ draw I just add them to the x and z. Now that I think about it, it’s alot like OpenGL’s Immediate Mode GL_QUAD Rendering… Anyways, here are the chunks with the offsets of (0, 0), (2, 2), (0, 2), (2, 0):


http://i1173.photobucket.com/albums/r594/Slyth2727/Screenshotfrom2013-08-15233207.png

So I did SOMETHING with that chunk system that made rendering faster… I honestly have no clue… But rendering one chunk doesn’t drop below 60 (the cap), however one more it goes to 30-40 and more than that it goes in the teens .__.

Oh well. Still looking for suggestions for the rendering. Anything about VBO’s? I heard they are useful :wink:

Nice! I too want to do this. Can you recommend some tutorials for an absolute beginner? All I’ve managed is to get a rotating cube with a color on each side.

I assume you’ve looked at xoppa’s tutorials? If not here:

These honestly didn’t help me that much, what did however was really just googling “libgdx cube renderer” and other stuff of the like and looking at the libgdx tests that come up on github. The one that really kicked me off though was this one:

You can use GL_TRIANGLES instead of GL_LINES in that code as well as some other things to make some interesting effects. For the camera controller I personally prefer the FirstPersonCameraController so I used that for a controller. Other than that it really is just seeing what you can find in the libgdx g3d tests on github.

I’ve added a nice purtiful skybox to go along with it as well. This will look better when I have full terrain and fog obviously.


http://i1173.photobucket.com/albums/r594/Slyth2727/Screenshotfrom2013-08-16002517.png

That’s it for tonight folks, it’s almost 1 o’clock :wink:

Have you tried making chunks one model?I believe that it would render faster if you do that.

Do you mean combining vertices so that a unmodified perfect chunk actually only contains 8 indices? I’ve read somewhere that that actually isn’t worth it because when you get into chunks that are modified, it’ll take longer for the game to connect all the cube vertices together. I would just check to see if a cube is touching “air” and then only render ones that actually are. Of course there are plenty more optimizations for chunk systems, but that is a very basic one.

Ok, Ill admit I have no clue where to go from the point that I am at for performance. I have tried rendering each face with a mesh so that I could choose whether or not to display that face if it has a neighbour, but I simply could not get it going. Tried for hours. Is there a way to maybe not render the cubes that I cannot see? Do you have an idea of how to render a cube face by face with a mesh?

If anyone could offer anyhelp I would be very thankful because I just felt like I lost all the enthusiasm that I had when I first got something in 3d to render and I’d love to get it started again

Well first off, when you are trying to see if you can “see” a face, there are two ways to do it (generally speaking). You can do frustum culling. LibGDX provides a few methods like this one:

pointInFrustum(Vector3 point)

That allow you to check if a certain object is viewable on the screen currently. There is also a frustum check from LibGDX that allows you to use bounding boxes, so you may or may not choose to use that over the point check.

You can also loop through all your cubes in the chunk and check whether or not the chunk is visible to “air”. For instance (some psuedo code):

boolean facesVisible[5];

for (int x = startChunkX; x < endChunkX; x++)
     //repeat for other two dimensions

     if(blocks[x][y][z].hasBlock(x + 1, y, z)
	facesVisible[0] = false;
	else 
	facesVisible[0] = true;
     //check all other six faces

     if(facesVisible[0 to 5] = false 
	//dont add block to your renderer
     else 
	//add blocks to renderer

You can also only render faces which are visible. So you can add only faces to the renderer instead of whole blocks (if you already aren’t doing so). I would also not update blocks every frame. I would only update them if a block touching them suddenly changes. For instance, if you have a water block and you remove a solid block that was blocking it, update the blocks directly touching the water. You can even go further and say only update blocks that can be affected by water. So, if water interacts with sand, only update the sand blocks that are touching the new water block, don’t update any of the blocks that don’t interact with water. I’m getting pretty specific now, so I’ll stop and let you contemplate those ideas.

The next thing you have to consider is making your own block class and using shaders to do your rendering. I imagine you’re still using the model builder that LibGDX provides, but you have to realize this probably isn’t going to be enough. I guess it may be if you aren’t looking to make a super amazing game, I just imagine the model builder isn’t the most efficient thing ever. It might actually be, I have no idea considering I’ve never used the new 3D API, so take my word with a grain of salt.

I’ll try to find some resources on frustum culling, if you have any questions feel free to ask!

Good lord man, thanks so much! This is exactly what I needed! I’ll jump right into testing these, I can’t wait to see what else you come up with

Not to beg, but I always do love a good medal :wink: hint

I also found this rather long, and technical post about frustum culling :
http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html
And LibGDX’s simple approach:
https://code.google.com/p/libgdx-users/wiki/Culling#View_frustum_culling

I completely forgot about the medals on this site! Forgive me :wink:

Oh, no problem! Just hit appreciate, of course only if you want!