创建一个基本的 OpenGL 上下文

Posted

技术标签:

【中文标题】创建一个基本的 OpenGL 上下文【英文标题】:Creating a basic OpenGl context 【发布时间】:2014-06-01 21:01:44 【问题描述】:

我正在阅读 OpenGL 红皮书,但我几乎被第一个教程所困。如果我使用 freeglut 和 glew,一切正常,但我想自己处理输入等。所以我放弃了 freeglut 并开始编写自己的代码。我查看了其他一些教程并完成了代码,但没有显示任何内容。似乎 FreeGlut 在后台做了一些巫术魔法,但我不知道我错过了什么。我试过这个:

int attributeListInt[19];
int pixelFormat[1];
unsigned int formatCount;
int result;
PIXELFORMATDESCRIPTOR pixelFormatDescriptor;
int attributeList[5];

context = GetDC (hwnd);
if (!context)
    return -1;

attributeListInt[0] = WGL_SUPPORT_OPENGL_ARB;
attributeListInt[1] = TRUE;
attributeListInt[2] = WGL_DRAW_TO_WINDOW_ARB;
attributeListInt[3] = TRUE;
attributeListInt[4] = WGL_ACCELERATION_ARB;
attributeListInt[5] = WGL_FULL_ACCELERATION_ARB;
attributeListInt[6] = WGL_COLOR_BITS_ARB;
attributeListInt[7] = 24;
attributeListInt[8] = WGL_DEPTH_BITS_ARB;
attributeListInt[9] = 24;
attributeListInt[10] = WGL_DOUBLE_BUFFER_ARB;
attributeListInt[11] = TRUE;
attributeListInt[12] = WGL_SWAP_METHOD_ARB;
attributeListInt[13] = WGL_SWAP_EXCHANGE_ARB;
attributeListInt[14] = WGL_PIXEL_TYPE_ARB;
attributeListInt[15] = WGL_TYPE_RGBA_ARB;
attributeListInt[16] = WGL_STENCIL_BITS_ARB;
attributeListInt[17] = 8;
attributeListInt[18] = 0;

result = wglChoosePixelFormatARB (context, attributeListInt, NULL, 1, pixelFormat, &formatCount);
if (result != 1)
    return -1;

result = SetPixelFormat (context, pixelFormat[0], &pixelFormatDescriptor);
if (result != 1)
    return -1;
attributeList[0] = WGL_CONTEXT_MAJOR_VERSION_ARB;
attributeList[1] = 4;
attributeList[2] = WGL_CONTEXT_MINOR_VERSION_ARB;
attributeList[3] = 2;
attributeList[4] = 0;

rendercontext = wglCreateContextAttribsARB (context, 0, attributeList);
if (rendercontext == NULL)
    return -1;

result = wglMakeCurrent (context, rendercontext);
if (result != 1)
    return -1;

glClearDepth (1.0f);
glFrontFace (GL_CCW);
glEnable (GL_CULL_FACE);
glCullFace (GL_BACK);

return 0;

这设置了一个图形上下文,但显然不足以使一切正常工作。本教程没有包含有关视图或投影矩阵的任何内容,因此我不确定是否应该添加类似的内容。但是窗口仍然是黑色的。

这是教程代码,调整为我的代码:

#define BUFFER_OFFSET(offset) ((void *)(offset))

bool init ();
bool mainloop ();

enum VAO_IDs  Triangles, NumVAOs ;
enum Buffer_IDs  ArrayBuffer, NumBuffers ;
enum Attrib_IDs  vPosition = 0 ;
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
const GLuint NumVertices = 6;

int main (int argc, char** argv)

    Window w;

    w.init (&mainloop);
    if (!init ())
        return 0;

    w.run ();
    w.shutdown ();

    return 0;


