OpenGL VBO 没有正确更新

Posted

技术标签:

【中文标题】OpenGL VBO 没有正确更新【英文标题】:OpenGL VBO not updating properly 【发布时间】:2012-03-04 13:50:12 【问题描述】:

我遇到了 OpenGL VBO 问题。我从 NeHe 下载了名为 Lesson45 的旧 VBO 示例,并对其进行了修改以进行检查。

我的最终结果是创建了大约 9 个图块,其中一个是原点。然后当玩家在屏幕上移动时,顶部/底部的行/列会更新数据。但现在我想要一些基本的东西:

我创建了一个 VBO,然后我想在另一个线程中更新数据。在上传数据时,我不想绘制 VBO,因为那样会导致问题。

我在这里创建 VBO:

glGenBuffersARB( 1, &m_nVBOVertices );
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_nVBOVertices);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices, GL_DYNAMIC_DRAW_ARB);

我创建了一个线程,我设置了一个 OpenGL 上下文,我共享列表。然后我处理数据,当用户在键盘上按“R”时:

    while(TerrainThreadRun)
    
        //look for R
        if(window.keys->keyDown[82] == TRUE && keyactivated == false)
        
            keyactivated = true;
            window.keys->keyDown[82] = FALSE;
        

        if(keyactivated)
        
            for(int i = 0; i < g_pMesh->m_nVertexCount; i++)
            
                g_pMesh->m_pVertices[i].y = 800.0f;
            
            while(!wglMakeCurrent(window.hDCThread,window.hRCThread))//This was removed
                Sleep(5);//This was removed
            glBindBufferARB(GL_ARRAY_BUFFER_ARB, g_pMesh->m_nVBOVertices);      
            glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, g_pMesh->m_nVertexCount*3*sizeof(float), g_pMesh->m_pVertices);
            keyactivated = false;
        
    

绘制数据:

if(!keyactivated)

    glEnableClientState( GL_VERTEX_ARRAY );

    glBindBufferARB(GL_ARRAY_BUFFER_ARB, g_pMesh->m_nVBOVertices);
    glVertexPointer(3, GL_FLOAT, 0, (char*)NULL);


    glDrawArrays(GL_TRIANGLES, 0, g_pMesh->m_nVertexCount);

    glDisableClientState(GL_VERTEX_ARRAY);

我知道不推荐使用 ARB 扩展,但这只是一个简单的基本示例。

问题是当我第一次按“R”时,数据没有得到更新。 VBO 绘制相同。我第二次按“R”,它会更新数据。我能做些什么来强制平局。我做错了吗?

数据需要强制到显卡吗?我错过了什么吗?

更新:我查看了我的代码,现在我只使用 wglMakeCurrent 一次,当上下文初始化时。在线程中,我在共享列表后使用它,并在共享列表后立即在主线程上使用它,如下所示:

window->hRC = wglCreateContext (window->hDC);
if (window->hRC ==0)

    // Failed


TerrainThreadRun = true;
TerrainThread = CreateThread(NULL, NULL,(LPTHREAD_START_ROUTINE)TerrainThreadProc, 0, NULL, NULL);

while(!sharedContext)
    Sleep(100);

if (wglMakeCurrent (window->hDC, window->hRC) == FALSE)

在线程中:

    if (!(window.hRCThread=wglCreateContext(window.hDCThread)))
    
//Error
    

while(wglShareLists(window.hRC, window.hRCThread) == 0)

    DWORD err = GetLastError();
    Sleep(5);

sharedContext = true;
int cnt = 0;

while(!wglMakeCurrent(window.hDCThread,window.hRCThread))
    Sleep(5);
while(TerrainThreadRun)

    //look for R

第二次更新:我尝试使用 glMapBuffer 而不是 glBuferSubData,但应用程序的行为相同。代码如下:

        void *ptr = (void*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_READ_WRITE_ARB);
        if(ptr)
        
            memcpy(ptr, g_pMesh->m_pVertices, g_pMesh->m_nVertexCount*3*sizeof(float));
            glUnmapMapBuffer(GL_ARRAY_BUFFER_ARB);
        

更新三:

我做错了一些事情,所以我修改了它们,但问题仍然存在。这是我现在做所有事情的方式:

当应用程序加载时,我创建了两个窗口,每个窗口都有自己的 HWND。基于它们,我创建了两个设备上下文。

然后我分享他们之间的列表:

wglShareLists(window.hRC, window.hRCThread);

这仅在我初始化时执行一次。 之后,我显示了 OGL 窗口,它呈现;我使上下文处于活动状态。然后我加载函数指针并创建 VBO。 主渲染 OGL 完成后,我创建线程。加载线程后,我将其设备上下文激活。

然后我们做正常的事情。

所以我的问题是:我需要更新每个设备上下文的函数指针吗?这可能是我的问题吗?

作为更新,如果我在 gDEBugger 中运行我的测试应用程序,然后我先按“R”然后暂停,它不会正确显示。我看一下内存(纹理、缓冲区和图像查看器)和 GLContext1(我认为是主渲染线程)设备上下文具有 OLD 数据。而 GLContext2 (Shared-GL1) (我认为线程上下文)具有正确的数据。

奇怪的是,如果我回顾 GLContext1,程序仍处于暂停模式,现在它会显示新数据,就像它以某种方式“刷新”它一样。然后如果我按下播放键,它就会开始正确绘制。

【问题讨论】:

【参考方案1】:

我找到了解决办法,我需要在调用glUnmapBuffer之后在工作线程中调用glFinish()。这将解决问题,一切都会很好地呈现。

【讨论】:

以上是关于OpenGL VBO 没有正确更新的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL:用 VBO 画线

慢跑。 OpenGL。如何更新 VBO?

OpenGL - 错误地创建多个 VBO

OpenGL 更新不同大小的 VBO 数据

切换到使用交错 VBO - 编译但没有绘制 - opengl es 2.0

在OpenGL中实现VBO,窗口保持黑色