# Regulating how much to draw based on how much was drawn last frame

[Edit: I found an answer - see below]

I have a 3D game world on an iPhone (limited graphics speed), and I'm already regulating whether I draw each shape on the screen based on it's size and distance from the camera. Something like...

if (how_big_it_looks_from_the_camera > constant) then draw


What I want to do now is also take into account how many shapes are being drawn, so that in busier areas of the game world I can draw less than I otherwise would.

I tried to do this by dividing how_big_it_looks by the number of shapes that were drawn last frame (well, the square root of this but I'm simplifying - the problem is the same).

if (how_big_it_looks / shapes_drawn > constant2) then draw


But the check happens at the level of objects which represent many drawn shapes, and if an object containing many shapes is switched on, it increases shapes_drawn lots and switches itself back off the next frame. It flickers on and off.

I tried keeping a kind of weighted average of previous values, by each frame doing something like shapes_drawn_recently = 0.9 * shapes_drawn_recently + 0.1 * shapes_just_drawn, but of course it only slows the flickering down because of the nature of the feedback loop.

Is there a good way of solving this?

My project is in Objective-C, but a general algorithm or pseudo-code is good too.

Thanks.

Edit: Please, I'm not asking for general advice on rendering performance. I need an answer to the specific question of how to take the shapes drawn in previous frames into account without getting flickering.

That's what Z buffering is for. Once you cull outside your frustum, and apply LoD to further-away objects, then you draw closest first. This will ensure that the graphics hardware can easily reject pixels that it doesn't need to draw.

Ultimately, if the shapes are part of your scene, then you can't not draw them and still get a correct image. You may try decomposing the resulting frames and see how many you actually needed.

• If I only drew depending on distance and not size, tiny objects will get drawn when huge but slightly further away ones don't - it just doesn't work. I certainly can't draw everything, or slow devices run at about 1fps because they're drawing small far-away things that really don't matter and are little more than dots. – Mike Howard Jun 25 '11 at 14:54
• To avoid this problem with huge objects create an extremely low LOD version and use a 2nd render loop with a deeper distance to pick out these important objects outside the smaller render distance for everyone else. – Patrick Hughes Jun 25 '11 at 17:30
• @Mike Howard: You draw on distance and size. Size first. – DeadMG Jun 27 '11 at 19:51

First order of business is that you've discovered that it's best to measure before optimizing =) So now you know that it's object count that's killing your speed and not screen real estate.

Measure how many drawn objects your rendering can handle at the needed speed.

Now we need to test drawing distance, create a maximum distance at which you will draw objects and stress test your environment at different distance settings by running around and catching object counts. From this you will come up with a good distance to clip objects being drawn.

Now your basic render loop becomes one of throwing away any object that's farther away than that distance.

At this point most studios will pass that information along to the artists and designers so that they can make their data fit within the drawing parameters you've laid down.

Tip 1 is do do distance in units squared, this will avoid a sqrt() on every object every frame.

• I already did all that to come up with what I'm already doing, but now I need to expand on this because some areas are more densely populated with shapes than others. Re tip 1; I do the square root only once per frame, every object reads the result. – Mike Howard Jun 25 '11 at 18:00
• Sort the objects to render by distance. Start with the nearest, count how many and stop when you reach your limit? – Patrick Hughes Jun 25 '11 at 21:48
• It's OK, I found the answer :) – Mike Howard Jun 25 '11 at 23:54

Make each object remember whether it was drawn or not the previous frame.

It it was, be more lenient with it when deciding whether it should be drawn this frame than you would be if it hadn't been drawn the last frame. So...

if (how_big_it_looks * (1.2 if drawn last frame, 1.0 if not) / shapes_drawn > constant2) then draw


Voila, no flicker. Can't believe I didn't think of this sooner.