bool init ()

    glGenVertexArrays (NumVAOs, VAOs);
    glBindVertexArray (VAOs[Triangles]);
    GLfloat vertices[NumVertices][2] = 
        -0.90f, -0.90f, // Triangle 1
        0.85f, -0.90f,
        -0.90f, 0.85f,
        0.90f, -0.85f, // Triangle 2
        0.90f, 0.90f,
        -0.85f, 0.90f
    ;

    glGenBuffers (NumBuffers, Buffers);
    glBindBuffer (GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData (GL_ARRAY_BUFFER, sizeof(vertices),
        vertices, GL_STATIC_DRAW);
    ShaderInfo shaders[] = 
        GL_VERTEX_SHADER, "triangles.vert",
        GL_FRAGMENT_SHADER, "triangles.frag",
        GL_NONE, NULL
    ;

    GLuint program = LoadShaders (shaders);
    glUseProgram (program);
    glVertexAttribPointer (vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET (0));
    glEnableVertexAttribArray (vPosition);

    return true;


bool mainloop ()

    glClear (GL_COLOR_BUFFER_BIT);
    glBindVertexArray (VAOs[Triangles]);
    glDrawArrays (GL_TRIANGLES, 0, NumVertices);
    glFlush ();

    return true;

【问题讨论】:

一方面,您的三角形是逆时针缠绕的,而正面设置为顺时针。通过剔除背面(逆时针),您将看不到任何东西。将正面更改为 CCW、剔除正面或禁用剔除。 @AndonM.Coleman 我已将其更改为 CCW,但它仍然没有显示任何内容。 我不认为自己做所有事情是一个特别合理的解决方案。那样你不会学得更快。 此外,您有一个双缓冲上下文,但不是交换缓冲区(这是必要的,并且 隐式 调用 glFlush (...) 或 @ 987654324@ 取决于您使用的是硬件 ICD 还是 GDI),您调用了glFlush (...)。将其替换为SwapBuffers () 并将| GL_DEPTH_BUFFER_BIT 添加到您的glClear (...) 调用中(因为您有像素格式的深度缓冲区)。您不必清除深度缓冲区,因为默认情况下禁用了深度测试,但如果您启用深度测试,那么事情将开始写入深度缓冲区。 @AndonM.Coleman 我已经禁用了深度缓冲区,现在使用 SwapBuffers 一切正常,谢谢! 【参考方案1】:

创建 OpenGL 上下文并非易事。尤其是如果您想使用必须通过 OpenGL 扩展机制加载的wglChoosePixelFormatARB...首先需要一个正常工作的 OpenGL 上下文才能工作。我想你明白这是一个先有鸡还是先有蛋的问题。此外,用于创建 OpenGL 上下文的 Window 需要某些属性才能可靠地工作。一方面,WndClass 应该设置 CS_OWNDC 样式,并且窗口样式应该包括 WS_CLIPSIBLINGS | WS_CLIPCHILDREN

我最近使用我的小型 wglarb 辅助工具解决了上述先有鸡还是先有蛋的问题:https://github.com/datenwolf/wglarb

它还附带一个小测试程序,展示如何使用它。

我建议你使用它提供的功能。我以某种方式编写了这个小助手库,如果您的程序使用其他扩展加载机制,它不会受到负面影响。 但是它还不是线程安全的;我最终将不得不添加它。 我花时间使代码线程安全。您现在可以使用公开的功能而不必关心同步;这一切都是在内部以可靠的方式完成的。

【讨论】:

以上是关于创建一个基本的 OpenGL 上下文的主要内容,如果未能解决你的问题,请参考以下文章

有效的 OpenGL 上下文

带有 QT 错误的 OpenGL:断言:“QOpenGLFunctions::isInitialized(d_ptr)”。无法创建 OpenGL 上下文

如何使用 fltk 1.3 创建 opengl 3.x 或 4.x 上下文?

创建跨平台 OpenGL 离屏上下文

GtKGLArea 无法创建 OpenGL 2.1 上下文

带有 OpenGL 上下文的基于 Qt 的命令行工具