3

I have a Vector with 3 components (X,Y,Z) and i want to find a Vector orthogonal to the given one. Since the Vectors orthogonal to any Vector are infinite, i just need one that is randomic.

I've tried using an equation with the Dot Product formula, since the dot product between two orthogonal Vectors is always 0, and I managed to write a bit of code that works only when the given Vector is axis-aligned, but that is probably because the randomized components of the vectors are X and Y. I really can't get my head around this.

I wrote my code on the Unity3D engine in order to be able to easly visualize it:

Vector3 GenerateOrthogonal(Vector3 normal)
    {
        float x = Random.Range(1f, -1f);
        float y = Random.Range(1f, -1f);

        float total = normal.x * x + normal.y * y;
        float z = -total / -normal.z;

        return new Vector3(x, y, z).normalized;
    }
  • https://stackoverflow.com/questions/11132681/what-is-a-formula-to-get-a-vector-perpendicular-to-another-vector gives you way to find orthogonal vectors - just find 2 and use random linear combinations of them. – Alexei Levenkov Apr 01 '19 at 23:37
  • Think of Orthogonal a a plane perpendicular to a point on a vector. So first you need a point on the original Vector. So step one is to get a random X (from zero to infinity) and then solve for Y and Z on original Vector. Then you can get a 2nd Vector orthogonal to the first.The 2nd vector is really any vector on a plane the is perpendicular to first vector at a point on the first vector.So you are really dealing with infinity squared.First you have an infinite number of points on the original vector. And then Infinite number of vectors on a plane perpendicular to 1st vector at a point. – jdweng Apr 01 '19 at 23:43

1 Answers1

1

There are a few methods for doing this. I'll provide two. The first is a one-liner that uses Quaternions to generate a random vector and then rotate it into place:

Vector3 RandomTangent(Vector3 vector) {
    return Quaternion.FromToRotation(Vector3.forward, vector) * (Quaternion.AngleAxis(Random.Range(0f, 360f), Vector3.forward) * Vector3.right);
}

The second is longer, more mathematically rigorous, and less platform dependent:

Vector3 RandomTangent(Vector3 vector) {
    var normal = vector.normalized;
    var tangent = Vector3.Cross(normal, new Vector3(-normal.z, normal.x, normal.y));
    var bitangent = Vector3.Cross(normal, tangent);
    var angle = Random.Range(-Mathf.PI, Mathf.PI);
    return tangent * Mathf.Sin(angle) + bitangent * Mathf.Cos(angle);
}

Here are some notes on their differences:

  • Both of these functions generate a random perpendicular vector (or "tangent") with a uniform distribution.
  • You can measure the accuracy of these functions by getting the angle between the input and the output. While most of the time it will be exactly 90, there will sometimes be very minor deviations, owing mainly to floating point rounding errors.
  • While neither of these functions generate large errors, the second function generates them far less frequently.
  • Initial experimentation suggests the performance of these functions is close enough that the faster function may vary depending on platform. The first one was actually faster on my machine for standard Windows builds, which caught me off guard.
  • If you're prepared to assume that the input to the second function is a normalized vector, you can remove the explicit normalization of the input and get a performance increase. If you do this and then pass it a non-normalized vector, you'll still get a perpendicular vector as a result, but its length and distribution will no longer be reliably uniform.
  • In the degenerate case of passing a zero vector, the first function will generate random vectors on the XY plane, while the second function will propagate the error and return a zero vector itself.
VPellen
  • 1,071
  • 5
  • 10
  • Thank you very much! You really helped me a lot – Oro Portaluri Apr 02 '19 at 20:17
  • 1
    It's worth noting that the second function has another degenerate case when the input vector is some multiple of `<1, -1, 1>`. In that case, the calculated tangent will always be the zero vector and will propagate. – gfaster Dec 29 '22 at 02:37