Wednesday, 5 November 2008

Anti-aliasing in Processing

Over the last few days, I have started to play with Processing, primarily to get a feel for its capabilities.

On the whole, I am impressed by the simplicity. It took me less than a minute to produce some (albeit simple) graphics. The lack of the normal "clutter" associated with most programming languages is a big plus for those that just want to produce images.

What I am less impressed with are some of the idiosyncrasies. Two in particular revolve around the functions loop()/noLoop(), and smooth()/noSmooth().

The loop()/noLoop() functions control whether draw() should be called once, or continually. By default, Processing is set to loop(). This is fine for animated graphics, and applications with some user interaction (such as through keyboard or mouse events), but for simple static graphics it has two downsides.

The first is on machine performance. A quick look at a performance meter shows that the continual redrawing has its cost. For simple applications, this may hardly be noticeable, but an application that involves any disk access (e.g. image reading) or complicated calculations is likely to noticeably impact machine performance. It is therefore important to keep any operations that only need to be performed once in the setup() function.

The second downside is image quality, and this is where the smooth()/noSmooth() functions come in. The smooth()/noSmooth() functions control anti-aliasing. This is important in computer graphics. We have moved on from the primitive computer graphics of the early 1980s home computers such as the Sinclair ZX Spectrum, and yet the default in Processing is set to have the anti-aliasing switched off with an implied call to noSmooth().

To me, the default settings for these two functions are wrong. Anybody new to Processing is going to start with simple, static images. They will be looking at issues like ease of use, and image quality. Surely it would be better to default to noLoop() and smooth(), rather than loop() and noSmooth() as is currently the case?

This isn't just an academic argument either. As I will show below, these settings have a very visible effect of results.

Consider the following code. The intent is to draw a black circle on a white background:
void setup(){
size(140, 140);

background(255); // White
stroke(0); // Black

strokeWeight(10);
ellipseMode(CENTER);

smooth() or noSmooth();
loop() or noLoop();
}

void draw(){
ellipse(70, 70, 120, 120);
}
It will be noted that this code is not entirely syntactically correct. The smooth() or noSmooth() and loop() or noLoop() lines give 4 variations. The table below shows the result of these variations:



noSmooth()smooth()
noLoop()
Suggested default settings
loop()
Default settings

The visual differences in image quality are obvious. A check sum compare of both of the unsmoothed images shows that they are byte-for-byte identical. The same is not true for the smoothed images.

I don't understand why the developers of Processing choose these defaults, and nor do I understand why the smoothed image quality is reduced when looping, unless there is some deliberate throttling of the algorithm to reduce processor overhead.

So, to recap, if you are drawing static images, I recommend the following skeleton code:
void setup(){
size(x, y);
smooth();
noLoop();
}

void draw(){
}