opengl 有没有一种方法可以在世界空间中的一个枢轴点上旋转多个模型矩阵?

velaa5lx  于 2023-05-22  发布在  其他
关注(0)|答案(2)|浏览(145)

我正在使用OpenGL和GLFW,我试图旋转多个对象,每个对象都在同一个枢轴点上具有各自的模型矩阵。我的兔子有三个不同的模型,一个身体,一个前腿,一个后腿,我试图在Y轴上旋转它们,使它们面向一个方向。然而,当我试图将腿旋转到位时,腿看起来像是在“移动”。如果我不沿着Y轴旋转它们,那么它们就没问题。我想找到一种方法,在一个枢轴点上旋转所有三个模型矩阵,所以当它们最终旋转时,它们不会在自己的原点上旋转。下面是我的主要代码:

class rabbit {
public:
    std::vector<colored_model_object*> rabbit_renderers;
    std::vector<glm::mat4> rabbit_models;

    glm::vec3 position = glm::vec3(0.0f);
    float fore_leg_rotation = 0;
    float hind_leg_rotation = 0;

    float whole_rotation = 0;

    int jump_phase = 0;
    float jump_lerp = 0.0f;
    float jump_speed = 0.003f;
    glm::vec3 jump_start, jump_end;

    float y_velocity = 0;
    
    rabbit() {
        rabbit_renderers.push_back(new colored_model_object("res/objects/rabbit/rabbit_body.obj"));
        rabbit_renderers.push_back(new colored_model_object("res/objects/rabbit/rabbit_front_legs.obj"));
        rabbit_renderers.push_back(new colored_model_object("res/objects/rabbit/rabbit_hind_legs.obj"));
    }

    void jump(glm::vec3 direction, float magnitude) {
        if (jump_phase >= 1) return;
        glm::vec3 jump_power = glm::normalize(direction) * magnitude;
        jump_start = position;
        jump_end = position + jump_power;
        jump_phase = 1;
        jump_lerp = 0;
        fore_leg_rotation = 0.0f;
        hind_leg_rotation = 0.0f;
        y_velocity = 1;

        glm::vec2 dir_2d = glm::normalize(glm::vec2(direction.x, direction.z));
        glm::vec2 up = glm::vec2(0, 1);
        float dot = dir_2d.x * up.x + dir_2d.y * up.y;
        float det = dir_2d.x * up.y - dir_2d.y * up.x;
        float body_angle = atan2(det, dot);
        whole_rotation = body_angle;
    }

    void update() {
        position.y += y_velocity;
        y_velocity -= 0.008f;
        if (position.y < 0) position.y = 0;
        if (jump_phase> 0) {
            glm::vec2 jump_start_xz = glm::vec2(jump_start.x, jump_start.z);
            glm::vec2 jump_end_xz = glm::vec2(jump_end.x, jump_end.z);
            glm::vec2 position_xz = glm::mix(jump_start_xz, jump_end_xz, jump_lerp);
            position.x = position_xz.x;
            position.z = position_xz.y;
            jump_lerp += jump_speed;
        }
        if (jump_phase == 1) {
            fore_leg_rotation += 1;
            hind_leg_rotation += 1;
            if (fore_leg_rotation > 45.0f) {
                jump_phase = 2;
            }
        }
        if (jump_phase == 2) {
            fore_leg_rotation -= 0.2f;
            hind_leg_rotation -= 0.2f;
            if (fore_leg_rotation < 0.0f) {
                jump_phase = 3;
            }
        }
        if (jump_lerp > 1) {
            jump_phase = 0;
            jump_lerp = 0;
            fore_leg_rotation = 0.0f;
            hind_leg_rotation = 0.0f;
        }
    }

    void update_models() {
        update();

        rabbit_models.clear();
        rabbit_models.push_back(system3d::get_model());
        rabbit_models.push_back(system3d::get_model());
        rabbit_models.push_back(system3d::get_model());
        rabbit_models.at(0) = (system3d::create_model(rabbit_models.at(0),glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(-100 + position.x, 310.5f + position.y, 0 + position.z), 0.0f, glm::vec3(1, 1, 1)));
        rabbit_models.at(1) = (system3d::create_model(rabbit_models.at(1), glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(-100 + position.x, 310.5f + position.y, 0 + position.z), fore_leg_rotation, glm::vec3(1, 0, 0), glm::vec3(0, -42.0f, 0)));
        rabbit_models.at(2) = (system3d::create_model(rabbit_models.at(2), glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(-100 + position.x, 310.5f + position.y, 0 + position.z), hind_leg_rotation, glm::vec3(1, 0, 0), glm::vec3(0, -42.0f, 17.0f)));
        for (int i = 0; i < rabbit_models.size(); i++) {
            rabbit_models.at(i) = glm::rotate(rabbit_models.at(i), glm::radians(whole_rotation), glm::vec3(0, 1, 0));
        }
    }
};

