Please note that I don't have unity, but my example is in c# so you'll be able to follow along.
First, since your question concerns a bike (assuming it'll always be on the ground), I've taken the liberty to 'flatten' the question and use only the x and y attributes of the used directions as in this context the z is irrelevant.
The way I'd do it:
- Compute the angle between the bike and a reference vector, in this case (1.0, 0.0) because we'll use atan2 and things get computed w.r.t that vector in atan2.
- Rotate the light source vector (invert the light direction to get the source) by the angle computed in 1.
- Compute the angle of the rotated source vector. This way you get the angle of the source w.r.t. the front of the bike.
- With the last angle computed, determine where the light is w.r.t. the bike.
Now what is considered "in front" or "on the right side" is quite vague, so you'll have to set angle ranges.
Here is a code sample that illustrate the process.
struct Vec2
{
public Vec2(double aX = 0.0, double aY = 0.0) { x = aX; y = aY; }
public double x;
public double y;
}
static double radToDeg(double aRad) { return aRad / System.Math.PI * 180.0; }
static void Main(string[] args)
{
double angle;
angle = getAngle(new Vec2(1.0, 0.0), new Vec2(-1.0, 0.0));
System.Console.WriteLine(String.Format("Front? {0} {1}", angle, getDirection(angle)));
angle = getAngle(new Vec2(1.0, 0.0), new Vec2(1.0, 0.0));
System.Console.WriteLine(String.Format("rear? {0} {1}", angle, getDirection(angle)));
angle = getAngle(new Vec2(1.0, 0.0), new Vec2( 0.0, 1.0));
System.Console.WriteLine(String.Format("right? {0} {1}", angle, getDirection(angle)));
angle = getAngle(new Vec2(1.0, 0.0), new Vec2( 0.0, -1.0));
System.Console.WriteLine(String.Format("left? {0} {1}", angle, getDirection(angle)));
angle = getAngle(new Vec2(0.0, 1.0), new Vec2(0.0, -1.0));
System.Console.WriteLine(String.Format("Front? {0} {1}", angle, getDirection(angle)));
angle = getAngle(new Vec2(0.0, 1.0), new Vec2(0.0, 1.0));
System.Console.WriteLine(String.Format("rear? {0} {1}", angle, getDirection(angle)));
angle = getAngle(new Vec2(0.0, 1.0), new Vec2(-1.0, 0.0));
System.Console.WriteLine(String.Format("right? {0} {1}", angle, getDirection(angle)));
angle = getAngle(new Vec2(0.0, 1.0), new Vec2(1.0, 0.0));
System.Console.WriteLine(String.Format("left? {0} {1}", angle, getDirection(angle)));
}
static double getAngle(Vec2 aBikeForward, Vec2 aLight)
{
// invert the light because we want to have a source vector
Vec2 invertedLightVec = new Vec2(-aLight.x, -aLight.y);
// have both vector in the frame of the bike where it's front is pointing at (1, 0)
// get the angle of the bike with our reference (1,0); invert the angle
// because we'll use it to transform the inverted light vector.
double angleBike = -System.Math.Atan2(aBikeForward.y, aBikeForward.x);
// rotate the light by this angle
Vec2 rotatedLight = new Vec2(
invertedLightVec.x * System.Math.Cos(angleBike) - invertedLightVec.y * System.Math.Sin(angleBike)
, invertedLightVec.x * System.Math.Sin(angleBike) + invertedLightVec.y * System.Math.Cos(angleBike) );
// compute the angle of the rotated vector
return System.Math.Atan2(rotatedLight.y, rotatedLight.x);
}
static String getDirection(double aAngle)
{
if (radToDeg(aAngle) > -45.0 && radToDeg(aAngle) < 45.0)
{
return "front";
}
if (radToDeg(aAngle) > -135.0 && radToDeg(aAngle) < -45.0)
{
return "right";
}
if (radToDeg(aAngle) > 45.0 && radToDeg(aAngle) < 135.0)
{
return "left";
}
return "other";
}
I think there are other ways to achieve this, but I can't think of one right now, but this method will get you started.