A question about efficency

Here’s the deal; I want to create a minecraft-like environment as far as chunks and blocks go. I have got some code in place that is delivering terrible performance when I get above 10 by 10 by 10 in one chunk. I am doing some face culling in form of removing faces in between blocks and backface culling cutting vertices to about 3600 in this case, which is giving me about 20fps.

One block consists of 6 Polygon faces which in turn is made up of one mesh and 6 vertices, the whole mesh is removed when I do the culling in between blocks.

With backface culling off I get a more constant fps but lower than with it on, clocking in at 17-18fps.
Note: The backface culling is not removing polygons, only deciding if they should be drawn or not.

I do have a simple lightsystem in place which is only calculated once and will probably be remade when I learn more about shaders. It does not deliver any performance hit at runtime.

When it comes to optimizing this I do have a few thoughts in mind but I would like some input about these and which one that might be the best option in this case.

  • Generating a chunk as one complete mesh(I am not sure if this is possible though)
  • Merging each face on each block into one mesh = 1mesh/Block
  • Somehow creating only one block and then just making copies of it(Like a VBO object)
  • If you have a better suggestion than any of these then I’d gladly like to hear it

I’m pretty new to the shader concept and I have yet to understand it completely, but I kinda know how they work.
And as I understand using shaders to do some of the work would increase the performance alot.

@Muffincoder - as I recall from my own experiments, performance is linked quite closely to the number of vertices.

If all your blocks are the same size, you should only need to build one of them initially, then you can draw it as many times you need with different textures.

I guess you know you should sort any overlapping blocks or other objects, to draw the furthest ones first, to avoid flicker and other artifacts.

OpenGL is supposed to do its own face culling, but I’m not an expert on that.

I have written an ebook on shaders, and another on lighting, based on my own explorations, which you can find here.

@Muffincoder - reading your post again, I’ll explain a little further that you only need to create one mesh cube, centred on 0,0,0. Then you can set the texture, translate to any position, draw the cube, and repeat as required to draw everything. (As I recall, you should specify your mesh triangles for the cube in an anti clockwise direction around the vertices, as Open GL uses this to determine which are front faces and which are back faces, when it does its own culling - but it’s been a little while since I did this).

Shaders aren’t going to solve the basic speed problem in drawing and culling cubes, but you may find a use for them.

In one of my posts, I show how to create a hemispherical sky which would look very nice in your world.

@Muffincoder - a couple more thoughts. Narrowing the field of view from the default of 45 to 30 degrees shouldn’t hurt the look of your app, but will cut down on the drawing.

You can also restrict the depth that can be viewed, again to cut down the amount you draw. I think I may have covered this an another ebook I wrote on 3D in Codea (same link as above).

Alternatively, you could use mist to hide the faraway stuff, cutting back the drawing required. This is where a shader should help you (and I explain mist shaders in my ebook), although there is a balance between the amount of work required to check whether each pixel is visible, and the time saved in not drawing it.

@Ignatz Your thoughts seem quite interesting though some of it (like fov and mist) wouldn’t help performance in the current state where I have a small chunk which is completely visible. But I’ll keep them in mind for the future :slight_smile:

About the face culling already being in opengl is right, I actually have used it once or twice before in other projects, though it is not activated by default and since I cannot access the opengl functions in Codea, I have to make my own culling (If there is a way I am not aware of then please tell me)

Your thoughts about creating one cube mesh and redrawing it would make the faces between two neighbouring cubes be drawn, Though not reinstantiating a class for each polygon could be the better solution.

And yes, performance is vertex dependant if you got optimized code on each draw call. I tested by making a new project with one mesh and add rectangles to it the size of 2 by 2 pixels, It got smoothly up to about 200 000 rectangles and about 28fps indicating that the amount of total meshes should be kept to a minimum. Though I am not sure if Codea handles rectangles this way with vertex points which 3D meshes do.

@Muffincoder - rectangles are just meshes behind the scenes.

I don’t think you can access OpenGL commands from Codea. Wrt what you are able to do, I was advised that the last two pages of this document contain what you can do in Codea.

@Muffincoder - rather than culling parts of blocks, have you tried simply drawing complete blocks on the outside layer and culling complete blocks within (ie only culling completely invisible blocks)? While this involves drawing more faces, you avoid all the work required to cull vertices, because you are basically just drawing one pre-made block mesh over and over, using a 3d table in memory to guide you as to what needs to be drawn or not.

@Ignatz Now after some coding I have reduced the total meshes to 6(1 per face) and the cube then calls the class containing these meshes and translates and draws the necessary faces in the position of the current block.

What’s surprising is that the same 10 by 10 by 10 with 3600 verts is still giving that 20 fps as before, no improvement nor any decrease in performance.(Note that this is without backface culling though)

I also found that not drawing any textures gave the same scene about 40 fps meaning the texture part in the drawing is quite heavy…

As for the culling I’m currently just going through all blocks and check if any of the neighbouring ‘slots’ is occupied by a block, so that part should not be any problem since it is ran once)

