基于Visual C++单文档OpenGL多线程-结合VBO编程框架

Visual C++单文档OpenGL框架详见:https://blog.csdn.net/qq_34911636/article/details/86666112

一般而言OpenGL绘制图像的函数大多数在单文档程序的OnDraw函数内部实现,但是在绘制复杂图像或者像素点比较多

时会出现严重的卡顿现象,为了解决绘制复杂图像卡顿问题,本文以在三维空间中显示点为例子,利用多线程-结合VBO

编程的方式改善性能。

1、多线程框架的搭建,OpenGL初始化代码如下:

if (!SetupPixelFormat(pdc))//检测安装OpenGL
    {
        MessageBox(NULL, _T("SetPixelFormat failed"), _T("Error"), MB_OK);
        return FALSE;
    }

    /*GetPixelFormat函数是获取当前DC的像素索引值,函数SetupPixelFormat,设置了一个像素格式,它就有了一个自己的索引值通过这个函数GetPixelFormat,可以获得它的索引值并赋给n*/
    n = ::GetPixelFormat(pdc->GetSafeHdc());

    /*DescribePixelFormat函数是描述像素格式,获得索引之后要向设备描述你的像素格式,这样设备才会按照你的像素格式绘图*/
    ::DescribePixelFormat(pdc->GetSafeHdc(), n, sizeof(pfd), &pfd);

    /*WglCreateContext函数创建一个新的OpenGL渲染描述表,此描述表必须适用于绘制到由hdc返回的设备.这个渲染描述表将有和设备上下文(dc)一样的像素格式*/
    m_hRC = wglCreateContext(pdc->GetSafeHdc());  //m_hRC是设备的主渲染描述符
    m_SharehRC = wglCreateContext(pdc->GetSafeHdc()); //m_SharehRC为共享渲染描述符,共享主渲染描述符m_hRC
    //这边多线程显示,Opengl每一时刻只允许一个线程渲染,不允许多个线程共同渲染,所以这边只能通过共享的方式共享主渲染表    
    if (m_hRC == NULL)
    {
        return FALSE;
    }

    /*这边多线程显示,Opengl每一时刻只允许一个线程渲染,不允许多个线程共同渲染,所以这边只能通过共享的方式共享主渲染表wglShareLists函数设置共享渲染表,wglShareLists(HGLRC hglrc1, HGLRC hglrc2)其中参数hglrc1提供共享资源的render context参数hglrc2共享参数hglrc1提供的资源*/
    wglShareLists(m_hRC, m_SharehRC);

上述代码中红色字体为OpenGL初始化代码,而蓝色字体为注解

上述的代码核心是创建两个设备的渲染描述符分别为m_hRC、m_SharehRC,其中m_hRC为主描述符,而m_SharehRC是分享

主描述符m_hRC的描述符。

2、创建两个线程

  在单文档初始化程序设置线程

    m_ProcessingThread1 = AfxBeginThread(CallbackProcessing1, m_ClientDC, 0, 0, CREATE_SUSPENDED); //创建线程1
    m_ProcessingThread2 = AfxBeginThread(CallbackProcessing2, m_ClientDC, 0, 0, CREATE_SUSPENDED); //创建线程2

    m_ProcessingThread1->ResumeThread();  //启动线程
    m_ProcessingThread2->ResumeThread();   //启动线程

其中UINT CallbackProcessing1(LPVOID pParam)为线程回调函数1

UINT CallbackLidarProcessing(LPVOID pParam)

