Lets say I have a cube or spherical surface. I have an object that I want to have "sitting" on this surface, i.e. the y axis of the object should be equal to the normal of the surface. To render, I'm using a transformation that takes a position vector, 3 angles of rotation, and a scale vector.
Before, I was trying to compute the angle between a standard <0, 1, 0> vector and the normal, to get three angles: a, b, g. Then, I tried to use these angles to rotate the object around the i, j, and k unit vectors, to rotate it to be equal to the normal.
This didn't work, I assume because arccos has a range of [0, 180]. So my question is: what math would I need to do in order to assert my object to the normal of a surface?
Let me also specify that the rotation of the object around the normal doesn't matter, I only care that the object is normal to the surface.
For specification: I'm using Java and OpenGL, but this is more of a math-based question so I don't think that matters a ton.
Here's the current code I'm trying to use:
/**
* generates a vector of rotation to a vector
* @param v - the vector
* @return - a vector containing the x, y, z rotations
*/
public static Vector3f rotationTo(Vector3f v) {
float x = Vector3f.angleBetween(new Vector3f(0, 1, 0), new Vector3f(0, v.y, v.z));
float y = Vector3f.angleBetween(new Vector3f(0, 0, 1), new Vector3f(v.x, 0, v.z));
float z = Vector3f.angleBetween(new Vector3f(0, 1, 0), new Vector3f(v.x, v.y, 0));
return new Vector3f(x, y, z);
}
/**
* determines the angle between two vectors in degrees
* @param v - vector 1
* @param u - vector 2
* @return - the angle between
*/
public static float angleBetween(Vector3f v, Vector3f u) {
return (float) Math.toDegrees(
Math.acos(Vector3f.dot(v, u)
* quickInverseSqrt(v)
* quickInverseSqrt(u))
);
}
/**
* quickly determines the inverse magnitude of a vector using the
* Fast Inverse Square Root formula
* @param v - the vector
* @return - the magnitude
*/
public static float quickInverseSqrt(Vector3f v) {
float val = v.x * v.x + v.y * v.y + v.z * v.z;
float xHalf = 0.5f * val;
int i = Float.floatToIntBits(val);
i = 0x5f3759df - (i >> 1);
val = Float.intBitsToFloat(i);
val *= (1.5f - xHalf * val * val);
return val;
}
The answer I found was to instead of rotating 3 different times, (x, y, z) over (i, j, k), I determined the axis of rotation by crossing the vertical component j by the normal vector, and then I found the angle of rotation by using the formula Cos(t)=v·u. Then, I rotated around this axis by the angle, which allowed me to create a rotation matrix accordingly.