1
\$\begingroup\$

I have a object in 3d space that has certain position and velocity. If that object moves perfectly towards point A, the coefficient should be 1. If it moves perfectly away from A it should be -1 or 0. Everything else in between should be respective float. What I have tried for now is googling a lot on the subject, but with no great luck.

\$\endgroup\$

3 Answers 3

2
\$\begingroup\$

Take the position of the two objects, and use that to find a vector that represents the difference of their positions.

var pointA = new Vector3(10, 0, 10);
var objectPos = new Vector3(0, 0, 0);

// Subtraction order here matters:
// (pointA - objectPos) gives you a vector pointing toward pointA
// (objectPos - pointA) points from pointA toward objectPos
var objPosTowardPointA = pointA - objectPos;

Now you have a vector that points from your object toward pointA, you can use this to compare against your object's velocity. Using a Dot Product you can compare these vectors to determine if they're pointing in a similar direction, or opposite direction, or possibly perpendicular directions. However, when comparing direction, you'll have to make sure that the two vectors are of unit length (normalized).

I'm going to assume you don't have any math libraries handy, but if you already have math functions for Length(), Normalize(), and Dot(), then you skip past where I define those below.

Normalizing a vector is simply making its magnitude (length), a length of 1.

// Returns a unit-length version of a Vector3 source
Vector3 Normalize(Vector3 source)
{
    float length = Length();
    float inverseLength = 1.0f / length;

    return new Vector3(
        source.x * inverseLength, 
        source.y * inverseLength, 
        source.z * inverseLength);
}

And to normalize a vector you have to know its length, so here's a method to do that (this is basically the Pythagorean Theorum, if you're familiar with that):

float Length(Vector3 source)
{
    return Math.Sqrt(
        source.x * source.x + 
        source.y * source.y + 
        source.z * source.z); 
}

Ok, now that we've shown how to normalize a vector, let's put it to use:

// Now we have a vector pointing from our object toward point A
// and it's of unit-length, so it can represent a direction
var objToPointANormal = Normalize(objPosTowardPointA);

// We need our velocity to represent a direction without magnitude
// (speed), so we need to normalize it as well
var velocityNormal = Normalize(objectVelocity);

And now we have our two directions we care about, both normalized. From here we can perform a dot product operation on them. The method for that is shown below.

// Returns dot product of two vectors
Vector3 Dot(Vector3 a, Vector3 b)
{
    return a.x * b.x +
           a.y * b.y +
           a.z * b.z;
}

Let's put that dot product to use:

var dot = Vector3.Dot(objToPointANormal, velocityNormal);

And now you have your answer, in the form you asked for. If objToPointANormal and velocityNormal are pointing in the same direction, that is, if the object is moving toward point A, then dot will be 1. If the object is moving away from point A, then dot will be -1. If the object is moving perpendicular to the direction toward point A then dot will be 0.

Assuming you have the math functions set up, the code ends up looking like this:

var pointA = new Vector3(10, 0, 10);
var objectPos = new Vector3(0, 0, 0);

var objToPointANormal = Normalize(pointA - objectPos);
var velocityNormal = Normalize(objectVelocity);

var dot = Vector3.Dot(objToPointANormal, velocityNormal);
\$\endgroup\$
3
\$\begingroup\$

There are two vectors: the speed of the object and the direction of the object to the target point. Our goal is to calculate how "consistent" these two vectors are.

You can calculate the angle(θ) between two vectors using Dot_product:

enter image description here

And,

a·b = |a|*|b|*cosθ

So that, we get cosθ. Then use Inverse_trigonometric_functions (arccos) to get θ. It's range should be [0,180]. Most math libraries have this feature.

Finally, map [0,180] to [1,0] or [1,-1]:

rate = 1 - θ / 180
// or
rate = 1 - θ / 90
\$\endgroup\$
0
\$\begingroup\$

I ended up with something like this in Unity:

Vector3 pos = new Vector3(1, 2, 0);
Vector3 dir = new Vector3(0, -1, 0);
Vector3 targ = new Vector3(1, 0, 0);

Vector3 locTargNorm = (targ - pos).normalized;
Vector3 dirNorm = dir.normalized;

var directCoef = Mathf.Abs(Vector3.Angle(locTargNorm , dirNorm )) / 180.0f;
\$\endgroup\$
1
  • \$\begingroup\$ Your last line could just be: var directCoef = Vector3.Dot(locTargNorm, dirNorm); \$\endgroup\$
    – Nic Foster
    Jul 16, 2022 at 5:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .