【问题标题】:How to make 3d camera infinitely rotate around with SDL2 mouse motion?如何通过 SDL2 鼠标运动使 3d 相机无限旋转?
【发布时间】:2018-06-29 12:57:45
【问题描述】:

我正在尝试实现 3D 相机鼠标旋转。现在我能做的只是当我的鼠标在窗口的边界时旋转。这意味着如果我的窗口宽度为 1280,如果鼠标坐标为 0 或 1279,我将无法旋转更多。我读过相对鼠标应该有帮助。但它对我不起作用。

在主循环之前

SDL_ShowCursor(SDL_DISABLE);
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_WarpMouseInWindow(window, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);

旋转xyz的函数

glm::vec3 MouseMotion(float x, float y)
{
    float lastX = SCREEN_WIDTH / 2, lastY = SCREEN_HEIGHT / 2;
    float pitch = 0.0f, yaw = -90.0f;

    float offsetX = x - lastX;
    float offsetY = lastY - y;
    lastX = x;
    lastY = y;

    float sensitivity = 0.3f;

    yaw += offsetX * sensitivity;
    pitch += offsetY * sensitivity;

    if (pitch > 89.0f)
        pitch = 89.0f;
    if (pitch < -89.0f)
        pitch = -89.0f;

    glm::vec3 front;
    front.x = std::cos(glm::radians(yaw)) * std::cos(glm::radians(pitch));
    front.y = std::sin(glm::radians(pitch));
    front.z = std::sin(glm::radians(yaw)) * std::cos(glm::radians(pitch));

    //std::cout << "Mouse: " << offsetX << ", " << offsetY << std::endl;
    //std::cout << "YAW AND PITCH: " << yaw << ", " << pitch << std::endl;

    return glm::normalize(front);
}

和事件循环

while (SDL_PollEvent(&event))
    {
        if (event.type == SDL_QUIT)
        {
            exit(0);
        }
        if (event.type == SDL_MOUSEMOTION)
        {
            float mouseX = (float)event.motion.x;
            float mouseY = (float)event.motion.y;
            cameraFront = MouseMotion(mouseX, mouseY);
        }
    }

它可以工作,但前提是我的鼠标在边界内。

更改为 event.motion.xrel 和 event.motion.yrel 并不能解决此问题。由于我的相机抖动,即稍微向右然后回到中心或向左再回到中心,它使它更容易被窃听。

如何让我的相机完全移动,无限移动?

【问题讨论】:

  • 谷歌“[实现]鼠标外观”。 Here's 一个简单又好用的方法让您入门。
  • 我知道如何根据鼠标移动来旋转相机。我的问题是关于如何删除 SDL2 鼠标运动的界限。
  • 好吧,如果你实际上正确地研究了mouse look,你会遇到用来克服这个问题的标准方法,即将鼠标重置到一个固定点在每次位置查询之后。
  • 我明白了。 prev_mouse_x 实际上是什么,因为我没有看到任何声明?
  • 如果没有看到您的代码,我真的无法帮助您。我只能建议您原来的问题的解决方案;由您来实际实现和调试它。

标签: c++ opengl 3d camera sdl-2


【解决方案1】:

从 cmets 开始,以下是问题列表:

  • 你需要在每次SDL_MOUSEMOTION事件后调用SDL_WarpMouseInWindow来重置鼠标,否则它会很快击中你所说的“绑定”。

  • pitchyaw的范围要高于游戏循环,否则每次都会重置,无法实现“无限循环”。

  • sensitivity太高了。大约 500 个单位的典型鼠标移动转化为大约 180 度的转动。


这里尝试通过一些代码重构来解决上述问题:

glm::vec3 polarVector(float p, float y)
{
    // this form is already normalized
    return glm::vec3(std::cos(y) * std::cos(p),
                     std::sin(p),
                     std::sin(y) * std::cos(p));
}

// clamp pitch to [-89, 89]
float clampPitch(float p)
{
    return p > 89.0f ? 89.0f : (p < -89.0f ? -89.0f : p);   
}

// clamp yaw to [-180, 180] to reduce floating point inaccuracy
float clampYaw(float y)
{
    float temp = (y + 180.0f) / 360.0f;
    return y - ((int)temp - (temp < 0.0f ? 1 : 0)) * 360.0f;
}



int main(int argc, char*args[])
{
    // ...

    // experiment with this
    const float sensitivity = 0.001f; 

    #define CTR_X (SCREEN_WIDTH / 2)
    #define CTR_Y (SCREEN_HEIGHT / 2)
    #define RESET_MOUSE SDL_WarpMouseInWindow(window, CTR_X, CTR_Y)

    // call once at the start
    RESET_MOUSE;

    // keep outside the loop
    float pitch = 0.0f, yaw = 0.0f;

    while (!quit)
    {
        // ...

        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT)
            {
                exit(0);
            }
            if (event.type == SDL_MOUSEMOTION)
            {
                float deltaX = (float)event.motion.x - CTR_X;
                float deltaY = (float)event.motion.y - CTR_Y;

                yaw = clampYaw(yaw + sensitivity * deltaX);
                pitch = clampPitch(pitch - sensitivity * deltaY);

                // assumes radians input
                cameraFront = polarVector(glm::radians(pitch), glm::radians(yaw));

                // reset *every time*
                RESET_MOUSE;
            }
        }

        // ...
    }
}

【讨论】:

  • youtube.com/watch?v=KM2MqxPoZWw&feature=youtu.be 我一直在向左拉鼠标。
  • 您能否测试delta(X/Y) 的值是否符合预期,例如将它们打印到控制台?
  • 增量 X 是从 -640 到 +639,增量 Y 是从 -360 到 +359
  • 我的意思是,当您将鼠标拉向特定方向时,对应的delta(X/Y) 值是否合理?例如。拉到左下角,值应该是deltaX &lt; 0, deltaY &gt; 0
  • 抱歉,我忘记将yaw/pitch 转换为弧度。立即尝试。
猜你喜欢
  • 1970-01-01
  • 2022-12-23
  • 1970-01-01
  • 2017-10-02
  • 1970-01-01
  • 2015-01-08
  • 1970-01-01
  • 2021-11-13
  • 2021-08-01
相关资源
最近更新 更多