0
\$\begingroup\$

I have a forward vector of my object, which is a bike, and its position, and I have a directional light direction.

I would like to know where the light is with regards to the bike position/orientation, whether is it in front, on the right-hand side or on the left-hand side. The light will not move but the bike will.

Here is the code I have so far but it's not working as I expect:

Vector3 lightDirection = mDirectionaLightTransform.transform.position - Source.transform.position;
Vector3 normalizedLightDir = lightDirection.normalized;
Vector3 reflectedForward = Vector3.Reflect(normalizedLightDir, Vector3.forward);

float blobShadowAngle = Vector3.Dot(normalizedLightDir, reflectedForward);
\$\endgroup\$
  • \$\begingroup\$ So to clear it up: you want to know what part of your bike is facing the light? Is your light directional? Please update your question to make it a bit more clear. \$\endgroup\$ – Alexandre Vaillancourt Mar 4 '14 at 14:29
  • \$\begingroup\$ @AlexandreVaillancourt yes the light is directional, and what you described is exactly what I want to do. \$\endgroup\$ – Ahmed Saleh Mar 4 '14 at 15:12
0
\$\begingroup\$

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:

  1. 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.
  2. Rotate the light source vector (invert the light direction to get the source) by the angle computed in 1.
  3. 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.
  4. 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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.