C GLFW鼠标事件滞后,窗口拖动
我试图在GLFW中拖动一个未装饰的窗口,但遇到了一些事件延迟,即使我使用的是C GLFW鼠标事件滞后,窗口拖动,c,opengl,glfw,cursor-position,setwindowpos,C,Opengl,Glfw,Cursor Position,Setwindowpos,我试图在GLFW中拖动一个未装饰的窗口,但遇到了一些事件延迟,即使我使用的是glfwWaitEvents() 我有一个光标位置回调和一个简单的循环: // register a cursor position callback glfwSetCursorPosCallback(win, cursor_pos_callback); // then loop.. while(!glfwWindowShouldClose(win)) { glfwWaitEvents(); ... some
glfwWaitEvents()
我有一个光标位置回调和一个简单的循环:
// register a cursor position callback
glfwSetCursorPosCallback(win, cursor_pos_callback);
// then loop..
while(!glfwWindowShouldClose(win)) {
glfwWaitEvents();
... some rendering...
glfwSwapBuffers(win);
}
我的游标回调对delta进行一些简单的跟踪,并更新窗口位置
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
xpo
会按其应该的方式递增,然后每隔一段时间就会倒退一次(过时事件?)
可能我的窗口移动与光标不同步
结果是,当我拖动窗口时,它剧烈摇晃,我几乎无法将其移动到任何地方……
更新:我也尝试过将
glfwSetWindowPos
逻辑移动到主循环中,但没有成功——我仍然会得到同样的抖动和口吃
更新:当我注释掉
glfwSetWindowPos()
时,窗口不再移动(当然),但事件流现在是一致的
这让我想到,快速移动窗口会导致抖动(即向前2步,向后1步)。我怀疑您的问题在于
光标位置回调
接收光标相对于窗口的位置,移动窗口会立即影响该位置
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);
}
}
假设以恒定速率对角移动光标。如果光标在一个刻度上从相对位置(100100)移动到(105105),则计算delta_x=5
和delta_y=5
。然后你移动窗户。然后,移动窗口的过程会立即将相对坐标从(105105)更改回(100100),在下一个刻度上,即使您已移动到相对于原始窗口位置的位置(110110),您也仅处于相对于新窗口位置的相对位置(105105),因此,您可以从以前的位置(加上一些随机抖动噪声)计算delta_x=0
和delta_y=0
,即使您实际上沿每个轴移动了5个单位
相反,修改算法以保持恒定的相对光标位置。在拖动开始处,存储相对光标位置(例如(100100))。现在,在每个记号处,计算需要将窗口放置在何处,以将光标移回固定的相对位置。因此,如果光标已移动到(112108),则将窗口移动(+12,+8)以将光标放回(100100)。在稍后的勾选中,如果光标已移动到(108106),则不要尝试从(112108)计算增量;相反,将其与原始(100100)起点进行比较,并将窗口移动(+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);
}
}
我将另一个答案标记为可接受的解决方案,因为确实需要记录初始起始光标位置(相对于窗口),并使用该位置计算增量 然而,这样做只提供了一半的解决方案。 拖动时,我仍然会经历一些重大的跳跃和射击 最后,我发现这个同步问题来自于我设置新窗口位置的地方
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);
}
}
要完全消除任何延迟,并确保窗口+光标同步,必须在渲染循环内部同时执行glfwGetWindowPos()
和glfwSetWindowPos()
强>
在回调内部这样做将导致位置不同步的抖动。因此,我相信解决方案的一部分是确保窗口和光标尽可能保持同步
这是我想到的一个最小的例子(非常感谢K.a.布尔!)
#包括
#包括
#包括
#包括
静态双光标位置x=0;
静态双光标位置y=0;
静态双增量x=0;
静态双增量y=0;
静态int窗口拖动活动=0;
静态无效鼠标按钮回调(GLFWwindow*窗口、int按钮、int操作、,
int mods){
如果(按钮==GLFW\u鼠标按钮\u左&&action==GLFW\u按下){
窗口拖动活动=1;
双x,y;
glfwGetCursorPos(窗口、x和y);
光标位置x=楼层(x);
光标位置y=楼层(y);
}
如果(按钮==GLFW\U鼠标按钮\U左&&action==GLFW\U释放){
窗口拖动激活=0;
}
}
int main(){
glfwInit();
GLFWwindow*win=glfwCreateWindow(400500,“拖动示例”,NULL,NULL);
glfwSetMouseButtonCallback(赢,鼠标按钮回调);
glfwMakeContextCurrent(win);
而(!GLFWWindowsShouldClose(win)){
glfwaitevents();
如果(窗口\拖动\活动){
双XPO,YPO;
glfwGetCursorPos(win、xpos和YPO);
delta_x=xpos-光标_pos_x;
delta_y=ypos-光标位置y;
int x,y;
glfwGetWindowPos(win、x和y);
glfwSetWindowPos(win,x+delta_x,y+delta_y);
}
glfwSwapBuffers(win);
}
返回0;
}
谢谢您的详细回答!这无疑是解决问题的核心办法。然而,它只是部分修复了这个问题,抖动仍然存在,但至少它更好地跟踪了光标。