OpenGL闪烁?

Posted

技术标签:

【中文标题】OpenGL闪烁?【英文标题】:OpenGL Flashing? 【发布时间】:2015-07-25 07:36:47 【问题描述】:

我试图在 OpenGL 中绘制一些文本,而程序绘制一个立方体或任何 Opengl 本机,因此,当我尝试将文本放在屏幕上时,它闪烁得非常快,我不知道为什么,我试图改变睡眠值,什么都没有……

代码如下; here is a GIF showing the problem.

绿色背景是立方体,摄像头离背景很近,可以用NUM_2向后移动。

#include <windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include "default.h"

using namespace std;

LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
DWORD WINAPI WorkLoop(LPVOID PARAMS);
void keyScan (MSG msg, Camera cam);

HDC hDC;
HGLRC hRC;
HWND hwnd;

RECT WBounds;


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

    WNDCLASSEX wcex;
    MSG msg;
    BOOL bQuit = FALSE;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_OWNDC;
    wcex.lpfnWndProc = WindowProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = "GLSample";
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);;
    Screen ();

    if (!RegisterClassEx(&wcex))
        return 0;


    hwnd = CreateWindowEx(0,
                          "GLSample",
                          "OpenGL Testing",
                          WS_OVERLAPPEDWINDOW,
                          Scr.sx/2-630,
                          Scr.sy/2-450,
                          1260,
                          900,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    GetClientRect(hwnd, &WBounds);

    ShowWindow(hwnd, nCmdShow);
    EnableOpenGL(hwnd, &hDC, &hRC);  ///ENABLE OPENGL

    Camera cam = Camera (0, 0, -1);

    CreateThread(0, 0x1000, &WorkLoop, 0, 0, 0);

    while (!bQuit)
    
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        
            if (msg.message == WM_QUIT) bQuit = TRUE;
            else
            
                keyScan (msg, cam);
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            
        
        else
        
            renderSimulation (cam);
            SwapBuffers (hDC);
        
        Sleep(1);
    

    DisableOpenGL(hwnd, hDC, hRC);
    DestroyWindow(hwnd);
    return msg.wParam;


DWORD WINAPI WorkLoop(LPVOID PARAMS)

    while (true)
    
        InvalidateRect(hwnd, &WBounds, true);
        Sleep(33);
    
    ExitThread(0);



float x = 0.0f, y = 0.0f, z = 0.0f;
float rx = 0.0f, ry = 0.0f, rz = 0.0f;
char* textas = "test";

void keyScan (MSG p, Camera cam)

    if (p.message == WM_KEYDOWN)
    
        if (p.wParam == ARROW_RIGHT)      x += 0.1; cam.SetCameraPosition (x, y, z);
        else if (p.wParam == ARROW_LEFT)  x -= 0.1; cam.SetCameraPosition (x, y, z);
        else if (p.wParam == ARROW_UP)    y += 0.1; cam.SetCameraPosition (x, y, z);
        else if (p.wParam == ARROW_DOWN)  y -= 0.1; cam.SetCameraPosition (x, y, z);
        else if (p.wParam == NUM_8)       z += 0.1; cam.SetCameraPosition (x, y, z);
        else if (p.wParam == NUM_2)       z -= 0.1; cam.SetCameraPosition (x, y, z);
        else if (p.wParam == L)           SetFullScreen (p.hwnd, hDC, hRC);
        else if (p.wParam == K)           textas = "cambiado";
    


HFONT Font = CreateFont(40, 0, 0, 0,FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, FF_MODERN, TEXT("Arial"));
HPEN BoxPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
HPEN OutlinePen = CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
HPEN CHPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
HBRUSH CHBrush = CreateSolidBrush(RGB(0, 255, 0));

void drawtext(HDC hdc, int x, int y, const char * text)

    SetBkMode (hdc, TRANSPARENT);
    SetTextColor(hdc, RGB(0, 255, 0));
    SetBkColor(hdc, RGB(255, 255, 255));
    TextOutA(hdc, x, y, text, strlen(text));


/*void Draw(HDC hdc, int x, int y, float dist)

    int width = 20000 / dist;
    int height = 45000 / dist;
    SelectObject(hdc, OutlinePen);
    SelectObject(hdc, WHITE_BRUSH);
    Rectangle(hdc, x - (width / 2), y - height, x + (width / 2), y);
    SelectObject(hdc, BoxPen);
    Rectangle(hdc, x - (width / 2), y - height, x + (width / 2), y);
    SetTextAlign(hdc, TA_CENTER | TA_NOUPDATECP);
    std::stringstream ss2;
    ss2 << "Dist: " << dist << " m";
    drawtext(hdc, x, y + 90, ss2.str().c_str());
*/

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

    switch (uMsg)
    
        case WM_PAINT:
        
            int win_width = WBounds.right - WBounds.left;
            int win_height = WBounds.bottom + WBounds.left;
            PAINTSTRUCT ps;
            HDC Memhdc;
            HDC hdc;
            HBITMAP Membitmap;
            hdc = BeginPaint(hwnd, &ps);
            Memhdc = CreateCompatibleDC (hdc);
            Membitmap = CreateCompatibleBitmap (hdc, win_width, win_height);
            SelectObject (Memhdc, Membitmap);
            //FillRect (Memhdc, &WBounds, WHITE_BRUSH);
            SelectObject (Memhdc, Font);
            SetTextAlign (Memhdc, TA_LEFT | TA_NOUPDATECP);
            drawtext(Memhdc, 100, 100, textas);

            //Draw (Memhdc, 20, 50, 90.0);

            /*SelectObject(Memhdc, CHPen);
            SelectObject(Memhdc, CHBrush);*/

            BitBlt (hdc, 0, 0, win_width, win_height, Memhdc, 0, 0, SRCCOPY);
            DeleteObject(Membitmap);
            DeleteDC(Memhdc);
            DeleteDC(hdc);
            EndPaint(hwnd, &ps);
            ValidateRect(hwnd, &WBounds);
        
        case WM_KEYDOWN:
        
            switch (wParam)
            
                case VK_ESCAPE:
                    PostQuitMessage(0);
            
        
        case WM_ERASEBKGND:
            return 1;
        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    
    return 0;

【问题讨论】:

【参考方案1】:

你的程序有两个问题:

    为 OpenGL 窗口设置背景画笔将使操作系统在发送 WM_PAINT(在此基础上使用 OpenGL 过度绘制)之前使用画笔明显清除窗口。通过使用 InvalidateRect,您将在 WM_PAINT 之前触发此带有背景的擦除

    双缓冲 OpenGL 像素格式和使用 GDI 绘图不能很好地结合在一起。如果要绘制文本,则必须以不同的方式进行。例如,绘制到 DIBSECTION DC,然后使用纹理四边形绘制该位图。或者使用针对 OpenGL(FTGL、Glyphy 等)的字体光栅化器。

【讨论】:

以上是关于OpenGL闪烁?的主要内容,如果未能解决你的问题,请参考以下文章

启用 DEPTH_TEST 时 OpenGL 屏幕闪烁

OpenGL 闪烁/损坏,窗口调整大小和 DWM 处于活动状态

如何在opengl中以特定频率闪烁(轻弹)2d对象

OpenGl和闪烁

OpenGL奇怪的渲染行为(闪烁的面孔)

OpenGL闪烁并且比C ++更多