zoukankan      html  css  js  c++  java
  • MFC+OpenGL基础绘制<转>

    转载地址:https://blog.csdn.net/u013232740/article/details/47904115

    ------------------------------------------------------------------------------------------------------------

    本例在Visual Studio 2013环境下使用OpenGL,提供一个基本的开发应用程序框架。

    第一步:OpenGL基础设置:

    1.创建一个单文档的MFC应用程序,命名为TestGL,然后在TestGLView.h头文件中添加以下两条include包含语句:

    #include "gl/gl.h"  
    #include "gl/glu.h" 

    2.设置程序为静态运行方式

    执行菜单命令:项目->属性,弹出属性对话框,选择配置属性->常规->MFC使用->在静态库中使用MFC,然后单击确定。这样做会使程序变得很大,但是它编译生成的可执行程序可以在其他计算机中运行。

    3.链接OpenGL库文件

    执行菜单命令:项目->属性打开属性对话框,选择配置属性->链接器->常规->附加库路径,输入OpenGL的库文件所在的路径,单击确定。比如我的机子如下:

    再选择配置属性->链接器->输入->附加依赖库,在弹出的对话框中输入OpenGL的库文件OpenGL32.lib和glu32.lib,如下:

    然后确定结束属性配置。编译运行,如果没有错误则表明配置正确。

    第二步:在Visual Studio下用OpenGL绘制三棱锥:

    绘制步骤如下:

    *通过PIXELFORMATDESCRIPTOR结构设置设备描述表DC的像素格式和属性;

    *创建渲染描述表RC,并和DC建立联系;

    *使用OpenGL做图;

    *释放所占用的资源,包括解除DC和RC的联系,删除RC及其与之关联的DC;

    为应用程序添加变量和函数,对相关变量进行初始化,然后在函数中实现DC像素格式设置,RC的创建及其与DC 的关联,图形绘制以及资源释放等功能。

    1.添加成员变量和成员函数:

    为CTestGLView类添加公共变量:

    CClientDC* pDrawDC;     // 用于指向当前DC的指针  

    通过向导自动添加后,会在CTestGLView类的构造函数中将其初始化为NULL:

    CTestGLView::CTestGLView()  
        : pDrawDC(NULL)  
    {  
        // TODO: 在此处添加构造代码  
      
    }  

    然后为CTestGLView添加三个公共成员函数:

    void DrawGraphics(void);// 用于后续图形绘制  
    BOOL PixelformatSetting(void);  // 用于设置像素格式  
    void GLSetting(void);   // 用于创建渲染描述表  

    此时在TestGLView.cpp文件中可以看到添加消息的消息映射宏ON_WM_CREATE()和对应的OnCreate()函数。该消息响应在建立一个窗体前将被调用,因此可在其中做一些初始设置。

    同样的方法添加另外两个消息响应函数:

    OnDestroy():响应WM_DESTROY消息,宏为ON_WM_DESTROY(),窗口销毁时响应此函数,因此应该在此释放函数中所占用的资源。

    OnSize():响应WM_SIZE消息,宏为ON_WM_SIZE()。改变窗口大小时响应此函数,因此可在此函数中调整视场。

    3.为成员函数和消息响应函数添加代码:

    1)设置像素格式。在BOOL CTestGLView::PixelformatSetting(void)函数中添加如下代码:

    // 用于设置像素格式  
    BOOL CTestGLView::PixelformatSetting(void)  
    {  
        static PIXELFORMATDESCRIPTOR pfd={  
            sizeof(PIXELFORMATDESCRIPTOR),  //结构体长度  
            1,    //版本  
            PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //在窗口中绘图|支持进行OpenGL调用|双缓存模式  
            PFD_TYPE_RGBA,  //RGBA颜色模式  
            24,  //使用24位颜色  
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0,  
            32,  //深度缓冲区大小  
            0, 0,  
            PFD_MAIN_PLANE,  
            0, 0, 0, 0  
        };  //填充PIXELFORMATDESCRIPTOR像素格式  
        int ipixelformat;  
        //获取最佳匹配的像素格式索引  
        if((ipixelformat = ChoosePixelFormat(pDrawDC->GetSafeHdc(),&pfd)) == 0)  
        {  
            MessageBox(_T("Choose pixel format failed!"));  
            return TRUE;  
        }  
        //把DC的像素格式设置成由索引值ipixelformat指向的像素格式  
        if(SetPixelFormat(pDrawDC->GetSafeHdc(),ipixelformat,&pfd) == FALSE)  
        {  
            MessageBox(_T("Set pixel format failed !"));  
            return FALSE;  
        }  
        return TRUE;  
    }  

    2).创建渲染描述表:

    在函数void CTestGLView::GLSetting(void)中调用PixelformatSetting(void)设置像素格式,然后创建和DC关联的渲染描述表,代码如下:

    // 用于创建渲染描述表  
    void CTestGLView::GLSetting(void)  
    {  
        HGLRC hRC;   //渲染描述表句柄  
        pDrawDC = new CClientDC(this);  //使pDrawDC指向当前DC  
        ASSERT(pDrawDC !=NULL);  //断言pDrawDC不为空  
        if(!PixelformatSetting())  //设置像素格式  
            return;  
        //创建和当前DC兼容的RC,并和当前DC关联  
        hRC = wglCreateContext(pDrawDC->GetSafeHdc());  
        wglMakeCurrent(pDrawDC->GetSafeHdc(),hRC);  
    }  

    3).在消息响应函数OnCreate()函数中调用GLSetting()函数,使上述设置生效,代码如下:

    int CTestGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)  
    {  
        if (CView::OnCreate(lpCreateStruct) == -1)  
            return -1;  
      
        // TODO:  Add your specialized creation code here  
        GLSetting();  //该函数用来创建渲染描述表  
        return 0;  
    }  

    4).投影变换和视口变换。

    在OnSize()中添加代码设置投影变换和视口变换,如下所示:

    void CTestGLView::OnSize(UINT nType, int cx, int cy)  
    {  
        CView::OnSize(nType, cx, cy);  
      
        // TODO: Add your message handler code here  
        if(cy>0)  
        {  
            glMatrixMode(GL_PROJECTION);  //启动投影矩阵,4×4  
            glLoadIdentity();   //初始化为单位矩阵  
            gluPerspective(45.0f,cx/cy,0.0f,30.0f);  //设置透视投影变换,指定视场  
            glViewport(0, 0, cx, cy);  //设置视场,即定义显示范围  
        }  
        RedrawWindow();   //显示更新  
    }  

    5).绘制三棱锥:

    在void CTestGLView::DrawGraphics(void)函数中,添加代码绘制3个三角形,构成一个三棱锥,如下:

    void CTestGLView::DrawGraphics(void)  
    {  
        glTranslatef(0.0f, 0.0f, -6.0f);  //移动物体到显示区  
        glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);   //以边线方式绘制三角形  
        //绘制3个三角形的三个顶点  
        glBegin(GL_TRIANGLES);  
            glVertex3f(-0.6f, 0.0f, 0.0f);  
            glVertex3f(0.6f, 0.0f, 0.0f);  
            glVertex3f(0.0f, 0.15f, 0.6f);  
      
            glVertex3f(-0.6f, 0.0f, 0.0f);  
            glVertex3f(0.0f, 0.15f, 0.6f);  
            glVertex3f(0.0f, 0.9f, 0.6f);  
      
            glVertex3f(0.0f, 0.9f, 0.6f);  
            glVertex3f(0.0f, 0.15f, 0.6f);  
            glVertex3f(0.6f, 0.0f, 0.0f);  
        glEnd();  
    }  

    6).在OnDraw()函数中设置背景并调用DrawGraphics()函数绘制图形。

    通常使用CView类的成员函数OnDraw()绘制用户界面,此外还可以在该函数中添加代码完成背景色设置,然后调用DrawGraphics()函数完成绘制。

    void CTestGLView::OnDraw(CDC* /*pDC*/)  
    {  
        CTestGLDoc* pDoc = GetDocument();  
        ASSERT_VALID(pDoc);  
        if (!pDoc)  
            return;  
      
        // TODO: 在此处为本机数据添加绘制代码  
        static BOOL bBusy = FALSE;  //定义开关变量  
        //绘制完成后才可以更新缓存  
        if(bBusy)  
            return;  
        bBusy =TRUE;  
        glClearColor(0.0f, 0.0f, 0.5f, 0.5f);  //设置背景颜色  
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  //清除深度缓存和颜色缓存  
        glMatrixMode(GL_MODELVIEW);  //启动模型矩阵  
        glLoadIdentity();   //初始化为单位矩阵  
        DrawGraphics();   //绘制图形  
        SwapBuffers(wglGetCurrentDC());  //更新缓存  
        bBusy=FALSE;  
    }  

    7).删除渲染描述表。

    在消息响应函数OnDestroy()中删除渲染描述表及其绑定的设备描述表,代码如下:

    void CTestGLView::OnDestroy()  
    {  
        CView::OnDestroy();  
      
        // TODO: Add your message handler code here  
        HGLRC hRC;  
        hRC=::wglGetCurrentContext();   //获取当前RC句柄  
        ::wglMakeCurrent(NULL,NULL);  //解除当前RC和DC的关联,并把当前RC非当前化  
        if(hRC)  
        {  
            ::wglDeleteContext(hRC);  //删除RC  
        }  
        if(pDrawDC)  
        {  
            delete pDrawDC;   //删除DC  
        }  
    }  

    编译运行项目,如果没有错,可得结果如下:

    4.添加旋转功能:

    实现一个交互功能,即单击鼠标开始/停止三棱锥旋转。

    1).添加消息响应函数。

    为CTestGLView类添加鼠标左键消息WM_LBUTTONDOWN和定时器消息WM_TIME,鼠标左键消息响应函数OnLButtonDown(),宏ON_WM_LBUTTONDOWN()。定时器消息响应函数为OnTimer(),宏ON_WM_TIMER().
    2).为CTestGLView类添加两个共有属性的成员变量,

    BOOL bRotate;   // 控制图形旋转  
    float RotateAngle;   // 旋转角度  

    Visual Studio会自动在CTestGLView类的构造函数中将bRotate初始化为FALSE,将RotateAngle初始化为0.手动将bRotate的初始值改为TRUE。

    3).在void CTestGLView::OnLButtonDown(UINT nFlags, CPoint point)函数中添加如下代码,通过单击启动/停止定时器,

    void CTestGLView::OnLButtonDown(UINT nFlags, CPoint point)  
    {  
        // TODO: Add your message handler code here and/or call default  
        if(bRotate)  
        {  
            SetTimer(1,100,NULL);   //设置定时器1,100ms触发一次  
        }  
        else  
        {  
            KillTimer(1);  //移除定时器1  
        }  
        bRotate = !bRotate;   //更新bRotate的值  
        CView::OnLButtonDown(nFlags, point);  
    }  

    4).设置旋转角度。在定时器消息响应函数OnTimer()中添加如下代码,实现每次定时到达时都能将图形旋转10度

    void CTestGLView::OnTimer(UINT_PTR nIDEvent)  
    {  
        // TODO: Add your message handler code here and/or call default  
        //若定时器1到达预定时刻,则旋转角度增加10度  
        if(nIDEvent == 1)  
        {  
            RotateAngle += 10.0f;  
            Invalidate(FALSE);  //使当前窗口失效,重新绘制  
        }  
        CView::OnTimer(nIDEvent);  
    }  

    在OnTimer()函数中使用的Invalidate()函数作用是将整个客户区失效,从而被重新绘制,而最终的重绘工作由OnDraw()函数完成。此处用函数Invalidate()函数调用了OnDraw()函数来绘制旋转后的图形。

    5).每次按照设置的角度重绘图形。重绘窗口由OnDraw()函数完成,而OnDraw()函数调用DrawGraphics()函数绘制图形。因此在函数DrawGraphics()函数中需添加如下代码:

    glRotated(RotateAngle,1.0, 1.0, 1.0);  //按设定的角度RotateAngle旋转图形 

    将这句代码放在glTranslatef()函数语句之后。使得每次重绘时将图形绕着从原点指向(1.0,1.0,1.0)的射线旋转RotateAngle的角度,而RotateAngle的值在定时器函数OnTimer()中更新。这样就可以实现每次单击鼠标左键,定时器开始计时,每个100ms后响应定时器消息的函数OnTimer()将RotateAngle的值增加10度,同时Invalidate()函数使界面失效而被重绘,重绘是将图形选择RotateAngle的角度,有时间间隔短,所以看上去就会产生三棱锥旋转的效果。当鼠标在此单击左键时,定时器被取消,图形停止旋转。

    ===================================================================================================================================

    原贴地址:https://blog.csdn.net/u013232740/article/details/47904115

  • 相关阅读:
    全面监测网站信息
    linux 将Mysql的一张表导出至Excel格式文件
    渗透测试人员发现用户可无限输入密码次数,超过5次未锁定用户,存在暴力破解风险。解放方案:限制每个输入的用户名(不管存不存在该账户)登陆失败次数不超过5次,超过则锁定该用户
    mysql linux下数据库导出 常用操作
    find php.ini 和 php的执行目录 bin目录
    解决:The “https://packagist.laravel-china.org/packages.json” file could not be downloaded
    如何上传代码至GitHub
    7. Jmeter-逻辑控制器介绍与使用
    19、Linux命令对服务器内存进行监控
    20、Linux命令对服务器磁盘进行监控
  • 原文地址:https://www.cnblogs.com/wainiwann/p/8780781.html
Copyright © 2011-2022 走看看