C++ Opengl纹理有时会在调整窗口大小时闪烁/移动
我有个小问题 我有一个带有OpenGL子窗口的窗口, 到目前为止,Opengl窗口所做的只是在窗口的右下角渲染纹理 如果我真的从左向右快速调整窗口大小,纹理有时会向左移动,这就好像它的重新绘制速度不够快,甚至不知道im直接绘制到opengl上下文 我解决这个问题的唯一方法是在主窗口调整大小时使opengl窗口的设置无效,但我不确定为什么会解决这个问题,因为我是在opengl上下文中绘制的,所以我不需要在绘制到上下文后使它自己绘制 如果C++ Opengl纹理有时会在调整窗口大小时闪烁/移动,c++,winapi,opengl,C++,Winapi,Opengl,我有个小问题 我有一个带有OpenGL子窗口的窗口, 到目前为止,Opengl窗口所做的只是在窗口的右下角渲染纹理 如果我真的从左向右快速调整窗口大小,纹理有时会向左移动,这就好像它的重新绘制速度不够快,甚至不知道im直接绘制到opengl上下文 我解决这个问题的唯一方法是在主窗口调整大小时使opengl窗口的设置无效,但我不确定为什么会解决这个问题,因为我是在opengl上下文中绘制的,所以我不需要在绘制到上下文后使它自己绘制 如果bHandled为false,则调用defWndProc,否则
bHandled
为false,则调用defWndProc,否则返回函数
主窗口WM_大小
int ControllerMainWnd::OnSize(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
bHandled = true;
int width = LOWORD(lParam);
int height = HIWORD(lParam);
//Set OpenGL Window Size
::SetWindowPos(glHandle, 0, 0, 0, width, height, SWP_NOZORDER);
//Invalidate OpenGL Window
::InvalidateRect(glHandle, 0, FALSE); // if i comment this out my texture sometime moves
return 0;
}
OpenGL窗口
int ControllerGL::OnPaint(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
//bHandled = true;
//LRESULT lRes = defWinProc(WM_PAINT, wParam, lParam);
Paint();
//return lRes;
return 0;
}
int ControllerGL::OnSize(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
bHandled = true;
int width = LOWORD(lParam);
int height = HIWORD(lParam);
modelGL->setWindowSize(width, height);
Paint();
return 0;
}
int ControllerGL::OnEraseBkgnd(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
bHandled = true;
return 1L;
}
auto ControllerGL::Paint() -> void
{
openGLcontext->activateContext();
modelGL->draw();
openGLcontext->swapBuffers();
}
您的问题可能与这样一个事实有关,即每次在调整大小期间移动鼠标时,都会导致窗口重新绘制2次 首先,当您调整窗口区域的大小时,Windows会自动使其无效(您可以使用类样式CS_HREDRAW和CS_VREDRAW来控制这一点,该类样式应始终为OpenGL窗口设置,因为调整大小通常需要完整的窗口重画) 然后(冗余地)手动使窗口rect无效。然后,您强制它进行绘制-未来的绘制现在已排队 OpenGL窗口的OnPaint处理程序实际上应该如下所示:
int ControllerGL::OnPaint(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd,&ps);
wglMakeCurrent(hdc,hglrc);
scene->Display();
SwapBuffers(hdc);
wglMakeCurrent(hdc,NULL);
EndPaint(hwnd,&ps);
bHandled = true;
return 0;
}
我把它留作一个适当封装hwnd和hglrc的练习,以这种方式编写它可以明确地告诉您SwapBuffers在DC上工作,而不是在隐式OpenGL上下文上,并且wglMakeCurrent应该使用动态获取的窗口DC来确定范围
大多数OpenGL示例都非常懒惰,使用一个DC类,只是让OpenGL内容始终处于“活动”状态,但一旦线程上的两个窗口尝试执行OpenGL,就会失败。最好省略C_-OWNDC(如果您有)并在实际需要时获取(并释放)DC
i、 e.如果您想更传统地处理WM_大小(类似于glut重塑回调),您可以这样做:
int ControllerGL::OnSize(WPARAM wParam, LPARAM lParam, bool & bHandled)
{
bHandled = true;
int width = LOWORD(lParam);
int height = HIWORD(lParam);
HDC hdc = GetDC(hwnd);
wglMakeCurrent(hdc,hglrc);
scene->Reshape(width,height);
wglMakeCurrent(hdc,NULL);
ReleaseDC(hwnd,hdc);
return 0;
}
从
ControllerGL
到我称之为scene
和您调用modelGL
的每一次调用都会被类似地包装。当您从未验证它时,为什么还要麻烦调用invalidate
?该区域在代码中始终无效。不需要告诉系统,它已经知道了什么。除非您开始验证无效区域。已经有了。因为如果不改变窗口大小,当窗口调整得非常快时,纹理会移动/闪烁一点。所以我问为什么更明确-始终在WM_-PAINT
处理程序中使用BeginPaint
和EndPaint
-这是验证无效区域所必需的-并正确剪裁到要更新的区域。@ChrisBecke im使用openGl上下文而不是windows api绘制。所以我仍然需要使用beginPaint?你不需要,但你应该验证无效区域,以防止你的应用程序收到持续不断的WM_PAINT
消息流。