【问题标题】:GLFW Mouse event lag with window dragGLFW 鼠标事件延迟与窗口拖动
【发布时间】:2018-02-22 12:50:34
【问题描述】:

我试图在 GLFW 中拖动一个未装饰的窗口,但遇到了一些事件延迟,即使我使用的是 glfwWaitEvents()

我有一个光标位置回调和一个简单的循环:

// register a cursor position callback
glfwSetCursorPosCallback(win, cursor_pos_callback);

// then loop..
while(!glfwWindowShouldClose(win)) {
  glfwWaitEvents();
  ... some rendering...
  glfwSwapBuffers(win);
}

我的光标回调对增量进行了一些简单的跟踪并更新了窗口位置。

cursor_pos_callback(GLFWwindow *win, double xpos, double ypos) {
  // figure out delta_x and delta_y based on cursor previous position
  int delta_x, delta_y;

  // update window position
  if (window_drag_active) {
     int x,y;
     glfwGetWindowPos(window, &x, &y);
     glfwSetWindowPos(window, x + delta_x, y + delta_y);
  }
}

这是三角洲的样子当我沿直线拖动时

delta_x:  10    delta_y:   0    |    xpos:   649    ypos: 55
delta_x:   5    delta_y:  -1    |    xpos:   654    ypos: 54
delta_x:   5    delta_y:   3    |    xpos:   659    ypos: 57
delta_x:   5    delta_y:   2    |    xpos:   664    ypos: 59
delta_x:  -5    delta_y:  -2    |    xpos:   659    ypos: 57
delta_x:   4    delta_y:   0    |    xpos:   663    ypos: 57
delta_x:   2    delta_y:   0    |    xpos:   665    ypos: 57
delta_x:  -3    delta_y:  -3    |    xpos:   662    ypos: 54
delta_x:   2    delta_y:   1    |    xpos:   664    ypos: 55
delta_x:   2    delta_y:   0    |    xpos:   666    ypos: 55
delta_x:   3    delta_y:   2    |    xpos:   669    ypos: 57
delta_x:   1    delta_y:  -1    |    xpos:   670    ypos: 56
delta_x:   2    delta_y:  -1    |    xpos:   672    ypos: 55
delta_x:   7    delta_y:   3    |    xpos:   679    ypos: 58
delta_x:   2    delta_y:  -1    |    xpos:   681    ypos: 57
delta_x:  -2    delta_y:  -3    |    xpos:   679    ypos: 54
delta_x:   0    delta_y:  -2    |    xpos:   679    ypos: 52
delta_x:   3    delta_y:   3    |    xpos:   682    ypos: 55
delta_x:  -5    delta_y:  -3    |    xpos:   677    ypos: 52

xpos 会按应有的递增,然后每隔一段时间就会倒退(过时的事件?)

也许我的窗口移动没有与光标同步?

结果是当我拖动窗口时,它剧烈摇晃,我几乎无法将它移动到任何地方......


更新:我也尝试将 glfwSetWindowPos 逻辑移动到主循环中,但没有成功——我仍然遇到同样的抖动和口吃。


更新:当我注释掉glfwSetWindowPos() 时,窗口不再移动(当然),但事件流现在是一致的。

这让我认为窗口的移动在快速完成时会导致抖动(即向前 2 步,向后 1 步)。

【问题讨论】:

    标签: c opengl glfw cursor-position setwindowpos


    【解决方案1】:

    我怀疑您的问题是 cursor_pos_callback 接收光标位置相对于窗口,移动窗口会立即影响该位置。

    假设您以恒定速率沿对角线移动光标。如果超过一个刻度,光标从相对位置 (100,100) 移动到 (105,105),则计算 delta_x=5 和 delta_y=5。然后移动窗口。然后移动窗口的过程会立即将相对坐标从 (105,105) 更改回 (100,100),并且在下一个刻度上,即使您已移动到相对于原始窗口位置的位置 (110,110),您也只能在相对相对于新窗口位置的位置 (105,105),因此即使您实际上已经移动了一个附加项,您也可以从之前的位置(加上一些随机抖动噪声)计算 delta_x=0 和 delta_y=0每个轴 5 个单位。

    改为修改您的算法以保持恒定的相对光标位置。在拖动开始时,存储相对光标位置(例如 (100,100))。现在,在每个刻度处,计算您需要将窗口放置在何处以将光标移回该固定的相对位置。因此,如果光标已移动到 (112,108),则将窗口移动 (+12,+8) 以将光标放回 (100,100)。在稍后的滴答声中,如果光标已移动到 (108,106),请不要尝试从 (112,108) 计算增量;相反,将其与原始 (100,100) 起点进行比较,并将窗口移动 (+8,+6)。应该是这样的:

    cursor_pos_callback(GLFWwindow *win, double xpos, double ypos) {
    
      // update window position
      if (window_drag_active) {
         int delta_x = xpos - window_drag_starting_xpos;
         int delta_y = ypos - window_drag_starting_ypos;
         int x,y;
         glfwGetWindowPos(window, &x, &y);
         glfwSetWindowPos(window, x + delta_x, y + delta_y);
      }
    }
    

    【讨论】:

    • 感谢您的详细解答!这绝对是解决问题的核心。然而它只是部分解决了这个问题,抖动仍然存在,但至少它更好地跟随光标。
    【解决方案2】:

    我将另一个答案标记为已接受的解决方案,因为您确实需要记录初始起始光标位置(相对于窗口)并使用它来计算增量。

    但是,这样做只提供了一半的解决方案。 拖动时我仍然在屏幕上经历了一些重大的跳跃和射击!

    最后我发现这个同步问题来自我设置新窗口位置的位置。

    要完全消除任何延迟,并确保窗口+光标同步,您必须同时执行glfwGetWindowPos() 和glfwSetWindowPos() 在渲染循环内部!

    在回调内部这样做会导致位置不同步的抖动。所以我相信部分解决方案也是确保尽可能保持窗口+光标同步。

    这是我想到的一个最小示例(非常感谢 K.A. Buhr!)

    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #include <GLFW/glfw3.h>
    
    static double cursor_pos_x = 0;
    static double cursor_pos_y = 0;
    static double delta_x = 0;
    static double delta_y = 0;
    
    static int window_drag_active = 0;
    
    static void mouse_button_callback(GLFWwindow *window, int button, int action,
                                  int mods) {
        if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
            window_drag_active = 1;
            double x, y;
            glfwGetCursorPos(window, &x, &y);
            cursor_pos_x = floor(x);
            cursor_pos_y = floor(y);
        }
        if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
            window_drag_active = 0;
        }
    }
    
    int main() {
        glfwInit();
    
        GLFWwindow *win = glfwCreateWindow(400, 500, "Drag Example", NULL, NULL);
    
        glfwSetMouseButtonCallback(win, mouse_button_callback);
        glfwMakeContextCurrent(win);
    
        while (!glfwWindowShouldClose(win)) {
        glfwWaitEvents();
    
        if (window_drag_active) {
            double xpos, ypos;
            glfwGetCursorPos(win, &xpos, &ypos);
            delta_x = xpos - cursor_pos_x;
            delta_y = ypos - cursor_pos_y;
    
            int x, y;
            glfwGetWindowPos(win, &x, &y);
            glfwSetWindowPos(win, x + delta_x, y + delta_y);
        }
    
        glfwSwapBuffers(win);
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-10-07
      • 2020-05-10
      • 1970-01-01
      • 2020-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-16
      相关资源
      最近更新 更多