Jagged edges on rotated sprites

When rotating simple sprites in HTML5 I always get jagged edges.

Eg, this simple example produces the output shown below.

package;

import openfl.display.Sprite;

class Main extends Sprite
{
    public function new()
    {
        super();

        var sprite = new Sprite();
        sprite.graphics.beginFill(0xCC0000);
        sprite.graphics.drawRect(0, 0, 200, 200);
        sprite.rotation = 2;
        sprite.width = 200;
        sprite.height = 200;
        sprite.x = 100;
        sprite.y = 100;

        trace('adding sprite');
        this.addChild(sprite);

        var sprite2 = new Sprite();
        sprite2.graphics.beginFill(0x00CC00);
        sprite2.graphics.drawCircle(100, 100, 100);
        sprite2.width = 200;
        sprite2.height = 200;
        sprite2.x = 400;
        sprite2.y = 100;

        this.addChild(sprite2);
    }
}

Strangely the edges of the circle are smooth but not the rotated shape.

Is there a setting I can set to get the rectangle to render smoothly?

Yes, this artifact, sometimes referred to as “jaggies” occurs when a straight line is skewed. A circle is perfectly round so there are no straight angles to skew. The rendering display is made up of a grid of pixels which means that a perfectly straight line is only possible when pixels are drawn exactly horizontally or vertically. The exception to this is perhaps vector graphics where smoothing occurs to blend in these jagged artifacts so that they look clean at any angle and at any scale.

Ok, with that said, there are a few things you could actually do here to make the line appear smoother when rotating geometry with straight lines. Most notably, you can take advantage of computationally heavy anti-aliasing algorithms. Fortunately, openfl exposes AA in the project xml. To reap the benefits of this, you simply need to add <window antialiasing="16" />. The value can be between 0 and 16, with 16 being the most expensive for your hardware to perform. Additionally, you can smooth out rough edges with a built in filter like blur or glow, depending on your use case, although this is only helpful in limited situations.

But wait a minute! Doesn’t the graphics API support drawing vector graphics and shouldn’t this resolve the problem? Well the answer is sort of complicated and its a Yes and a No. Let me explain:

By default OpenFL uses hardware rendering if your system meets the requirements. Let me just start out by saying that the GPU is not especially good at rendering Vector graphics and in fact, in OpenFL, it doesn’t. Even when utilizing GPU hardware acceleration in OpenFL, we still fall back to software rendering to draw initial Vector graphics. When displayed, these are still hardware accelerated because as soon as they’re drawn by the CPU, they are piped to the GPU as a static texture. Therefor, when you rotate the shape, you experience jagged edges that you wouldn’t normally experience if you were using the software rendered in totality. SO - with that said, another way to resolve this problem is to simply turn off hardware accelerated rendering in your project XML via <window hardware="false" />.

I hope this not only helps you achieve your desired affect, but also understand why you experienced the undesirable one to begin with.

Cheers!

1 Like

Thanks for the super detailed answer. I wish things like setting antialiasing were included in the documentation!

Increasing the antialiasing improved things and turning off hardware acceleration “fixed” things as you suggested it would. Unfortunately turning off hardware acceleration broke other parts of my app so I can’t use that for now. Inset DropShadows for example seem to require hardware acceleration turned on.

To clarify that I understood you correctly, are you saying that the rectangle if first drawn in software, then uploaded to the GPU and then the rotation is being applied by the GPU?

I’m still not sure I understand why OpenGL can’t draw something like this cleanly. Looking at this site for example:

I can see lots of crisp lines and I’m assuming they’re using hardware acceleration. Am I missing something?

AA I would assume - This is what it looks like when I turn off AA in my browser.

You might even be able to force the software renderer to redraw the vector when its rotated, although this will be slow, but I’m not sure about this.

Thanks,
I found this example of using WebGL2 that has a rotating square that looks very smooth. I’m trying to dig into it now to see what the difference is but I’m completely new to the WebGL.

var sprite = new Sprite();		
        sprite.graphics.beginFill(0xCC0000);
        sprite.graphics.drawRect(-100, -100, 200, 200);
        sprite.rotation = 0;
        sprite.width = 200;
        sprite.height = 200;
        sprite.x = 200;
        sprite.y = 200;
		
		addChild(sprite);
		
		addEventListener(Event.ENTER_FRAME, function(e:Event){
			sprite.rotation ++;
		});

Well possibly because the edges dont look as jagged in motion. Try this.

In the demo you linked, here is where the gl context is populated. AA is enabled by default. In order to disable it you pass the {antialias: false} parameter. var context = canvas.getContext('webgl', {antialias: false});

You’re right. Once it’s animated the jagged edges aren’t nearly as apparent. Thanks so much for your help.