- Home /
What's the most efficient way to rotate a Vector2 of a certain angle around the axis orthogonal to the plane they describe?
Hi UnityAnswers Community,
I am using a Vector2 to store input information(a gesture direction), but I also need to calibrate it (it's an external device) by rotating the input direction around the axis orthogonal to the plane they lay on.
To help you visualize the code:
Vector2 normalizedDirection;
float calibrationAmount; //amount of rotation
I searched for a native function to rotate a vector2 but didn't find it. A Google search didn't help either.
Since the code should also run on mobile, what's the most efficient way to do it in C# without using external DLLs? Should I manually do the math?
At the moment I'm using this code:
float _x = normalizedDirection.x;
float _y = normalizedDirection.y;
float _angle = calibrationAmount * Mathf.Deg2Rad;
float _cos = Mathf.Cos(_angle);
float _sin = Mathf.Sin (_angle);
float _x2 = _x * _cos - _y * _sin;
float _y2 = _x * _sin + _y * _cos;
return new Vector2(_x2, _y2);
But I'm not sure it's the best way to do it. It seems overly complicated for a simple rotation on the origin that should be implemented natively.
Do you know a simpler, computationally fastest way to do it?
Thanks for your time :)
Answer by DDP · Jun 25, 2014 at 04:12 PM
What about using an extension method?
using UnityEngine;
public static class Vector2Extension {
public static Vector2 Rotate(this Vector2 v, float degrees) {
float sin = Mathf.Sin(degrees * Mathf.Deg2Rad);
float cos = Mathf.Cos(degrees * Mathf.Deg2Rad);
float tx = v.x;
float ty = v.y;
v.x = (cos * tx) - (sin * ty);
v.y = (sin * tx) + (cos * ty);
return v;
}
}
Can be use that way:
Vector2 direction = Vector2.right.Rotate(45f);
Your method seems good, but it does change the source vector (v) AND return it. To be consistent with other methods (like Clamp$$anonymous$$agnitude), I'd return a new Vector 2 :
public static class Vector2Extension {
public static Vector2 Rotate(this Vector2 v, float degrees) {
float radians = degrees * $$anonymous$$athf.Deg2Rad;
float sin = $$anonymous$$athf.Sin(radians);
float cos = $$anonymous$$athf.Cos(radians);
float tx = v.x;
float ty = v.y;
return new Vector2(cos * tx - sin * ty, sin * tx + cos * ty);
}
}
@Tabemasu Games Vector2 is a struct (pass by value). $$anonymous$$odifying the parameter is fine, as it does not affect the value provided when calling the method (since there is no ref or out keyword).
@Trexug I didn't know it was a struct, thanks for the intel. :)
Quaternions can do all this math for you:
public static class Vector2Extension
{
public static Vector2 Rotate(this Vector2 v, float degrees)
{
return Quaternion.Euler(0, 0, degrees) * v;
}
}
This will work the same as above.
@akauper Quaternion can indeed do the math for you, but the question is not "how can I do this?", and context matters. On a low-weight code like this, overhead can make up a large portion of the method's execution time, And doing the math "manually" avoids large chunks of overhead and, at least according to my tests, can make the code be roughly 2 times faster. --- It's already super fast anyway, and optimizing it is overkill for anything but the most hardcore simulation or bullet-hell games, but it's faster none the less, and as an extension method that's probably never getting changed after you implement it once, it's certainly worth doing I$$anonymous$$HO.
Answer by whydoidoit · Mar 11, 2014 at 06:41 PM
Well if it works don't knock it. You could also do this:
return Quaternion.AngleAxis(_angle, Vector3.forward) * normalizedDirection;
I was just looking for an answer like this. Thank you.
Except based on my test, in this example, the answer should be
return Quaternion.AngleAxis(calibrationAmount, -Vector3.forward) * normalizedDirection;
because calibrationAmount is in degrees, and using Vector3.forward will cause it to rotate in the opposite direction, so you want to use -Vector3.forward ins$$anonymous$$d.
That's irrelevant. There is no right way how something should rotate. If anything then the normal mathematical way should apply which is a counter-clockwise rotation and as far as i can tell that's exactly what's happening. If you need the rotation the other way round you have to either:
use a negative angle
invert the rotation axis (like you did)
But again the "normal" rotation direction is counter-clockwise. $$anonymous$$eep in $$anonymous$$d that Unity is a left-handed system
Though if you only work with 2d vectors the solution that DDP posted is the faster one with less overhead. Creating a quaternion with AngleAxis also requires one "Sin" and one "Cos" call. Though the actual quaternion multiplication is a bit longer since it only works with 3d vectors:
// for reference this is the multiply operator of the Quaternion struct.
public static Vector3 operator *(Quaternion rotation, Vector3 point)
{
float num = rotation.x * 2f;
float num2 = rotation.y * 2f;
float num3 = rotation.z * 2f;
float num4 = rotation.x * num;
float num5 = rotation.y * num2;
float num6 = rotation.z * num3;
float num7 = rotation.x * num2;
float num8 = rotation.x * num3;
float num9 = rotation.y * num3;
float num10 = rotation.w * num;
float num11 = rotation.w * num2;
float num12 = rotation.w * num3;
Vector3 result;
result.x = (1f - (num5 + num6)) * point.x + (num7 - num12) * point.y + (num8 + num11) * point.z;
result.y = (num7 + num12) * point.x + (1f - (num4 + num6)) * point.y + (num9 - num10) * point.z;
result.z = (num8 - num11) * point.x + (num9 + num10) * point.y + (1f - (num4 + num5)) * point.z;
return result;
}
Your answer
Follow this Question
Related Questions
How to rotate a 2D object on touch 1 Answer
How to always rotate clockwise 1 Answer