简体   繁体   中英

How would one place an object normal to a surface in 3D space?

Lets say I have a cube or spherical surface. I have an object that I want to have "sitting" on this surface, ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM