2d rotation help

Hi.

So a couple of weeks ago I asked Casey to explain how I could add rotation to the particles during a pre stream. Unfortunately I don't have a copy of the prestream and I am having difficulty in working out how to go about this.

He explained the basics of rotating a point in 2d which I thought at the time made sense however I am having trouble trying to work out how this would fit in with the existing handmade hero render code base especially with the concept of the x and y axis.

For example, when drawing the particles in handmade hero we use push bitmap. I wanted to added some kind of rotation argument to this call which I then used before calling draw bitmap to rotate the x axis.

1
2
Vector2 xAxis = { Cos(entry->Rot), Sin(entry->Rot) };
Vector2 yAxis = Perp(xAxis);


However this just rotates the particles as a whole system around the lower left of the player which I assume is the origin.

So my question is how can I can rotation into this so I can rotate each particle independently around the particle centre?

The way Casey explained it was that we need to move what we want to rotate to the origin, and then rotate it before translating it back I am having a hard time actually implementing this in code.

Edited by Jay on
You can actually watch the prestream on twitch. If you go to the video section on the handmade hero twitch account. If the stream is old enough, it could be expired already. You might want to check quickly.

- Connor
1
Vector2 result = Vector2((in.x-origin.x) * xaxis.x + (in.y-origin.y) * xaxis.y + origin.x, (in.x-origin.x) * yaxis.x + (in.y-origin.y) * yaxis.y + origin.y);

or in more lines:
1
2
3
Vector2 moved = in - origin;
Vector2 rotated = Vector2(in.x * xaxis.x + in.y * xaxis.y, in.x * yaxis.x + in.y * yaxis.y);
Vector2 result = rotated + origin;


You can reduce this into a single v3 * mat3 with some repositioning of values.
If you understand matrices a bit, for a 2d rotation, it is quite simple.

1
2
|x'| = | cos(angle)    sin(angle)|  |x|
|y'|   |-sin(angle)    cos(angle)|  |y|


This is rotation of the point (x, y) around the origin (0, 0), by an `angle`, its new position will be (x', y'). Or if you like:

1
2
x' =  cos(angle)*x + sin(angle)*y
y' = -sin(angle)*x + cos(angle)*y


If you want to rotate in place though. Translate the thing to be centred around the origin, rotate it, then translate to its original position.

Edited by Ginger Bill on
You can also download older prestream episodes with BitTorrent Sync. Or if you don't want to install it and you now exact day, I could put it on Google Drive and share with you. Just give me a day number.

Edited by Mārtiņš Možeiko on
Thanks mmozeiko. I can't remember exactly what day so I'll download BitTorrent Sync and see if I can find it.

From Bill's and ratchet's explanation I think I understand it - kind of.

I'm now rotating a rectangle around it's origin, however when I try and rotate around the center it isn't working correctly.

I have the below code to rotate the rectangle:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
float angle = gameState->TotalTime;

Vector2 origin = { 0.5f*static_cast<float>(drawBuffer->Width),
	0.5f*static_cast<float>(drawBuffer->Height) };

Vector2 xAxis = CreateVector2(100.0f, 0.0f);

xAxis = CreateVector2(xAxis.X * Cos(angle) - xAxis.Y * Sin(angle),
	xAxis.Y * Cos(angle) + xAxis.X * Sin(angle));

Vector2 yAxis = Perp(xAxis);

PushCoordinateSystem(
	renderGroup, 
	origin,
	xAxis,
	yAxis);


This works fine. Now if I understand correctly if I want to rotate around the rectangle center, I need to translate the rectangle. So my origin is the screen center and the x axis is 100, 0 with the y being 0, 100 - calculated using the Perp method. So the center of my rectangle should be 50, 50?

If I add this translation into my code it doesn't rotate correctly.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
float angle = gameState->TotalTime;

Vector2 origin = { 0.5f*static_cast<float>(drawBuffer->Width),
	0.5f*static_cast<float>(drawBuffer->Height) };

Vector2 xAxis = CreateVector2(100.0f, 0.0f);

xAxis -= CreateVector2(50.0f, 50.0f);

xAxis = CreateVector2(xAxis.X * Cos(angle) - xAxis.Y * Sin(angle),
	xAxis.Y * Cos(angle) + xAxis.X * Sin(angle));

xAxis += CreateVector2(50.0f, 50.0f);

Vector2 yAxis = Perp(xAxis);

PushCoord(
	renderGroup, 
	origin,
	xAxis,
	yAxis);


You can see I am subtracting the center of the rectangle from the x axis, rotating, and then adding it back in. You can see the results here.

The first gif is the rectangle rotating around the origin correctly and the second is my attempt at rotating around the center - which obviously is not working. What am I doing wrong?

Edited by Jay on
xAxis and yAxis vectors should not change at all. x/yAxis only indicate direction (and scale) to transform rectangle/bitmap. Direction and scale doesn't change if you translate point you are rotating about.

What you should be modifying is only origin variable. Haven't tried it, but it should be something like this:
1
2
3
4
Vector2 point = CreateVector2(50.0f, 50.0f); // this is what you'll be rotating around
Vector2 moved = origin - point;
Vector2 rotated = Vector2(moved.X * xAxis.X + moved.Y * xAxis.Y, moved.X * yAxis.X + moved.Y * yAxis.Y);
origin = rotated + point;
Ah ok. So once the xaxis and yaxis have been rotated, we just need to translate and rotate the origin. That makes sense.

However the code you have listed isn't working. It results is a massive value for rotated which will be drawing off screen Vector2 {45739.4375, 15521.0703}.

So I tried swapping your rotated calculation with the rotation code I was using for the xAxis which results coordinates that actually fit onto the buffer, but again it seems to be rotating around the screen 0, 0!

1
2
3
4
5
6
// After xaxis rotation and yaxis creation...
Vector2 point = CreateVector2(50.0f, 50.0f); // this is what you'll be rotating around
Vector2 moved = origin - point;
Vector2 rotated = CreateVector2(moved.X * Cos(angle) - moved.Y * Sin(angle),
    moved.Y * Cos(angle) + moved.X * Sin(angle));
origin = rotated + point;


See here.

I wasn't sure if this was because the origin is the center of the buffer (480, 270) but the axis and point are offset from the origin - since Casey's draw code adds the axis to the origin when drawing the rectangle.

Do you know what I am doing wrong?

Edited by Jay on
Oh yeah, x/yaxis used to calculate rotated variable should be normalized so only direction component is used, not scale.

Do you just need to rotate rectangle around its center? Then you can do only this:
1
origin = origin - 0.5f*xAxis - 0.5*yAxis;
OK thanks mmozeiko that did it!

Also I downloaded days 229, 230 and 231 as I think the question during the pre stream was asked on one of those days (230 I think) but the videos I downloaded didn't include the prestream and only started where the youtube video starts? Did I download the wrong video or did Casey just not provide the pre stream for those days?
You downloaded regular videos. Prestream videos are shared in different folder - BXX52F55Z5ZQNRQWRMTMESHCZWHPOQEOD