fredoverflow
fredoverflow

Reputation: 263320

anti-aliased pixel rendering

I'm trying to implement anti-aliased pixel rendering. My basic idea is to render 4 pixels instead of 1, and give each "real" pixel a weight based on its distance to the "virtual" pixel:

void put_aa_pixel(double x, double y)
{
    int x0 = int(x);
    int x1 = x0 + 1;
    int y0 = int(y);
    int y1 = y0 + 1;

    double weight_x1 = x - x0;
    double weight_x0 = 1 - weight_x1;
    double weight_y1 = y - y0;
    double weight_y0 = 1 - weight_x1;

    put_pixel(x0, y0, int((weight_x0 * weight_y0) * 255));
    put_pixel(x1, y0, int((weight_x1 * weight_y0) * 255));
    put_pixel(x0, y1, int((weight_x0 * weight_y1) * 255));
    put_pixel(x1, y1, int((weight_x1 * weight_y1) * 255));
}

Multiplying the x and y weights gives me the overlapping area of the virtual pixel inside each real pixel. I naively assumed this would give me a perfect anti-aliasing effect, but the moving pixels inside my test program just display an aweful flicker. It looks much worse then simple pixels without any anti-aliasing.

However, when I switch from multiplication to addition, it looks much better:

    put_pixel(x0, y0, int((weight_x0 + weight_y0) * 127.5));
    put_pixel(x1, y0, int((weight_x1 + weight_y0) * 127.5));
    put_pixel(x0, y1, int((weight_x0 + weight_y1) * 127.5));
    put_pixel(x1, y1, int((weight_x1 + weight_y1) * 127.5));

Adding the weights doesn't seem to have any geometric significance. So why does this work better? What's wrong with the first version? And is there an even better approach?

Upvotes: 3

Views: 3821

Answers (2)

fredoverflow
fredoverflow

Reputation: 263320

There was a bug lurking in my code for half a year:

double weight_x1 = x - x0;
double weight_x0 = 1 - weight_x1;
double weight_y1 = y - y0;
double weight_y0 = 1 - weight_x1;   // BUG

Can you see the bug? Yes, it's a classic copy and paste error:

double weight_y0 = 1 - weight_y1;   // FIXED

After fixing the bug, the original multiplication approach looks very nice.

Upvotes: 4

lapk
lapk

Reputation: 3918

As requested :)

Intuitively: your x and y weights express distance along axis from virtual to real pixel. So, the actual distance is sqrt(w_x^2 + w_y^2). Explains why sum works better - it's way closer to this form than multiplication.

Upvotes: 4

Related Questions