下面是引用的system3d类:

class system3d {
public:
    static glm::mat4 get_model(glm::vec3 scale_vec, glm::vec3 translate_vec, float rotation, glm::vec3 rotation_vec) {
        glm::mat4 model = glm::mat4(1.0f);
        model = glm::scale(model, scale_vec);
        model = glm::rotate(model, glm::radians(rotation), rotation_vec);
        model = glm::translate(model, translate_vec);

        return model;
    }

    static glm::mat4 get_model(glm::vec3 scale_vec, glm::vec3 translate_vec, float rotation, glm::vec3 rotation_vec, glm::vec3 rotation_pivot) {
        glm::mat4 model = glm::mat4(1.0f);
        model = glm::scale(model, scale_vec);
        model = glm::translate(model, translate_vec);

        model = glm::translate(model, -rotation_pivot);
        model = glm::rotate(model, glm::radians(rotation), rotation_vec);
        model = glm::translate(model, rotation_pivot);

        return model;
    }

    static glm::mat4 create_model(glm::mat4 existing, glm::vec3 scale_vec, glm::vec3 translate_vec, float rotation, glm::vec3 rotation_vec) {
        glm::mat4 model = existing;
        model = glm::scale(model, scale_vec);
        model = glm::rotate(model, glm::radians(rotation), rotation_vec);
        model = glm::translate(model, translate_vec);

        return model;
    }

    static glm::mat4 create_model(glm::mat4 existing, glm::vec3 scale_vec, glm::vec3 translate_vec, float rotation, glm::vec3 rotation_vec, glm::vec3 rotation_pivot) {
        glm::mat4 model = existing;
        model = glm::scale(model, scale_vec);
        model = glm::translate(model, translate_vec);

        model = glm::translate(model, -rotation_pivot);
        model = glm::rotate(model, glm::radians(rotation), rotation_vec);
        model = glm::translate(model, rotation_pivot);

        return model;
    }

    static glm::mat4 get_model() {
        glm::mat4 model = glm::mat4(1.0f);
        return model;
    }
};

我一直在试图找到一个解决方案几个小时了,我还没有找到一个不涉及四元数。(我发现四元数真的很令人困惑,我个人无法编写有效的四元数代码。
这里是一个视频的结果,首先当他们的Y轴旋转为0,然后当Y轴旋转不为0:

有人知道我能做什么吗?

cig3rfwq

cig3rfwq1#

如果我理解你的问题,问题是:

  • 当兔子处于其初始方向时,如果旋转腿,则腿将按所需方式旋转。
  • 当你旋转兔子,然后旋转腿,腿旋转的轴与兔子不同(导致奇怪的行为,如腿飞离身体)

如果这代表问题,则需要通过以下方式执行正确的操作顺序:

  • 旋转每个单独的子零部件,就像它们处于初始方向一样
  • 按要应用于整个兔子的整体旋转来旋转整个组。

例如:您想要:

  • 向外旋转右后腿(相对于家兔)- [R1]
  • 向后旋转两条后腿(相对于家兔前/后方向)- [R2]
  • 旋转整个家兔以面向摄像机- [R3]

然后,应用于每个的旋转为:

  • 右腿得到:R_fin_right_hind_leg = [R3][R2][R1]
  • 左后腿:R_fin_left_hind_leg = [R3][R2]
  • 兔子身体的其余部分:R_fin_rabbit_other = [R3]
70gysomp

70gysomp2#

旋转矩阵应首先在任何模型顶点上操作,然后才应应用模型矩阵。所以顺序应该是M*R。另一种方法是“固定”旋转矩阵,使其也平移模型,使其保持在当前位置:

glm::mat4 fixRotationToBeAroundPivot(glm::mat4 const &rotation, glm::vec3 pivot)
{
    glm::mat4 out(rotation);
    glm::vec4 pivot4(pivot.x, pivot.y, pivot.z, 1);
    glm::vec4 displacement4 = pivot4 - out * pivot4; // solve the equation  pivot = rotation * pivot + displacement
    out[3][0] = displacement4.x;
    out[3][1] = displacement4.y;
    out[3][2] = displacement4.z;
}
  • rotation是由glm::rotate创建的矩阵
  • pivot是Model的位置(例如,您可以从ModelMatrix[3]中获取)

相关问题