0
\$\begingroup\$

Suppose that I have an orientation Quaternion Q, I can compute its forward vector from V = Q * Vector3.forward easily.

Inversely, suppose that I have its forward vector V, how do I compute Q?

I know that is not possible, please tell me what's needed beside V, in order to compute Q.

Motivation behind the problem: I have a forward direction of a game object, I want to find out its up direction and its right direction. I can find out all these 3 directions if I have the orientation Quaternion.

\$\endgroup\$
5
  • \$\begingroup\$ Do you know the method Quaternion.LookRotation ? \$\endgroup\$
    – DMGregory
    Commented Oct 13, 2018 at 20:38
  • \$\begingroup\$ yes. i know but it's not creating the same rotation as Q \$\endgroup\$
    – offchan
    Commented Oct 13, 2018 at 21:53
  • \$\begingroup\$ You passed both the forward and up parameters? \$\endgroup\$
    – DMGregory
    Commented Oct 13, 2018 at 21:54
  • \$\begingroup\$ I don't have the up vector. \$\endgroup\$
    – offchan
    Commented Oct 13, 2018 at 23:53
  • \$\begingroup\$ Maybe you should tell us what you do have then. So far all we know is that you have a forward vector, but you already know that's insufficient on its own. \$\endgroup\$
    – DMGregory
    Commented Oct 14, 2018 at 0:01

3 Answers 3

0
\$\begingroup\$

You can calculate a right and up directly from the forward. however it is not going to be a unique up and right because there is an extra degree of freedom you need to consider.

Code from Building an Orthonormal Basis, Revisited

void branchlessONB(const Vec3f &n, Vec3f &b1, Vec3f &b2){
    float sign = copysignf(1.0f, n.z);
    const float a = -1.0f / (sign + n.z);
    const float b = n.x * n.y * a; 
    b1 = Vec3f(1.0f + sign * n.x * n.x * a, sign * b, -sign * n.x);
    b2 = Vec3f(b, sign + n.y * n.y * a, -n.y);
}
\$\endgroup\$
1
\$\begingroup\$

Unless your forward vector is directed exactly up, you can easily find the right and up vectors in Unity:

Vector3 right = Vector3.Cross(Vector3.up, forward);
Vector3 up = Vector3.Cross(forward, right);

Otherwise, right and up will be zero and you will be experiencing gimbal lock, a problem that has plenty of different solutions depending on your case. Choosing an arbitrary right vector may be a solution. The final code could be:

Vector3 right = Vector3.Angle(Vector3.up, forward) < 0.001)
              ? Vector3.right : Vector3.Cross(Vector3.up, forward);
Vector3 up = Vector3.Cross(forward, right);
\$\endgroup\$
3
  • \$\begingroup\$ Similar to gimbal lock, the method you propose has a singularity when looking straight up or straight down, but it's not caused by gimbal lock in this case because we're not rotating on gimbals (dependent rotation axes). The symptoms are also different: in gimbal lock, we'll still have a valid orientation but we'll lose a degree of freedom, left with only two axes. The singularity in this construction won't cause a loss of a degree of freedom, it will cause either an invalid/underspecified orientation, or once dealt with, a discontinuous change in orientation for a continuous change in inputs. \$\endgroup\$
    – DMGregory
    Commented Oct 15, 2018 at 12:39
  • \$\begingroup\$ I want right and up vector that is relative to the object entirely. So the right vector needs to not be parallel to the ground like this. I think your code gives right vector that is parallel to the ground. \$\endgroup\$
    – offchan
    Commented Oct 15, 2018 at 19:44
  • \$\begingroup\$ @off99555 then there is one piece of missing information: the roll value, otherwise many values for the right vector can be good, especially the one parallel to the ground. \$\endgroup\$ Commented Oct 16, 2018 at 7:18
0
\$\begingroup\$

In order to convert a direction-vector to a quaternion, use Quaternion.LookRotation(v). The (optional) second argument isn't the up-vector of the object. It's the up-vector of the world.

\$\endgroup\$
1
  • \$\begingroup\$ The second argument is an approximate up vector you want the resulting rotation to have. (ie. you want it to get as close as possible to resultQuaternion * (0, 1, 0) == secondArgument given the forward vector provided in the first argument} It defaults to the world up vector if not specified, so if we're specifying it, then it's generally because we don't want the world up vector. \$\endgroup\$
    – DMGregory
    Commented Oct 15, 2018 at 12:30

You must log in to answer this question.

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