1

Suppose you have a rectangle centered at point (0, 0) and now I want to rotate it such that it is facing the point (100, 100), how would I do this purely with matrix math?

To give some more specifics I am using javascript and canvas and I may have something like this:

var position = {x : 0, y: 0 };
var destination = { x : 100, y: 100 };
var transform = Matrix.identity();

this.update = function(state) {

  // update transform to rotate to face destination

};

this.draw = function(ctx) {
  ctx.save();
  ctx.transform(transform); // a helper that just calls setTransform()      
  ctx.beginPath();
  ctx.rect(-5, -5, 10, 10);
  ctx.fillStyle = 'Blue';
  ctx.fill();
  ctx.lineWidth = 2;
  ctx.stroke();
  ctx.restore();
}

Feel free to assume any matrix function you need is available.

  • Not sure what you mean by facing since you are doing this in 2d. Do you mean you want a corner to point to 10,10, or you want to skew the rectangle in a way that 0,0 on the rect is facing 10,10? Assuming z is locked at 0 as well then? – Loktar Mar 30 '12 at 16:19
  • Whatever way is eaiser to explain I think. I was picturing the identity matrix and identity vector to essentially be the direction the rectangle was "facing" in the start state... but basically I want the top side of the rectangle to be considered the direction it is facing. – justin.m.chase Mar 30 '12 at 16:27
  • Sounds like you need to construct a lookat matrix considering the rectangle to be the camera. – chaosTechnician Mar 30 '12 at 16:32
  • Oh yes that looks good! I'm assuming the second part of the formula is the new matrix? The formatting there is pretty unfortunate. – justin.m.chase Mar 30 '12 at 17:09
  • Hmm, now how the heck would I translate that into 2d? – justin.m.chase Mar 30 '12 at 17:20
  • lookAt() uses cross product, which isn't defined for 2 dimensions. – notlesh Mar 30 '12 at 18:00
  • http://www.euclideanspace.com/maths/algebra/vectors/lookat/index.htm maybe that will help you – notlesh Mar 30 '12 at 18:04
  • 1
    Justin, your question is not a 2D problem. You have a facing-vector that does not lie in the 2D plane, it points out of it, so you already deal with 3D. Given the 2D constraint, the entire question does not make much sense as it stands, as @Loktar already mentioned. Its actually a 3D problem, so welcome to 3D :) – Maik Semder Mar 30 '12 at 18:23
  • It probably doesn't matter that lookAt is a 3D function, you just feed it 0s for the 3rd dimension and it should give a useful result. After all, the 2D vector space is just a plane of the 3D vector space. Of course the 3D function is more complicated than what is needed for 2D, but once you know that part of the input is always going to be 0 you can reduce it pretty heavily. – aaaaaaaaaaaa Mar 30 '12 at 18:25
  • @eBusiness, and you'd want to feed an up vector perpendicular to the two basis vectors for your plane, namely (0, 1, 0) or (0, -1, 0) depending on whether you have eyes in the back of your head :) – notlesh Mar 30 '12 at 18:47
  • Thanks for your patience everyone. I'm realizing I'm thinking about things wrong. I'm getting closer. – justin.m.chase Mar 30 '12 at 19:01
  • This may make me sound foolish but one revelation that I had while working on this was that position is not needed at all... the position information is encoded into the matrix. That was messing me up. – justin.m.chase Mar 30 '12 at 20:21

2 Answers2

2

If I got my maths right in order to rotate from facing A to facing B you can use the matrix:

 [ A1*B1+A2*B2   A2*B1-A1*B2 ]
 [ A1*B2-A2*B1   A1*B1+A2*B2 ]
_______________________________

            |A|*|B|
aaaaaaaaaaaa
  • 8,892
  • 1
  • 21
  • 35
2

Here's my first take on it:

Assuming you want the top edge of the rectangle to be the edge that sets the "facing direction" as per your comment, and that would be considered your identity direction (0, -1) or zero angle in 'JustinSpace', rotating the rect so that that edge faces 100,100 would in effect be a 135 degree rotation clockwise. Most Math libraries think of 1,0 as being the identity direction (or 0 angle) requiring a 90 deg shift of the angle to place it into 'JustinSpace'.

A matrix that rotates something 135 deg clockwise on a 2d XY plane looks like this:

float angle = Math.Atan2(100,100) + Math.Atan2(-1, 0); // 45 deg + 90 deg

//RH coordinate Row Major system
Matrix m = Matrix.Identity();
m.11 = m.22 = cos(angle);
m.12 = sin(angle);
m.21 = -sin(angle);

//for column major
//m.Transpose()

If eBusiness' answer works however, I would use it as linear algebra is almost always favorable over trig in game dev.

Steve H
  • 5,089
  • 19
  • 21
  • Are you sure that angle shouldn't be Math.Atan2(100,100) - Math.Atan2(-1, 0) = 45 deg - 180 deg = -135 deg = 135 deg clockwise? – aaaaaaaaaaaa Mar 30 '12 at 19:50
  • very possible, should be tried both ways to make sure... thanks. – Steve H Mar 30 '12 at 20:17
  • Thanks a ton, this was almost exactly what I needed. I just submitted an edit to your answer with the actually working function for future reference. I will accept this as the answer. – justin.m.chase Mar 30 '12 at 20:18
  • @eBusiness, Actually, not sure where you get the 180 from. Atan2(-1,0) returns the angle of vector 0,-1. Atan2 takes the Y component as the first arg... – Steve H Mar 30 '12 at 20:19
  • @Justin, try it with a rect where w != h just to make sure it is rotating the correct direction you want. If I have the rotation going ccw instead of cw, a square like your sample would mask that prob. – Steve H Mar 30 '12 at 20:24
  • Forgot that about Atan2, then it's 45 deg - (-90 deg) = 135 deg = 135 deg counterclockwise. And I am by the way pretty sure that you need to subtract one from the other, but it's easy to switch them around. Luckily that is usually an easy bug to track. – aaaaaaaaaaaa Mar 30 '12 at 20:29
  • Yeah, you could be right, I often think and compose conceptually then iron out the details while debugging. – Steve H Mar 30 '12 at 20:34
  • In reality I'm using a rectangle, it looks good. Also a friend of mine showed me a way to do it without using trig. It's basically like this: var p = target.subtract(new Point(x, y)).normal(); then the matrix is: [p.y, -p.x, p.x, p.y, x, y] – justin.m.chase Mar 30 '12 at 20:59
  • @justin.m.chase That is the specific case of my answer where the initial rotation is always (0,1). – aaaaaaaaaaaa Mar 31 '12 at 07:22