zoukankan      html  css  js  c++  java
  • 在MFC框架中使用OpenGL的简单实例

    引言

      我们知道,在MFC框架中,用于绘图的接口是GDI。但GDI只能绘制简单的2D图形,要想制作精美的3D图形,一个可行的办法是使用OpenGL或者Direct3D等第三方库。

      由于最近在给导师的一个小项目帮忙,而且要求使用OpenGL,所以我特地在网上搜索“如何在MFC框架中使用OpenGL”,看了很多博文,甚至论文(居然还有人把这个写成论文)后,自己又到VS2012上尝试了一番,最终摸索出了最最简单基本的使用方法,故总结在这里。一方面开启自己在博客园的学习和自省之路,另一方面也为需要的朋友提供点小小的帮助。相信这个实例会是最简单最容易理解的。

    摘要

      GDI绘图使用的是HDC,而OpenGL使用的则是HGLRC。与D2D通过把RenderTarget绑定到HDC以实现和GDI的混用的方法类似,OpenGL要想与HDC混用,或者说兼容HDC吧,需要使用wglCreateContext()函数来通过HDC创建一个HGLRC并把它选为当前所使用的环境。不过在此之前,我们还需要把像素格式设置成支持OpenGL的格式。另外,窗口也必须被改为特定的样式才能被OpenGL使用。做好了这三点,就能在MFC框架中使用OpenGL进行绘制了。

    具体实现步骤

    1. 封装OpenGL类

      首先,基于OOP的思想,我们把跟OpenGL相关的数据与操作封装起来:

    #pragma once
    class COpenGL
    {
    private:
      HDC hDC;     //GDI绘图中使用的的设备环境句柄
      HGLRC hRC;    //OpenGL渲染时使用的渲染环境句柄
    
    public:
      COpenGL(void);
      virtual ~COpenGL(void);
        
      bool SetupPixelFormat(HDC hdc);  //设置像素格式为适合OpenGL的格式
      void Init(void);           //初始化渲染过程中属性的设置
      void Render(void);          //绘制代码
    
      void Reshape(int width,int height);  //改变窗口大小时对视窗进行的操作
    };
    #include "stdafx.h"
    #include "OpenGL.h"
    
    
    COpenGL::COpenGL(void)
    {
    }
    
    
    COpenGL::~COpenGL(void)
    {
        wglMakeCurrent(hDC, NULL);
        wglDeleteContext(hRC);
    }
    
    
    void COpenGL::Init(void)
    {  
        //可添加例如“开启深度探测”等绘图属性设置代码
    }
    
    
    bool COpenGL::SetupPixelFormat(HDC hdc)
    {
        hDC=hdc;
    
        PIXELFORMATDESCRIPTOR pfd = 
        {
           sizeof(PIXELFORMATDESCRIPTOR),    // pfd结构的大小
           1,                                // 版本号
           PFD_DRAW_TO_WINDOW |              // 支持在窗口中绘图
           PFD_SUPPORT_OPENGL |              // 支持OpenGL
           PFD_DOUBLEBUFFER,                 // 双缓存模式
           PFD_TYPE_RGBA,                    // RGBA 颜色模式
           24,                               // 24 位颜色深度
           0, 0, 0, 0, 0, 0,                 // 忽略颜色位
           0,                                // 没有非透明度缓存
           0,                                // 忽略移位位
           0,                                // 无累加缓存
           0, 0, 0, 0,                       // 忽略累加位
           32,                               // 32 位深度缓存   
           0,                                // 无模板缓存
           0,                                // 无辅助缓存
           PFD_MAIN_PLANE,                   // 主层
           0,                                // 保留
           0, 0, 0                           // 忽略层,可见性和损毁掩模
        };
    
        int nPixelFormat;    // 像素点格式
        if (!(nPixelFormat = ChoosePixelFormat(hDC, &pfd)))
        { 
            MessageBox(NULL,L"can not find proper mode",L"Error",MB_OK|MB_ICONEXCLAMATION);
            return FALSE;
        }
    
        SetPixelFormat(hDC,nPixelFormat,&pfd);
        hRC = wglCreateContext(hDC);    //利用GDI绘图所使用的HDC创建对应的HGLRC
        wglMakeCurrent(hDC, hRC);        //使OpenGL绘图所使用的HGLRC为当前绘图工具
    
        return TRUE;
    }
    
    
    void COpenGL::Render()
    {
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);        
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();                        
     
        //绘制操作:
        glColor3ub(255,0,0);
        glBegin(GL_POLYGON);//填充凸多边形
            glVertex3f(0.5f,0.5f ,0.0f);
            glVertex3f(0.5f,-0.5f, 0.0f);
            glVertex3f(-0.5f,-0.5f,0.0f);
            glVertex3f(-0.5f,0.5f,0.0f);
        glEnd();
       
        glFlush();
        SwapBuffers(hDC);
    }
    
    
    void COpenGL::Reshape(int width,int height)
    {
        glViewport(0,0,width,height);
    }

    2. 使用OpenGL类

      接下来,我们在MFC框架中的CProjNameView类中创建刚刚编写的OpenGL类成员并进行相应的调用和操作来进行绘制:

      先在头文件中添加成员变量:

    COpenGL opengl;

    然后,改写CProjNameView::PreCreateWindow()函数以改变窗口样式来适应OpenGL的要求:

    BOOL CProjNameView::PreCreateWindow(CREATESTRUCT& cs)
    {
        // TODO: 在此处通过修改
        //  CREATESTRUCT cs 来修改窗口类或样式
        cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
    
        return CView::PreCreateWindow(cs);
    }

    再在CProjNameView::OnInitialUpdate()函数中添加设置像素格式、转换当前绘图所使用的环境和初始化OpenGL绘制属性的操作。(这里我们省去了初始化操作,即省去了OpenGL.cpp中的Init()函数的代码。设置像素格式、转换当前绘图所使用的环境都包含在COpenGL类的成员函数SetupPixelFormat()中)

    void CProjNameView::OnInitialUpdate()
    {
        CView::OnInitialUpdate();
    
        // TODO: 写入最终选择模式代码之后移除此代码
        m_pSelection = NULL;    // 初始化所选内容
       opengl.SetupPixelFormat(::GetDC(GetSafeHwnd()));
        opengl.Init();
    } 

    接下来,在CProjNameView::OnDraw()函数中添加绘制操作。

    void CProjNameView::OnDraw(CDC* /*pDC*/)
    {
        CFaceModelingDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        if (!pDoc)
            return;
    
        // TODO: 在此处为本机数据添加绘制代码
        opengl.Render();
    }

    最后,再改写CProjNameView::OnSize()函数,就大功告成了!(当然,这个并不是本例子中必要的,没有这项控制也能成功绘制。)

    void CProjNameView::OnSize(UINT nType, int cx, int cy)
    {
        if(cx==0)
        {
           cx=1;
        }
        opengl.Reshape(cx,cy);
    }

    效果图如下:

    补充

      当然,事先需要包含gl.h和glut.h两个头文件,他们一般都在GL文件夹目录下,而且gl.h是自带的,glut.h是需要自己扩展的。另外,还需要把glut.lib添加到工程可见的范围内。方便起见,我在这里提供一下glut的下载链接:glut扩展包

      另外,在MFC中使用OpenGL的绘制列表和纹理时要注意,MFC貌似不支持OpenGL的绘制列表,而且MFC似乎要求在每次绘制前都要设置一次纹理。这之中的道理只有深入了解MFC和OpenGL后才能明白了。

    原文链接:

    在MFC框架中使用OpenGL的简单实例

  • 相关阅读:
    java实现调用打印机代码
    java合并PDF文件
    关于如何把项目做得更好的一次思考
    web语义化之SEO和ARIA
    快速理解web语义化
    使用HTML5地理位置定位到城市的方法及注意事项
    Plupload上传插件简单整理
    两列布局——左侧宽度固定,右侧宽度自适应的两种方法
    Java并发编程之线程基础
    Spring Boot学习之YAML文件配置
  • 原文地址:https://www.cnblogs.com/rainbow70626/p/8975731.html
Copyright © 2011-2022 走看看