donderdag 22 oktober 2015

HTML5 Canvas, context setTransform explained from skew, rotate, scale and translate

Things are sometimes a little skewed in the world of Adobe. And if you use Adobe products to produce game graphics (like animations) that you'll use on a canvas, (and you don't want the BULK of createJS) you run into trouble quite easily.

So I needed to understand how to get THIS in terms of the canvas context.setTransform() function.



If you want to skip the explanation, my working example is at the bottom of the page.

What are matrices again?

The canvas setTransform function takes a transformation matrix: [[ace],[bdf],[001]]
Now I've had matrices in school for a semester and later dabbled in OpenGL matrices, which are a bit more complicated than 2D matrices, but I always had trouble explaining to myself what happened in either 2D or 3D. So time for some experimentation.

void ctx.setTransform(a, b, c, d, e, f);

They say, it helps to think about these parameters as:
a Horizontal scaling.
b Horizontal skewing.
c Vertical skewing.
d Vertical scaling.
e Horizontal moving.
f Vertical moving.

It helps. If only it wasn't a gross over-simplification.
Because when you start to experiment for real, you'll see the truth is a bit different.
The above is only true, AS LONG AS you do not ROTATE.
But you should be able to set skewing even when rotated, just like that.. That's the beauty of using matrices, I remember that much from school.

So I wrote this little bit of code to experiment and show you (and myself) how simple or difficult it REALLY is to get the results you expect..

If you want to rotate, make sure the angle for x and y are the same. If you want to skew, make the angles for x and y NOT the same. The amount by which they differ is the skewing.

You can visualise this as setting the rotation for the x axis and the rotation for the y axis seperately. Just like you would when you do a non proportional scale and set the length of the X axis and Y axis seperately.
Anyway, it helps me to understand those pesky matrices better and I wanted to clarify what I found to you. So here is the code-breakdown:
It basically sets up a interval and a canvas. Then in the move function draws a stroked rectangle repeatedly from -50 to +50 in x and y.
But before it does that it sets the context transform according to the frame-counter.
The first 45 frames it just rotates and moves a scaled version of the rectangle.
After the first 45 frames it skewes it in the y-direction as well..

The first 45 frames you might achieve the same by doing ctx.translate, ctx.scale and ctx.rotate.
But after 45 frames, you really see the power of setTransform.
Also note, that ctx.translate etc are cumulative and you need to save and restore your context.
With setTransform, you don't. Just set it back to the zero-matrix when you are done and want to draw normally again: ctx.setTransform(1,0,0,1,0,0);

Anyway, here is my code and it's execution:

var counter=0;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
setInterval(move,25);

function move()
{
    counter++;
    var anglex=45+counter;
    var angley=45+counter;
    if(counter>45) angley=80+counter;
    var scalex=0.5;
    var scaley=0.7;
    var origx=0+counter*2;
    var origy=100;
    var rx=Math.PI*anglex/180;
    var ry=Math.PI*angley/180;
    ctx.setTransform(scalex*Math.cos(rx),scalex*Math.sin(rx),-scaley*Math.sin(ry),scaley*Math.cos(ry),origx,origy);
    ctx.strokeRect(-50,-50,100,100);
}





About skewing

Now skew or slant is a bit of a wrongly used term normally. Speaking Mathematically we mean something else, than what most people know from Adobe's programs.

So I made another example, to mean more what most people THINK skewX and skewY mean: namely skewx and skewy are inverted: If you want the code for that one, just press the edit in fiddle button in the top right hand.
I'm not going to explain that code here, I've kept it very simple.

It's still not exactly how skew works with Adobe, because at low skews in the X the height of the object stays the same with for instance Flash. If you go skew things a lot, it will just give you very unexpected results. This is why: Adobe compensates the length of the axis that is not skewed to make it keep approximately the same height:
I fiddled around a little bit more and ended up with this:

If you are used to adobe products, this will give you something quite a kin to the skewing that you know and love. It's not an exact -pixel perfect- match, mind you, but quite good at low settings (-45/45 degrees) and that's good enough for me right now.


Original article I found (and I found was wrong:)
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform


Geen opmerkingen:

Een reactie posten