Drawing Anti-Aliased Circles in OpenGL on the iPhone/iPad
March 16th 2011
During the development of Corrino Software's iPhone/iPad game Pizarro, I ran into problems with some of the inherent limitations of the OpenGL ES implementation in iOS. The iOS devices don't support anti-aliasing for polygons or for lines wider than 1 pixel. I knew Pizarro would require drawing primitives in OpenGL, as opposed to sprites, both for performance and memory reasons. However, without antialiasing, these primitives would be ugly and the lines jagged.
I was off to several false starts. Initially, I tried drawing the circles with CoreGraphics and converting them to OpenGL textures, but the performance was dreadful and brought older devices to their knees. It seemed ridiculous overhead for something that should be so simple: drawing an antialiased circle. After much trial and error, I was ultimately able to overcome -- or, some might say, circumvent -- these problems, and so thought I'd share with the world the clever trick I used.
To start off, it's worth saying a few things about Pizarro, the game I was developing. Pizarro is a very simple game. One or more red balls bounce around in a box. The objective of the game is to touch the screen and hold to create expanding circles to cover the area without having these circles collide with the bouncing balls. When 80% of the surface area has been covered, you advance to the next level. Obviously, the majority of the in-game graphics were circles. It was essential that they look good. The appearance and feel of the game itself depended on it.
As you can see from the screenshot of the final version of Pizarro above, the circles look great and are beautifully antialiased. How did I get them antialiased on iOS, which as of writing has an implementation of OpenGL ES that doesn't support antialiasing for polygons (and by extension, circles)?
I was developing Pizarro for iOS using the excellent, open-source cocos2d
engine. The version of Cocos2D I was using, 0.99.5, included some built-in functions for drawing primitives,
including a function called
ccDrawCircle in the
CCDrawingPrimitives class. All the
primitives functions in the engine only drew the shapes as outlines. I wanted filled circles, not outlines, so
I created a duplicate of the
ccDrawCircle function, which I called
only one line was changed:
<div class="codeblock"> <pre>glDrawArrays(GL_LINE_STRIP, 0, segs+additionalSegment);</pre> </div> <p>became</p> <div class="codeblock"> <pre>glDrawArrays(GL_TRIANGLE_FAN, 0, segs+additionalSegment);</pre> </div>
b2d294b366c501cf9a0316d2f25e02a1 774b7b36c93b6999e4263c09f45781d5 b0ab4b60a0849b0d1158b74f3f89b50c 0d6c01caea330d9a13216a8a955a821c
glEnable(GL_POINT_SMOOTH); glVertexPointer(2, GL_FLOAT, 0, &p); glDrawArrays(GL_POINTS, 0, 1);
<div class="codeblock"> <pre>glPointSize(circle.size);