使用OpenGL绘制三角形:如何使用两个类进行管理

Posted

技术标签:

【中文标题】使用OpenGL绘制三角形:如何使用两个类进行管理【英文标题】:Triangle drawing with OpenGL: how to manage with two classes 【发布时间】:2016-04-30 12:32:16 【问题描述】:

我对这段代码有疑问。没有错误或警告,但仅在调整窗口大小时会出现三角形。

我需要纠正这个问题。头文件包含这两个类:Window 和 WindowGL(基于类的继承)。这段代码有什么问题?

#ifndef OPENGL_H
#define OPENGL_H
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

class Window

protected:
    HWND hwnd;
    long clientWidh;
    long clientHeight;
public:
    Window() :hwnd(NULL);
    LRESULT WndProc(HWND , UINT , WPARAM , LPARAM );
    bool Initialize(HINSTANCE appHandle, POINT windowPosition, POINT windowSize);
    WPARAM Run();
;

class WindowGL : public Window

private:
    HGLRC handleRC;
    HDC handleDC;
    bool InitWGL(HWND hwnd);
    void DestroyWGL();
    void SetScene(bool isometricProjection);
    void Render();
public:
    WindowGL() :Window(), handleRC(NULL), handleDC(NULL);
    LRESULT WndProc(HWND, UINT , WPARAM, LPARAM );
    bool SetPixels(HDC) const;
window;

#endif

还有.cpp文件:

#include "myHeaderGL.h"
#include <cstdlib>
#include <gl/GL.h>
#include <gl/GLU.h>// not used in this example

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    return window.WndProc(hWnd, message, wParam, lParam);


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

    POINT windowPosition =  100, 100 ;
    POINT windowSize =  800, 600 ;
    if (!window.Initialize(hInstance, windowPosition, windowSize))
    
        MessageBox(NULL, "Initialisation fail.", "OpenGL Application", MB_OK | MB_ICONERROR);
        return EXIT_FAILURE;
    
    else return window.Run();



LRESULT Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    switch (message)
    
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_PAINT:
        RECT rect;
        GetClientRect(hWnd, &rect);
        clientWidh = rect.right - rect.left;
        clientHeight = rect.bottom - rect.top;
        break;
    default:
        return(DefWindowProc(hWnd, message, wParam, lParam));
    
    return 0L;


LRESULT WindowGL::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    long result = Window::WndProc(hWnd, message, wParam, lParam); 
    switch (message)
    
    case WM_CREATE:
        if (!InitWGL(hWnd))
        
            MessageBox(NULL, "Render context fail to load", "My OpenGL", MB_OK | MB_ICONERROR);
            return EXIT_FAILURE;
        
        SetScene(false);
        break;
    case WM_DESTROY:
        DestroyWGL();
        break;
    case WM_SIZE:
        SetScene(false);
        break;
    case WM_PAINT:
        Render();
        ValidateRect(hWnd, NULL);
        break;
    //default: 
        //return (DefWindowProc(hWnd, message, wParam, lParam));
    
    return result;


bool Window::Initialize(HINSTANCE appHandle, POINT windowPosition, POINT windowSize)

    char windowName[] = "My 1 OpenGL";

    WNDCLASSEX wc;
    wc.cbSize = sizeof(wc);
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 
    wc.lpfnWndProc = (WNDPROC)::WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = appHandle; 
    wc.hIcon = NULL; 
    wc.hIconSm = NULL; 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = NULL; 
    wc.lpszMenuName = NULL;
    wc.lpszClassName = windowName; 

    if (RegisterClassEx(&wc) == 0) return false;

    hwnd = CreateWindow(
        windowName,
        windowName,
        WS_OVERLAPPEDWINDOW,
        windowPosition.x, windowPosition.y,
        windowSize.x, windowSize.y,
        NULL,
        NULL,
        appHandle,
        NULL
        );
    if (!hwnd) return false;

    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);

    return true;


WPARAM Window::Run()

    MSG msg = 0;
    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
    
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    
    else
    
        window.Render();
    
    return msg.wParam;


