C++ Opengl纹理有时会在调整窗口大小时闪烁/移动

C++ Opengl纹理有时会在调整窗口大小时闪烁/移动,c++,winapi,opengl,C++,Winapi,Opengl,我有个小问题 我有一个带有OpenGL子窗口的窗口, 到目前为止,Opengl窗口所做的只是在窗口的右下角渲染纹理 如果我真的从左向右快速调整窗口大小,纹理有时会向左移动,这就好像它的重新绘制速度不够快,甚至不知道im直接绘制到opengl上下文 我解决这个问题的唯一方法是在主窗口调整大小时使opengl窗口的设置无效,但我不确定为什么会解决这个问题,因为我是在opengl上下文中绘制的,所以我不需要在绘制到上下文后使它自己绘制 如果bHandled为false,则调用defWndProc,否则

我有个小问题

我有一个带有OpenGL子窗口的窗口, 到目前为止,Opengl窗口所做的只是在窗口的右下角渲染纹理

如果我真的从左向右快速调整窗口大小,纹理有时会向左移动,这就好像它的重新绘制速度不够快,甚至不知道im直接绘制到opengl上下文

我解决这个问题的唯一方法是在主窗口调整大小时使opengl窗口的设置无效,但我不确定为什么会解决这个问题,因为我是在opengl上下文中绘制的,所以我不需要在绘制到上下文后使它自己绘制

如果
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
消息流。