update() vs. draw()

Hi, I have a performance question regarding these 2 functions…

I’m wondering what is the benefit to having them separately? For some instances I can understand first updating everything in the update function, then rendering everything in the render function. But what about a system where there are thousands and thousands of particles. It seems to me that it doesn’t make sense to loop through 10000 particles updating them, and then loop through them again to render them. Obviously the update function for such an object wouldn’t be heavy, so I’m quite tempted to do just one loop in which I update and render them - probably in the draw loop. But I was wondering whether these two distinct functions - update() & draw() - are simply there to aid thinking and structuring of the app, and draw() is just called straight after update(); or they are somehow internally handled differently?
P.S. I tried looking in the source, but couldn’t find it…

Cheers,

Memo.

1 Like

hi –

thanks! the motivation is pretty straightforward -

a) often times, the updating of the world is different then drawing, and you optimize them differently.

b) it makes sense in terms of debugging to separate them out to non visual and visual stuff that happens per frame. then is easier to spot errors.

c) there is no penalty to doing everything in draw if you like the way it’s done in processing, for example

d) glut does this - having an idle callback and a draw callback, so it made sense to take what they do and bring to the app level.

if it bothers you, just do everything you want to in draw, there is not penalty.

does that help?

best!
zach

2 Likes

Hi zach, thanks for the quick reply - was very helpful. It doesn’t bother me that there’s two different functions :stuck_out_tongue: I was just wondering whether it would be beneficial in any way to separate iterating through a few thousand particles into two functions as well… but it seems by your answer for those kind of cases its probably faster to just do it one loop…
cheers,

Separating your drawing code from your update code can also help the performance of your app.

I once profiled one of my GL apps to see what was faster, to update the frame data and then draw (which would naturally be the first thing you would think of) or to draw the last frame’s data and then update the current frame.

It turns out that the latter was faster than the former, because OpenGL drawing occurs asynchronously. As soon as the app code under draw() calls glutSwapBuffers(), the function returns almost immediately and your code can follow happily along updating the data for the next frame while drawing is being done in the background by the GL driver. As soon as you issue any other GL function call, that call will block until all the previous drawing is done.

For some apps this will not be important if you take care to do all your updates at the top of the draw() function, but if you mix drawing code with update code in the same function your performance will probably suffer.

But, as with all the advice about optimization, you should always measure to see if this is true for your app.

Cheers,
P.

For me a big reason for separating the update/draw logic is that typically in games you want your update to be a fixed time step, whereas you just want to make as many draw calls as you can between each game tick (update). This means that if the frame rate changes the game logic still occurs at the same frequency so a movement of one unit each update() tick is the same regardless of framerate and you dont need any logic in your update ticks to check how much actual time has passed since the last update call and adjust things accordingly. (typically this is coupled with storing the last frame + current frame transforms and interpolating between these in the draw() method based on the elapsed time).

Is the behaviour in OF like this? Or do both functions just get called as often as possible (assuming vsync is disabled). I guess if this is not the case it can be simulated by doing nothing in the update() method unless the desired timestep has elapsed. Although this will probably also require a bit of logic in the draw() method to make sure that making another draw call isn’t going to result in the next update() tick being called late…

I’m just looking for answers about how much of this might already be covered by the API or if its left down to the user.

Cheers!