{

       while(true)

       {

   /*wglMakeCurrent函数设定OpenGL当前线程的渲染环境,使一个指定的OpenGL渲染上下文调用线程的当前呈现上下文
    OpenGL只允许当前一个线程拥有渲染环境,若wglMakeCurrent函数返回FALSE则说明其他线程已占有渲染环境,如果
   返回TRUE则成功的设置当前的线程为渲染环境*/

            if (wglMakeCurrent(Pdc->GetSafeHdc(), m_OpenGL->m_hRC) == TRUE)
             {
                    glewInit();
//初始化VBO缓冲区,前提必须启动函数glewInit初始化,否则无法初始化
                    GLuint vboid;

                    glGenBuffers(1, &vboid); //创建顶点缓冲区对象
                    glBindBuffer(GL_ARRAY_BUFFER, vboid); //将顶点缓冲区对象设置为当前数组缓冲区对象
                    glBufferData(GL_ARRAY_BUFFER, sizeof(m_Pointdata), m_Pointdata, GL_DYNAMIC_DRAW); /*为顶点缓冲区对        象申请内存空间,并进行初始化,其中m_Pointdata要显示的顶点数组*/

                    m_OpenGL->vboid = vboid //把VBO对象标识vboid存储在全局变量m_OpenGL->vboid中供后续使用
                    m_ThreadProcessing2++;
    /*当该线程创建VBO结束或者当前绘图结束时记得要释放当前渲染环境,若没有释放渲染环境则在其他线程就没办法获取

     渲染环境操作*/
                     wglMakeCurrent(NULL, NULL);//释放渲染环境
             }

       }

}

注解:在上面CallbackLidarProcessing例程只是一个示例,里面VBO的初始化只要一次就行,但这部的代码会处于不断循环,真正运行此段代码需要修改,若想实时的改变数组m_Pointdata的显示内容可以采用VBO的glMapBuffer函数修改内存数据,从而改变显示内容。

///

其中UINT CallbackProcessing2(LPVOID pParam)为线程回调函数2

UINT CallbackProcessing2(LPVOID pParam)
{
    CClientDC *Pdc = (CClientDC *)(pParam);
//创建线程函数AfxBeginThread传递CClientDC指针
    while (true)
    {
      
 /*wglMakeCurrent函数设定OpenGL当前线程的渲染环境,使一个指定的OpenGL渲染上下文调用线程的当前呈现上下文
        OpenGL只允许当前一个线程拥有渲染环境,若wglMakeCurrent函数返回FALSE则说明其他线程已占有渲染环境,如果
        返回TRUE则成功的设置当前的线程为渲染环境*/

        if (wglMakeCurrent(Pdc->GetSafeHdc(), m_OpenGL->m_SharehRC) == TRUE)
        {
            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//设置显示区域的背景色
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除原有的画面
            m_OpenGL->DisplayModeInit(); //显示方式初始化
            m_OpenGL->ViewAngle(); //设置视角
            m_OpenGL->DisplayGrid(); //画水平网格
            m_OpenGL->DisplayCoordinate(); //画坐标系
            m_OpenGL->DirectionLight(); //光照函数
            
            if (m_OpenGL->vboid != 0) //判断VBO对象是否有效
            {
                glBindBuffer(GL_ARRAY_BUFFER, m_OpenGL->vboid);
//关联已有的VBO对象
                glEnableClientState(GL_VERTEX_ARRAY); //打开顶点绘图
                glVertexPointer(3, GL_FLOAT, 0, 0); //设置顶点的格式
                glDrawArrays(GL_POINTS, 0, 3); //绘图
                glDisableClientState(GL_VERTEX_ARRAY); //关闭绘图
                glBindBuffer(GL_ARRAY_BUFFER, 0); //解除关联对象
            }    
            m_OpenGL->Point();
            

            glFlush(); //强制刷新绘图缓冲区
            SwapBuffers(wglGetCurrentDC()); //交换缓冲区,把已绘制完成的缓冲区的数据显示出来
            m_ThreadProcessing2++;
            wglMakeCurrent(NULL, NULL);
//释放渲染环境
        }
    }
    return 0;
}

上述代码通过主程序初始化OpenGL代码,并在主程序中创建两个线程,通过共享渲染描述符的方式两个线程分时

的获取绘图句柄,在线程1中负责数据的导入或修改等(通过VBO),在线程2中负责数据的显示,这种可以增强

系统渲染的实时性。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值