Mihai
Mihai

Reputation: 229

Drawing a lot of circles - optimization

I have an app in which when you press on the screen the app create a circle on that position and starting to grow until hit the max size and it's deleted.
How to optimize my code in order to draw a lot of circles?

    Iterator<CircleShape> it = mCircles.iterator();
    while (it.hasNext()) {
        CircleShape shape = it.next();
        if (shape.getScale().x <= shape.getMaxScale()) {
            shape.setScale(shape.getScale().x + mGrowSpeed * smoothedDeltaRealTime_ms);
            draw(shape);
        } else {
            it.remove();
        }
    }

The circles are created in the fragment shader by discarding the pixels I don't need:

void main()
{
    float d = distance(v_texCoord, vec2(0.5, 0.5));

    if (d > 0.5f)
            discard;

    gl_FragColor = uColor;
}

Here is a picture of my app:

enter image description here

Upvotes: 0

Views: 140

Answers (1)

Matic Oblak
Matic Oblak

Reputation: 16774

First you should try to analyze where you bottlenecks are. I assume the fragment shader is still quite heavy but can be optimized a bit.

You are comparing a distance which uses a root square that is generally slow. Try doing

vec2 vector = v_texCoord - vec2(0.5, 0.5);
if(vector.x*vector.x + vector.y*vector.y > 0.5*0.5) // or 0.25

Depth buffer may benefit you in this case if you are not using it. And if you are not using it I assume you draw the circles in order from oldest (widest) to newest. That means it will actually draw all of the fragments for each of the circles and then the new one will be redrawn on the old one. You can enable the depth buffer and as you increase the circle in size you may also put it further in z coordinate a bit. Now change the order of drawing from newest to oldest so those circles in the background will not be drawn where the previous circle was already shown. Do not forget to clear the depth buffer as well.

There are some other potential optimizations such as in your case you could probably just draw the stroke around the circle which represents the increase in size and not ever clear the color buffer. But that means actually creating vertices for drawing a stroke circle with defined width which would at least increase the load on the vertex part but severely decrease the rasterization and number of fragments drawn. In this approach you would need a depth buffer but once a new circle comes in you would also need to push back the current depth buffer... Could be done with a single screen redraw but this is quite a task to achieve correctly.

Another approach I can think of is actually having a uniform array for circle centers, colors and radiuses which may be fed to the fragment shader. Then in fragment shader iterate through the array and check which of the circle representation is actually the one you should draw at that specific pixel and use its color (if non are valid simply discard to keep the current background color). This means drawing only one single rectangle across the whole view. No depth buffer, no need to clear the color buffer. This might be heavy for the fragment shader but a number of fragments is severely decreased so it might give you quite a performance boost (or not).

Upvotes: 1

Related Questions