Page 1 of 1

Optimisation of drawing 3d

Posted: Sun Feb 11, 2024 4:06 pm
by prostokiriuha
hello!

so, in general my question is very basic: what exactly i should and shouldn't do in draw function?

but here more spcific info.

i making a very simple voxel 3d game and now working on particles and billboards, and im using instancing to draw one simple square bunch of times at different positions.

initialisation, called once:

Code: Select all

    local mesh3d = require ('modules/mesh3d')
    state.PARTICLE_MESH = mesh3d.newTexturedParticleMesh ()

    state.MAX_PARTICLE_COUNT = 1000
    local particle_vertices = {}
    for i = 1, state.MAX_PARTICLE_COUNT do
        particle_vertices [i] = { 0, 0, 0, 0, 0 }
    end

    state.PARTICLE_INSTANCES_MESH = love.graphics.newMesh (
        {
            { 'InstancePosition', 'float', 3 },
            { 'InstanceTexIndex', 'float', 1 },
            { 'InstanceScale', 'float', 1 }
        },
        particle_vertices,
        'points',
        'dynamic'
    )
    state.PARTICLE_MESH:attachAttribute ('InstancePosition', state.PARTICLE_INSTANCES_MESH, 'perinstance')
    state.PARTICLE_MESH:attachAttribute ('InstanceTexIndex', state.PARTICLE_INSTANCES_MESH, 'perinstance')
    state.PARTICLE_MESH:attachAttribute ('InstanceScale', state.PARTICLE_INSTANCES_MESH, 'perinstance')

    local particle3d = require ('modules/particle3d')
    state.PARTICLE_COUNT = 0
    state.MAX_PARTICLE_COUNT = 1000
    state.PARTICLE_DATASET = particle3d.newDataset (state.MAX_PARTICLE_COUNT)
    state.PARTICLE_SYSTEM = particle3d.newSystem (state.PARTICLE_DATASET)
update, each frame:

Code: Select all

    local vertices_data = particle3d.update (state.PARTICLE_SYSTEM, dt)
    state.PARTICLE_COUNT = #vertices_data
    if state.PARTICLE_COUNT > 0 then
        state.PARTICLE_INSTANCES_MESH:setVertices (vertices_data)
    end
draw, each frame:

Code: Select all

    love.graphics.drawInstanced (state.PARTICLE_MESH, state.PARTICLE_COUNT)
and similar logic for billboards. aaand here is where i got an issue.

all data for each particle stored as single table of values where each N values related to one particle, so there is a table witn N * MAX_COUNT values and another table of pointers - indices of 'alive' particles. so, yeah, its a circular array.
this works fine and naturally prevents an issue of overflowing - new particles just override old ones, who cares, its just a visual thing.

but purpose of billboards are different, its more like flat model for entities, like fire, emm... "chunk"? so its just an unlimited table and there is no lifetime, i create and remove them when create/remove entities.

and then i tried to spawn heck-a-lot fire entities and got en error: Too many vertices (expected at most 1000, got 1125)

so, not surprised, my instance mesh can handle only 1000 of them, its current max count, and i need to fix this.

first of all i can just increase max count of items, but even 1000 should be enough for 99.99% of cases. so, all this memory will be reserved by mesh and allmost never used, am i correct? and also this only delay issue, but not prevent.

next obvious solution is just draw all in cycle by 1000 or less pieces until all drawn.

but to do this i need make both update and draw in each cicle iteration, not big deal, and here where i start ask myself some dumb questions:

what calculations should i do in update, what is better to keep in draw, and is there any differences at all?

also, im not good in glsh or shaders at all, so maybe there are some things i need to know about mesh instancing that is not in love2d wiki?

im doing some matrix multiplications just before sending them in shaders, but refreshing particle/billboard data is slightly more time consuming thing, esp if there would be quite a lot of them, so... should i be worried about it? i dont know, is there any 'rules' or some, i just doing things where i think it suppose to be, and its kinda messy now.

i know basic rules of optimisation - create less tables, use more local variables then table props, and so on, but some fps drops already happens, not much, but if i will not think about it now i could have "funny" time later.

thx.

Re: Optimisation of drawing 3d

Posted: Mon Feb 12, 2024 2:54 pm
by pgimeno
I can only reply to this question:
prostokiriuha wrote: Sun Feb 11, 2024 4:06 pm what calculations should i do in update, what is better to keep in draw, and is there any differences at all?
I'm not fully sure what you mean. love.update and love.draw are executed one after the other, in that order. There's no difference other than the fact that you can't draw to the screen in love.update, because the screen is cleared between love.update and love.draw, and the fact that love.update receives dt but love.draw doesn't. You could in theory grab dt in a variable in love.update, use love.draw for your game logic and graphics, and not use love.update for anything else, although that would not be very clean of course. It's a question of organization more than anything else: love.update is there for processing the logic of your game, and love.draw to graphically draw the result to the screen; it's recommended to use them like that but you don't have to.

But if you mean what to do in Lua (love.update/love.draw) vs. what to do in shaders (via love.graphics.draw) then the answer is different. Some calculations like matrix transformations that can be done in shaders, probably should, as they are typically faster.