如何使用GLFW在IMGUI中处理鼠标事件?

发布于 2025-01-17 19:47:53 字数 1242 浏览 0 评论 0 原文

我使用 glfw 回调函数用鼠标移动相机。

鼠标回调函数是:

void mouse_callback(GLFWwindow *window, double xposIn, double yposIn)
{
    if (is_pressed)
    {
        camera.ProcessMouseMovement((static_cast<float>(yposIn) - prev_mouse.y) / 3.6f, (static_cast<float>(xposIn) - prev_mouse.x) / 3.6f);
        prev_mouse.x = xposIn;
        prev_mouse.y = yposIn;
    }
    cur_mouse.x = xposIn;
    cur_mouse.y = yposIn;
}

void mouse_btn_callback(GLFWwindow *window, int button, int action, int mods)
{
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
    {
        prev_mouse.x = cur_mouse.x;
        prev_mouse.y = cur_mouse.y;
        is_pressed = true;
    }
    else
    {
        is_pressed = false;
    }
}

但是,在这种情况下,即使在其他imgui窗口中操作,相机也会移动,如下所示。

我不知道如何处理这个问题。

我是否应该使用诸如 ImGui::IsWindowHovered() 之类的东西将此逻辑放在 IMGUI 的开始和结束之间?

像这样:

ImGui::Begin("scene");
{
    if(ImGui::IsWindowHovered())
    {
        //camera setting    
    }
}
ImGui::End()

I used the glfw callback function to move the camera with the mouse.

mouse callback function is:

void mouse_callback(GLFWwindow *window, double xposIn, double yposIn)
{
    if (is_pressed)
    {
        camera.ProcessMouseMovement((static_cast<float>(yposIn) - prev_mouse.y) / 3.6f, (static_cast<float>(xposIn) - prev_mouse.x) / 3.6f);
        prev_mouse.x = xposIn;
        prev_mouse.y = yposIn;
    }
    cur_mouse.x = xposIn;
    cur_mouse.y = yposIn;
}

void mouse_btn_callback(GLFWwindow *window, int button, int action, int mods)
{
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
    {
        prev_mouse.x = cur_mouse.x;
        prev_mouse.y = cur_mouse.y;
        is_pressed = true;
    }
    else
    {
        is_pressed = false;
    }
}

However, in this case, the camera will move even when operated in other imgui windows as shown below.

I don't know how to handle this.

Should I put this logic between begin and end of IMGUI, using something like ImGui::IsWindowHovered()?

like this:

ImGui::Begin("scene");
{
    if(ImGui::IsWindowHovered())
    {
        //camera setting    
    }
}
ImGui::End()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

木落 2025-01-24 19:47:53

上面的回答都是错误的。
亲爱的 ImGui 常见问题解答中对此进行了解答:
https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-how-can-i-tell-whether-to-dispatch-mousekeyboard-to-dear- imgui 或我的应用程序
TL;DR 检查鼠标的 io.WantCaptureMouse 标志。

Answer above are wrong.
This is answered in the Dear ImGui FAQ:
https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-how-can-i-tell-whether-to-dispatch-mousekeyboard-to-dear-imgui-or-my-application
TL;DR check the io.WantCaptureMouse flag for mouse.

寒尘 2025-01-24 19:47:53

我今天有同样的问题。
对于现在看到此问题的任何人,您必须在初始化IMGUI之前定义GLFW回调。 IMGUI此时设置了自己的回调,并将输入发送给已经存在的回调,即使没有被消耗。如果您以后定义回调,则覆盖IMGUI创建的回调。

I had the same problem today.
For anyone seeing this now, you have to define your glfw callbacks before initializing ImGui. ImGui sets its own callbacks up at this point and handles sending inputs to already existing ones, if not consumed before. If you define your callbacks afterwards you overwrite those created by ImGui.

偏闹i 2025-01-24 19:47:53