@muffincoder. Maybe you should just remove the faces that touch one another? They will never show up, so you are drawing them for nothing, but still they cost on the GPU.

I have no idea why but after some testing I concluded that increasing the block count decreases the ‘fpsdrop’. If I have about 100 blocks(10x10x10) and add about 21 blocks the fps drops by about 10 fps, but if I have a 20x20x20 I run at ~5fps and at 20x30x20 at ~4fps which is a increase in about 200 blocks(though alot get culled away but still) and a fpsdrop in about 1fps.

This seems quite strange to me…

@Jmv38 Yea, that’s the only type of culling I’m using atm.

Before my latest optimization which reduced all meshes to a total of 6 I also used my own backface culling which I haven’t adapted to the new type of face rendering yet.

@muffincoder the processing time is not proportionnal to fps but to 1/fps. So 1 fps drop from 30 fps is about 1/30s, while 1 fps dtop from 10 fps is about 1/10s… 3x times longer! This is what gets you confused.

But also the cps is affected by the total surface area of the blocks, not the amount.

@Jmv38 Oh, right! Thanks, I didn’t notice that :slight_smile:

I’m getting quite frustrated on my project not delivering the performance I expect it to, it’s not my first time that happens, in fact every project does just that :confused:

I can’t understand how some games/programs can run alot more complicated geometry and things happening at the same time on the same hardware I’m struggling on getting something alot simpler to run smoothly on.

Though I think alot of it is in writing optimal code for the platform you’re developing on…

@Coder That is not true, I tested with reducing the size of the blocks to one tenth of the original size and got the same fps as with the original.

@muffincoder.
try to run this program: it defines a fullscreen mesh with 1 rectangle. The fps is displayed on top of that.
tap the right part of the screen to add 1 fullscreen rectangle. Tap the left to decrease.

On my ipad air i can have 14 fullscreen rects until the fps drops at 50 fps. On ipad1 you would be 5x slower…

So you cannot, in any case, display more than 14 layers on top of another, and keep the fps good. 14 is not so bad.

So if you manage your core program to run at 50 hz, and can do the trick with 14 layers or less, then you have it!


--# Main
-- speedtest

-- Use this function to perform your initial setup
local floor = math.floor
local m
function setup()
    displayMode(FULLSCREEN)
    N=1
    meshUpdate(N)
    fps = 60
    fontSize(70)
    fill(0)
end
function meshUpdate(N)
    m = mesh()
    m.texture = readImage("Cargo Bot:Codea Icon")
    for i=1,N do
    dx,dy = math.random()*100-50 , math.random()*100-50
        m:addRect(WIDTH/2 + dx,HEIGHT/2+dy ,WIDTH,HEIGHT)
    end
end
-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    fps = 1/DeltaTime*0.02 + fps*0.98 
    m:draw()
    text(tostring(N).." screens = "..tostring(floor(fps+0.5)).."fps",WIDTH/2,HEIGHT/2)
end

function touched(t)
    if t.state~=BEGAN then return end
    if t.x > WIDTH/2 then N = N + 1 else N = N - 1 end
    if N<1 then N=1 end
    meshUpdate(N)
end

In my experience, multiple meshes is laggy. I would recommend have one mesh per chunk, or one giant mesh for each type of block’s faces. I would also try and generate the meshes so the vertices are only made for visible faces, which would require some math but shouldn’t be too hard. Also, OpenGL doesn’t automatically cull backfaces, so you should have this line at the top of your main() in your fragment shader:

if (!gl_FrontFacing) discard;

@Jmv38 Hmm, quite interesting… Well to start with I managed to get 16 screens at 50 fps on my ipad 4(not too sure if 3).

I tested with reducing the size of the screens which greatly increased the amount of rects I could get, which proves your point @Coder , I did not expect this I must say…

Well, this complicates everything…
But how in the world can the iPad run minecraft if each of the blocks there have their own faces? There has to be some very complicated reductions made there.

So in other words, if you need to have a large mesh on a iPad you will have to do some real aggressive reductions and only draw the bare minimum to be able to draw at good framerates, am I right?

Well, I haven’t done too much work on reducing mesh vertices and optimizations regarding that so I really need some advice where to start.

I do have an idea how I’d enable backface culling in the shader (Thanks @SkyTheCoder) but when it comes to having a cube with random holes in it, I have no idea how I’d reduce the vertices in that.

minecraft only draws a few layers (the good ones) i am sure. And if your objects are smaller on the screen, they will take less time to draw, so you can have more.
My program above gives you an estimate of your (best case) total screen budget: width x height x 16 is all the pixel you can draw at 50Hz.
You should keep it simple: no transparent cubes, or cubes with holes. When one builds something in minecraft, you mainly see 1 layer…
You could use the trick ignatz used for 3D touch functions: he draw the scene into an image A, the color of each face is the n° of the face. Then you know exactly which faces are visible. These ones, and only these ones (and their neighbours), should be drawn to the screen. the image A doesnt have to be full screen size. You must check regularly (every s?) which faces are visible.
This is just a suggestion, i am no expert in this field.