Drawing in Allegro5 (Part 2)
pmprog

Sorry for the new thread, my other one seems to be locked now.

I've written some code to try drawing a voxel room. Originally I tried drawing three quads per cube, one for each visible face. But when you tried to maintain a list for a 100x100x100 cube, obviously the memory usage was massive and was working with 6 million triangles, and I dropped loads of frames.

So I switched to pre-rendering my cubes, and just blitting cubes on the screen, skipping cubes that were hidden by surrounding cubes, but even on a 80x80x48 scene I drop a few frames per second

https://youtu.be/4wtIjHPp8oU

The obvious downside is that I'm stuck with that "view" - which isn't the worst thing in the world, but I'd have liked to have had the option to swing my camera around to each of the four isometric viewpoints.

I think my main problem is most of my code is CPU based, when I really need to figure out how to make it GPU based.

This site talks about Vertex Buffers
https://sites.google.com/site/letsmakeavoxelengine/home/display-lists-or-vertex-buffers
and I can see Allegro has a create vertex buffer function; so maybe this is the approach I need to look down?

There's a couple of bits with this though.

Firstly, Each vertex has a colour. In order to have two cubes next to each other with different colours, I presume I'd have to have two vertices at the same location one with the colour for the cube on the left, and the other with the cube on the right? Otherwise, GL would just try and blend the colours as it renders the cube right?

Secondly, I think most of frame drops are due to that most of my rendering is pushed by the CPU. So could I use vertex buffers to render bitmaps?

I assume with either approach, if I was to toggle a voxel on/off, I presume I'd have to create a new vertex buffer again?

Cheers

MikiZX

Vertex buffer object (VBO) would give you the best results.
With VBO you could create it before your main loop (as it would certainly be time consuming to complete) and then in your main loop just call Allegro function to draw it, which should be fast as all the required data at that point will already be on the gfx card.
Traingles that would make up cube's faces could share vertices between them or use their own - it is in the Index buffer object(IBO) that you would tell Allegro how to connect these vertices into trianles/cube.
Once you pre-generate the VBO and IBO (before the main loop), in the main loop you could update only parts of the VBO so updating one cube with different color or position could be done without re-creating the entire VBO.

If 2d example can help:
An example of using VBO with Allegro can be found here: https://github.com/mikiZX/Allegro5-2d-Platformer-Demo-using-VBOs-and-Tiled-tilemaps

Creation of a VBO/IBO from a 2d map starts at line 100 of main.c

In your main loop, updating part of the VBO would be done using these commands:

void* lock_mem = al_lock_vertex_buffer(my_vbo_gpu_id, 0, 4, ALLEGRO_LOCK_WRITEONLY);
memcpy(lock_mem, &my_vbo_data, sizeof(ALLEGRO_VERTEX) * 4);
al_unlock_vertex_buffer(my_vbo_gpu_id);

In your main loop you would only have one call to al_draw_indexed_buffer to draw your voxel map.

pmprog

Thank you for the reply, had a quick look at your code, and I'll dig into it a bit later when I get a bit of free time.

But looks like a great help, thank you.

Edit: Is there a reason to create an index buffer. By looking at it, you can simply just draw the vertex buffer directly?

MikiZX

You are right about IBO.
Index buffer would permit re-using the vertices already present in the VBO hence making the VBO smaller. If you plan on defining each voxel using its own set of vertices then yeah, there is no need for the IBO and you could use al_draw_vertex_buffer instead.

pmprog

I'm not sure this is going to work. 128x128x128 cubes = 2.1mill * 8 vertices each (I can't reuse the points, as vertex colour would differ) = ~17mill vertices.

Can graphics cards even take that many vertices being uploaded?

I did find a sample somewhere on this forum (can't remember where now), that rended 300,000 vertices randomly across the screen, but even that chugged my computer.

Hmmm, maybe I could produce a VBO just for one layer of 128x128 cubes (131,072 vertices), then for each Z layer, modify the colours for each vertex, draw to screen, raising up the y axis. Still seems an awful lot to render.

I did try caching each layer of the voxel in a bitmap, only only re-render that when a voxel is changed inside, but that consumed massive amounts of memory.

Maybe to get the resolution I want, maybe I need to try this trick
http://www.squidi.net/three/entry.php?id=250
Though I imagine with a fairly large voxel matrix, this could be quite difficult to keep track of which blocks fit in which triangles.

The only other thing I could think is decreasing the number of triangles by searching each side of each plane of the voxel model, and combining a bunch of connected colours together. But I can imagine my computation time being huge.

To be fair, blitting a pre-rendered cube, and tinting it got me there without framedrops in Release mode, though I did have problems rendering that cube based on resolution.

Sorry, think I'm just waffling now, and not really getting anywhere... Maybe I should ditch the voxel approach, and either go back to 2D or consider low-poly 3D

MikiZX

Possibly 'ray-marching' is something that can help you? For both 2d or 3d you could do sort of ray-trace of your voxel model and only draw the first encountered voxels (which then obscure everything behind).
I've never done this though so I'm only guessing...

pmprog

I have made some decent progress

https://www.youtube.com/watch?v=aFtF41gF_6Q

Now this uses 6 triangles per cube, rather than 2 for drawing a prerendered cube. However, I only draw visible surfaces, and in theory, I should be able to "rotate" the camera if I get confident enough.

Now, if I create a single Voxel class of 128x128x128, performance degrades quite quickly as it rebuilds the vertex buffers. However, if you create several 32x32x32 Voxels and draw them next to each other, performance is much improved.

The VBOs are cached, so I'm only adjusting VBOs for rows that have been changed, and there's a "HoldRefresh" function so if I update multiple voxels in a single row, I can wait until I've done them all before the VBO is refreshed.

I haven't actually measured the performance yet, but seems fairly smooth, and as long as I keep animations and transparency to a minimum, should end up being quite a smooth engine.

Thanks for the suggestion, I'll keep ray-marching in mind if I do run into performance problems, but at the minute, I'm thinking it's looking fairly good.

Thread #618136. Printed from Allegro.cc