bool WindowGL::SetPixels(HDC handleDC) const

    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory(&pfd, sizeof(pfd));
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 32;
    pfd.cDepthBits = 32;
    pfd.iLayerType = PFD_MAIN_PLANE;
    int pixFormat = ChoosePixelFormat(handleDC, &pfd);
    if (pixFormat == 0) return false;
    if (!SetPixelFormat(handleDC, pixFormat, &pfd)) return false;

    return true;


bool WindowGL::InitWGL(HWND hwnd)

    handleDC= ::GetDC(hwnd);
    if (!SetPixels(handleDC)) return false;

    handleRC = wglCreateContext(handleDC);
    if (handleRC == NULL) return false;
    if (!wglMakeCurrent(handleDC, handleRC)) return false;
    return true;


void WindowGL::SetScene(bool isometricProjection)

    glViewport(0, 0, clientWidh, clientHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    float wsp = clientHeight / (float)clientWidh;
    if (!isometricProjection)
        glFrustum(-1.0f, 1.0f, wsp*-1.0f, wsp*1.0f, 1.0f, 10.0f);
    else
        glOrtho(-1.0f, 1.0f, wsp*-1.0f, wsp*1.0f, 1.0f, 10.0f);

    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_DEPTH_TEST);


void WindowGL::DestroyWGL()

    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(handleRC);
    ::ReleaseDC(hwnd, handleDC);


void WindowGL::Render()

    const float x0 = 1.0f;
    const float y0 = 1.0f;
    const float z0 = 1.0f;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -3.0f);
    glColor4f(1.0f, 1.0f, 0.0f, 1.0f);

    glBegin(GL_TRIANGLES);
        glVertex3f(-x0, -y0,  0.0f); 
        glVertex3f( x0, -y0,  0.0f);
        glVertex3f(0.0f, y0,  0.0f);
    glEnd();

    SwapBuffers(handleDC); 

【问题讨论】:

【参考方案1】:

您仅在发送WM_PAINT 时才调用Render(),请尝试每隔几毫秒在Run() 中调用它一次。 使用 PeekMessage 更改 GetMessage 以防止代码停滞,然后仅在有要读取的消息时使用 GetMessage。

编辑

while(msg.message != WM_QUIT)

    if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
    
         TranslateMessage(&msg);
         DispatchMessage(&msg);
    
    Render();
    sleep(10); // If you don't want to update the screen too fast

编辑 2

LRESULT Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    switch (message)
    
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_SIZE || WM_PAINT: // <- the problem was here
        RECT rect;
        GetClientRect(hWnd, &rect);
        clientWidh = rect.right - rect.left;
        clientHeight = rect.bottom - rect.top;
        break;
    default:
        return(DefWindowProc(hWnd, message, wParam, lParam));
    
    return 0L;

【讨论】:

抱歉。我已经更新了 Run() 函数。但仍然是同样的问题。不改变窗口大小就没有三角形。 我编辑了代码,它应该给你正确的想法。 是的,我之前编辑了上面的代码 - 并用“更好的”函数 PeekMessage() 更改了 Run() 但仍然没有效果。头类是这样构建的,我什至不能在 Run() 中调用 Render()。相反,我可以调用:window. Render() 但它不会改变任何东西。代码来自物理学家写的书,但作者没有提供源代码。你能试着在你的机器上编译这些东西吗?感谢您的帮助。 非常感谢您 FedeWar。我检查了我的书,发现了什么?有一个错误。我可能会把它寄回商店。再次感谢,我该如何奖励您? 不客气,奖励我选择这个答案为最佳。

以上是关于使用OpenGL绘制三角形:如何使用两个类进行管理的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL:使用退化三角形绘制线

如何将OpenGL绘图分成类

绘制三角形带时,啥控制 OpenGL 的行为?

使用 VBO/IBO 的 OpenGL 纹理三角形

OpenGL学习——绘制三角形

无法在opengl中绘制多个对象