How to calculate the right and up perpendicular vectors from a given 3D direction/vector?

I want to know how to manually calculate for the perpendicular up and right vectors from a given 3D vector? I found a hacky solution that can be seen here in this youtube video (once again, warning my video has random music in it :smile: ) .), it uses the transform.forward z vector for the given vector. This it depicts the result I want. I want to use the perpendicular vector calculations to then create a square shape that is perpendicular to the given vector and stretches within the cube boundary. However, I want to be able to do the math without the assistance of a gameobject.tranform, and I actually want to understand it.

There can be more than one way to solve this. Might be with quaternions such as in the video, the other way might be with matrices and linear algebra. I don’t know a lot of math, but I’d like to know how to manually solve this, can you be kind enough to explain it to a beginner?

To find perpendicular vectors you generally use the Vector3.Cross() method to compute the cross product of any two vectors.

From a single vector you only get a perpendicular plane that will contain the other direction vectors, but it’s not clear how those vectors would be rotated. Any rotation around the input vector can create a coordinate space, you need to somehow pick one.

Usually you pick the up direction to anchor the coordinate space. But what is up depends on the context, up could be (0,1,0), (0,0,1) or even position dependent, if you e.g. have planets in your game.

If you have your vector and the up direction, you can use the cross product, as @Kurt-Dekker mentioned:

bool CreateCoordinateSpace(Vector3 forward, Vector3 referenceUp, out Vector3 right, out Vector3 up)
{
    // Get right direction, perpendicular to plane formed by the forward/referenceUp vectors
    right = Vector3.Cross(referenceUp, forward).normalized;
    if (right.sqrMagnitude == 0f) {
        // directions of forward and referenceUp are near equal, result is undefined
        up = Vector3.zero;
        return false;
    }

    // forward/right form the base plane, cross them to get the perpendicular up direction
    up = Vector3.Cross(forward, right).normalized;
    return true;
}

As you can see, this is not guaranteed to work. If your forward direction is pointing exactly upwards, the result becomes undefined. Depending on your use case, you need to detect this case and add an appropriate fallback.

Thanks. I think this is the way to do it.
There was an other way I found out about, which is to create a quaternion rotation to the direction/forward vector, then multiply by a world vector (say world.right) to get the local (local.right).

From “Real-Time Rendering” book (section 4.2.4):

For a given vector r, we need to find two axes that are orthonormal both to r and to each other. We concentrate on finding the second axis, s, knowing that the third axis, t, will be the cross product of the first and the second axis, t = r × s. A numerically stable way to do this is to find the smallest component (in absolute value) of r, and set it to 0. Swap the two remaining components, and then negate the first of them (in fact, either of the nonzero components could be negated). Mathematically, this is expressed as:

This guarantees that s is orthogonal (perpendicular) to r, and that (r, s, t) is an
orthonormal basis.

Interesting, thanks for posting.

This is basically projecting the vector onto one of the cardinal planes into 2D space and then doing the 2D trick of swapping the axes and negating one of them to do a 90° rotation.

This has the advantage that it works for any input direction. However, this is not well suited if you have a rotating input direction and want to construct a stable coordinate space from that, as the space will abruptly flip at various points when rotating the input direction.