我对 ImGui 不熟悉,所以我不知道 ImGui 中可能需要或不需要调用哪些函数。

但是,GLFW 是一个相对较低级别的窗口 API,它不考虑窗口上可能存在的更高级别的抽象。当您将回调传递给 glfwSetCursorPosCallback 时,将在窗口的任何可访问部分调用该回调。

如果您需要仅当鼠标悬停在界面的相关部分上时才响应鼠标移动(或任何鼠标交互),则需要某种机制来定义该部分是什么。再说一次:我不知道你会如何在 ImGui 中做到这一点,但它可能看起来像这样:

void mouse_callback(GLFWwindow *window, double xposIn, double yposIn)
{
    //Structured Binding; we expect these values to all be doubles.
    auto [minX, maxX, minY, maxY] = //Perhaps an ImGui call to return the bounds of the openGL surface?
    if(xposIn < minX || xposIn > maxX || yposIn < minY || yposIn > maxY) {
        return; //We're outside the relevant bounds; do not do anything
    }
    //I'm assuming setting these values should only happen if the mouse is inside the bounds.
    //Move it above the first if-statement if it should happen regardless.
    cur_mouse.x = xposIn;
    cur_mouse.y = yposIn;
    if (is_pressed)
    {
        camera.ProcessMouseMovement((static_cast<float>(yposIn) - prev_mouse.y) / 3.6f, (static_cast<float>(xposIn) - prev_mouse.x) / 3.6f);
        prev_mouse.x = xposIn;
        prev_mouse.y = yposIn;
    }
}

I'm not familiar with ImGui, so I don't know what functions might or might not need to be called in ImGui.

But, GLFW is a relatively low level windowing API that has no regard for the higher level abstractions that might exist on the window. When you pass the callback to glfwSetCursorPosCallback, that callback will be called on any accessible part of the window.

If you need to have the mouse movements (or any mouse interactions) only respond when the mouse is hovered over the relevant part of the interface, you need some kind of mechanism to define what that part is. Again: I don't know how you'd do that in ImGui, but it'll probably look something like this:

void mouse_callback(GLFWwindow *window, double xposIn, double yposIn)
{
    //Structured Binding; we expect these values to all be doubles.
    auto [minX, maxX, minY, maxY] = //Perhaps an ImGui call to return the bounds of the openGL surface?
    if(xposIn < minX || xposIn > maxX || yposIn < minY || yposIn > maxY) {
        return; //We're outside the relevant bounds; do not do anything
    }
    //I'm assuming setting these values should only happen if the mouse is inside the bounds.
    //Move it above the first if-statement if it should happen regardless.
    cur_mouse.x = xposIn;
    cur_mouse.y = yposIn;
    if (is_pressed)
    {
        camera.ProcessMouseMovement((static_cast<float>(yposIn) - prev_mouse.y) / 3.6f, (static_cast<float>(xposIn) - prev_mouse.x) / 3.6f);
        prev_mouse.x = xposIn;
        prev_mouse.y = yposIn;
    }
}
帅哥哥的热头脑 2025-01-24 19:47:53

在我的 initializeWindow() 方法中,我在设置 ImGui 后调用 glfwSetCursorPosCallback(window, mouse_callback)。将其移至解决我的问题之前。这是有效的代码片段:

// Set the callback functions using GLFW
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);

// Set up DEAR IMGUI
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable 
       Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad 
       Controls        
// Set up Dear ImGui style
ImGui::StyleColorsDark();
// Set up Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 330");

In my initializeWindow() method, I was calling glfwSetCursorPosCallback(window, mouse_callback) after setting up ImGui. Moving the it to before resolved my problem. Here is the code snippet that worked:

// Set the callback functions using GLFW
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);

// Set up DEAR IMGUI
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable 
       Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad 
       Controls        
// Set up Dear ImGui style
ImGui::StyleColorsDark();
// Set up Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 330");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文