Search code examples
c++glm-math

Angles of a Point with X, Y, Z using GLM


I have two points, one represents the cursor(a cube) and another one represents the position of the Camera.

Now to find out which face the camera is facing I have done something like this

    glm::vec3 direction = glm::normalize(cursorPos - cameraPos);
    float angle_x, angle_y, angle_z; 

    angle_x = glm::dot(direction, vec3(1.0f, 0.0f, 0.0f));   // in terms of cosine
    angle_x = glm::acos(angle_x);    // in terms of radians
    angle_x = glm::degrees(angle_x); // in terms of degrees

    angle_y = glm::dot(direction, vec3(0.0f, 1.0f, 0.0f));   // in terms of cosine
    angle_y = glm::acos(angle_y);    // in terms of radians
    angle_y = glm::degrees(angle_y); // in terms of degrees

    angle_z = glm::dot(direction, vec3(0.0f, 0.0f, 1.0f));   // in terms of cosine
    angle_z = glm::acos(angle_z);    // in terms of radians
    angle_z = glm::degrees(angle_z); // in terms of degrees

    bool x_45     = angle_x <= 45; 
    bool x_135    = angle_x > 135;

    bool y_45     = angle_y <= 45; 
    bool y_135    = angle_y > 135;

    bool z_45     = angle_z <= 45;
    bool z_135    = angle_z > 135;


    if (x_45)
    {
        std::cout << "facing left face\n"; 
    }
    else if (x_135)
    {
        std::cout << "facing right face\n";
    }
    else if (y_45)
    {
        std::cout << "facing up face\n";
    }
    else if (y_135)
    {
        std::cout << "facing down face\n";
    }
    else if (z_45)
    {
        std::cout << "facing front face\n";
    }
    else if (z_135)
    {
        std::cout << "facing back face\n";
    }    

Why do angles that are getting calculated only in the range (0, 180) with the axis?

It's leading to calculated angles as:

"Angle with x: 62.9398 Angle with y: 47.5 Angle with z: 125.464"

Which should only be possible if the calculated angle range is in (0, 360)?

What is happening right now( I assume) is that it's getting calculated without the consideration of another axis, as shown in the below image.

enter image description here

I am sure this is the most brute way to do this, if anyone has other solution please tell. --Maybe something like converting that normalized vector in its quaternion rotation represtation and getting euler angels out of it?


Solution

  • You made this code hard to understand and maintain. Here is method which do not need large mind power.

    Just 6 vectors defining directions and trying find one which is closest to direction:

    Facing findOrientation(glm::vec3 direction)
    {
        struct FacingNormalizations {
            Facing facing;
            glm::vec3 v;
        };
    
        constexpr std::array facings {
            FacingNormalizations { Facing::back, { 0, 0, 1 } },
            FacingNormalizations { Facing::right, { 1, 0, 0 } },
            FacingNormalizations { Facing::up, { 0, 1, 0 } },
            FacingNormalizations { Facing::front, { 0, 0, -1 } },
            FacingNormalizations { Facing::left, { -1, 0, 0 } },
            FacingNormalizations { Facing::down, { 0, -1, 0 } },
        };
    
        auto r = std::max_element(facings.begin(), facings.end(),
            [direction](const auto& a, const auto& b) {
                return dot(direction, a.v) < dot(direction, b.v);
            });
    
        return r->facing;
    }
    

    https://godbolt.org/z/nqjGbMK54

    Note if you need to add some extra direction it is easy. If you like to make some direction more privileged, you should just make respective vector longer.

    Using C++20 ranges makes this code nicer.