MFC框架下OpenGL程序的实现步骤

本文详细介绍了如何在Microsoft Visual Studio .NET 2003中利用MFC框架创建OpenGL程序。通过新建MFC多文档应用程序,添加WSDView类并实现双缓存、鼠标交互等功能,实现了在MFC环境中绘制并交互3D对象,例如茶壶。

  

   本文主要介绍如何在MFC框架下编写OpenGL程序。现有的OpenGL参考书多是介绍基于AUX库,或是基于GLUT库的Win32 OpenGL程序。这类程序结构非常简单,主要目的是让读者熟悉OpenGL语言的用法及功能。然而不得不承认,编写可视化程序MFC框架有其独到的优势,本文就是针对这种需求,详细介绍MFC框架下OpenGL程序的实现步骤。

       编译器:Microsoft Visual Studio.NET 2003(中文版)

       准备工作下载OpenGL非标准额外GLUT库文件http://www.openglsource.com/download/download.htm包括glut.h, glut32.lib, glut32.dll。将glut.h放到目录VC2003.NET/Vc7/PlatformSDK/Include/gl下,glut32.lib放到目录VC2003.NET/Vc7/PlatformSDK/Lib下,再将glut32.dll放进WINDOWS/system32中,最后设置编译器的链接:【项目】-【属性页】-【链接器】-【输入】-【附加依赖项】-glut32.lib

      具体实现步骤:

1.       新建MFC多文档应用程序,项目名取为Render

2.       新建两个文件WSDView.hWSDView.cpp,并将这两个文件放入项目文件夹内。具体代码见附录。两文件的功能:创建类CWSDView,它继承自CView,成员函数包括设置像素格式,创建渲染描述表,各类鼠标消息相应函数如鼠标左键拖动,右键拖动及滚轴转动等。

3.       【文件】-【添加现有项】,选取WSDView.h, WSDView.cpp文件。

4.       RenderView.h文件中添加代码 #include "WSDView.h"

class CRenderView : public CView修改为class CRenderView : public CWSDView

RenderView.cpp文件中修改IMPLEMENT_DYNCREATE(CRenderView, CView)IMPLEMENT_DYNCREATE(CRenderView, CWSDView);修改  BEGIN_MESSAGE_MAP(CRenderView, CView)BEGIN_MESSAGE_MAP(CRenderView, CWSDView)

5.       CRenderView类中添加虚拟函数virtual void RenderScene(void)。实际上它是继承自父类CWSDView

6.       CRenderView::OnDraw(CDC* /*pDC*/)内添加代码:

  // TODO: 在此处为本机数据添加绘制代码

    //双缓存应用

    static BOOL bBusy = FALSE;

    if(bBusy)     return;

    bBusy = TRUE;

    //背景色

    glClearColor( 0.0f , 0.0f , 0.0f , 1.0f );

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清缓存

    glMatrixMode(GL_MODELVIEW);//启动模型矩阵

    glLoadIdentity();//初始化模型矩阵

    //  绘制动作 

    glTranslatef(0.0, 0.0, -8.0); //将场景移至可视区

    RenderScene();//绘制场景

    glFinish();//完成绘制

    SwapBuffers(wglGetCurrentDC());//双缓存应用:更新缓存

    bBusy = FALSE;

7.       CRenderView::RenderScene(void)内添加代码:

       glPushMatrix();

       //控制操作如下,与鼠标消息相应函数相关:

       glTranslatef(m_translateX, m_translateY, 0.0);

       glRotatef(rotate_x, 1.0, 0.0, 0.0);

       glRotatef(rotate_y, 0.0, 1.0, 0.0);

       glScalef(m_scale, m_scale, m_scale);

       //绘制实体 例如茶壶

       glPushMatrix();

       glColor 3f (0.5, 0.5, 0.5);

       glutSolidTeapot(0.3);

       glPopMatrix();

       glPopMatrix();

       Ok,至此基本框架已经搞定。按照上述步骤,编译运行显示结果:黑色背景下的灰色茶壶。用户使用鼠标达到与场景交互的目的,左键的拖动实现茶壶的旋转,右键拖动可使茶壶平移,滚轴转动则具有放大或缩小的功能。更复杂的OpenGL程序都可基于此框架完成,例如读取几何数据模型文件则可在CRenderDoc类中实现,模型显示代码主要在CRenderView类中的RenderScene()函数中添加,其他功能可根据作者需求适当修改添加,在此不再唠叨。

附录:

WSDView.h:

#if !defined(AFX_GLVIEW_H__3CA5EA 8F _BFF7_ 43F 2_B571_2385D95E5006__INCLUDED_)

#define AFX_GLVIEW_H__3CA5EA 8F _BFF7_ 43F 2_B571_2385D95E5006__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif

 

#include "gl/glut.h" //添加glut

 

#pragma comment(lib, "Opengl32.lib")

#pragma comment(lib, "glu32.lib")

//#pragma comment(lib, "glut32.lib")

 

class CWSDView : public CView

{

protected: // 仅从序列化创建

       CWSDView();

       DECLARE_DYNCREATE(CWSDView)

 

// 属性

public:

 

 

// 操作

public:

 

// 重写

       public:

       virtual void OnDraw(CDC* pDC);  // 重写以绘制该视图

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

// 实现

public:

       virtual ~CWSDView();

#ifdef _DEBUG

       virtual void AssertValid() const;

       virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

 

// 生成的消息映射函数

protected:

       DECLARE_MESSAGE_MAP()

public:

       afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

       afx_msg void OnSize(UINT nType, int cx, int cy);

       afx_msg void OnDestroy();

       //像素格式定义函数

       bool pixelFormat(void);

       // 显示设备环境类变量

       CClientDC* my_pDC;

       // 测试像素格式的函数

       void testPixelFormat(void);

       CRect my_oldRect;

 

       afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

 

       // X轴旋转角度

       double rotate_x;

       double rotate_y;

       // 记录光标位置

       CPoint m_oldPoint;

       afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

       afx_msg void OnMouseMove(UINT nFlags, CPoint point);

       afx_msg BOOL OnEraseBkgnd(CDC* pDC);//避免屏幕闪烁

       virtual void RenderScene(void);

       afx_msg void OnRButtonDown(UINT nFlags, CPoint point);

       afx_msg void OnRButtonUp(UINT nFlags, CPoint point);

       afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);

       // 沿X方向平移

       double m_translateX;

       double m_translateY;

       // 缩放系数

       double m_scale;

};

 

#endif // !defined(AFX_GLVIEW_H__3CA5EA 8F _BFF7_ 43F 2_B571_2385D95E5006__INCLUDED_)

WSDView.cpp:

// WSDView.cpp : CWSDView 类的实现

//

#include "stdafx.h"

#include "WSDView.h"

#include "math.h"

#include "./wsdview.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

 

// CWSDView

#define PI  3.1415927

 

IMPLEMENT_DYNCREATE(CWSDView, CView)

 

BEGIN_MESSAGE_MAP(CWSDView, CView)

       // 标准打印命令

       ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)

       ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)

       ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

       ON_WM_CREATE()

       ON_WM_SIZE()

       ON_WM_DESTROY()

       ON_WM_LBUTTONDOWN()

       ON_WM_LBUTTONUP()

       ON_WM_MOUSEMOVE()

       ON_WM_ERASEBKGND()

       ON_WM_RBUTTONDOWN()

       ON_WM_RBUTTONUP()

       ON_WM_MOUSEWHEEL()

END_MESSAGE_MAP()

 

// CWSDView 构造/析构

 

CWSDView::CWSDView()

: my_pDC(NULL)

, rotate_x(0)

, rotate_y(0)

, m_oldPoint(0)

, m_translateX(0)

, m_translateY(0)

, m_scale(1.0)

{

       // TODO: 在此处添加构造代码

 

}

 

CWSDView::~CWSDView()

{

}

 

BOOL CWSDView::PreCreateWindow(CREATESTRUCT& cs)

{

       // TODO: 在此处通过修改 CREATESTRUCT cs 来修改窗口类或

       // 样式

       cs.style=WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS;

 

       return CView::PreCreateWindow(cs);

}

 

// CWSDView 诊断

 

#ifdef _DEBUG

void CWSDView::AssertValid() const

{

       CView::AssertValid();

}

 

void CWSDView::Dump(CDumpContext& dc) const

{

       CView::Dump(dc);

}

 

#endif //_DEBUG

 

 

// CWSDView 消息处理程序

 

int CWSDView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

       if (CView::OnCreate(lpCreateStruct) == -1)

              return -1;

 

       // TODO:  在此添加您专用的创建代码

       testPixelFormat();//调用该函数,完成渲染描述表的调用

 

       return 0;

}

 

void CWSDView::OnSize(UINT nType, int cx, int cy)

{

       CView::OnSize(nType, cx, cy);

 

       // TODO: 在此处添加消息处理程序代码

       if(cy > 0)

    {

 

        my_oldRect.right = cx;

        my_oldRect.bottom = cy;

 

 

        glMatrixMode(GL_PROJECTION);

        glLoadIdentity();

              //视场调节:

              glFrustum(-1.0, 1.0, -1.0*cy/cx, 1.0*cy/cx, 5.0, 25.0);

              glViewport(0, 0, cx, cy);

    }

       RedrawWindow();

}

 

void CWSDView::OnDestroy()

{

       CView::OnDestroy();

 

       // TODO: 在此处添加消息处理程序代码

       //删除渲染描述表及绑定的设备描述表

       HGLRC   hrc;

       hrc = ::wglGetCurrentContext();

 

    ::wglMakeCurrent(NULL,  NULL);

      

    if (hrc)

        ::wglDeleteContext(hrc);

 

    if (my_pDC)

        delete my_pDC;

}

 

//像素格式定义函数

bool CWSDView::pixelFormat(void)

{

       //像素属性的设置

       static PIXELFORMATDESCRIPTOR pfd =

       {

        sizeof(PIXELFORMATDESCRIPTOR),

        1,                            

        PFD_DRAW_TO_WINDOW |          

          PFD_SUPPORT_OPENGL|                    // support OpenGL

                PFD_DOUBLEBUFFER,             // double buffered

        PFD_TYPE_RGBA,             

        24,                        

        0, 0, 0, 0, 0, 0,          

        0,                         

        0,                         

        0,                         

        0, 0, 0, 0,                

        32,                        

        0,                         

        0,                         

        PFD_MAIN_PLANE,            

        0,                         

        0, 0, 0                    

    };

    int pixelformat;

 

    if ( (pixelformat = ChoosePixelFormat(my_pDC->GetSafeHdc(), &pfd)) == 0 )

    {

        MessageBox("ChoosePixelFormat failed");

        return FALSE;

    }

 

    if (SetPixelFormat(my_pDC->GetSafeHdc(), pixelformat, &pfd) == FALSE)

    {

        MessageBox("SetPixelFormat failed");

        return FALSE;

    }

 

    return TRUE;

}

 

// 测试像素格式的函数

void CWSDView::testPixelFormat(void)

{

       PIXELFORMATDESCRIPTOR pfd;

    int         n;

       HGLRC          hrc;

 

    my_pDC = new CClientDC(this);

 

    ASSERT(my_pDC != NULL);

 

    if (!pixelFormat())

        return;

    n =::GetPixelFormat(my_pDC->GetSafeHdc());

    ::DescribePixelFormat(my_pDC->GetSafeHdc(), n, sizeof(pfd), &pfd);

 

    hrc = wglCreateContext(my_pDC->GetSafeHdc());

    wglMakeCurrent(my_pDC->GetSafeHdc(), hrc);

 

       GetClientRect(&my_oldRect);

    glClearDepth( 1.0f );

    glEnable(GL_DEPTH_TEST);

       glMatrixMode(GL_MODELVIEW);

       glLoadIdentity();

}

 

// CWSDView 绘制

 

//避免屏幕闪烁

BOOL CWSDView::OnEraseBkgnd(CDC* pDC)

{

       // TODO: 在此添加消息处理程序代码和/或调用默认值

 

       return true;

}

 

void CWSDView::RenderScene(void)

{

       //控制操作如下:

/*    glTranslatef(m_translateX, m_translateY, 0.0);

       glRotatef(rotate_x, 1.0, 0.0, 0.0);

       glRotatef(rotate_y, 0.0, 1.0, 0.0);

       glScalef(m_scale, m_scale, m_scale);

 

       //光照

       GLfloat          lAmb[4];

       GLfloat          lDif[4];

       GLfloat          lSpe[4];

       GLfloat          lPos[4];

 

       lAmb[0]= 0.0f ; lAmb[1]= 0.0f ;

       lAmb[2]= 0.0f ; lAmb[3]= 0.0f ;

 

       lDif[0]= 1.0f ;   lDif[1]= 0.0f ;

       lDif[2]= 0.0f ;   lDif[3]= 0.0f ;

 

       lSpe[0]= 0.5f ;  lSpe[1]= 0.0f ;

       lSpe[2]= 0.0f ;  lSpe[3]= 0.0f ;

 

       lPos[0]= 1.0f ;  lPos[1]= 0.0f ;

       lPos[2]= 0.0f ;  lPos[3]= 0.0f ;

 

       glLightfv(GL_LIGHT1,GL_AMBIENT,lAmb);

       glLightfv(GL_LIGHT1,GL_DIFFUSE,lDif);

       glLightfv(GL_LIGHT1,GL_SPECULAR,lSpe);

       glLightfv(GL_LIGHT1,GL_POSITION,lPos);

 

       glEnable(GL_LIGHTING);

       glEnable(GL_LIGHT1);

 

       //绘制实体

       glPushMatrix();

       glColor 3f (0.5, 0.5, 0.5);

       glutSolidTeapot(0.3);

       glPopMatrix();*/

}

 

void CWSDView::OnDraw(CDC* /*pDC*/)

{

/*    // TODO: 在此处为本机数据添加绘制代码

       //双缓存应用

       static BOOL bBusy = FALSE;

    if(bBusy)       return;

    bBusy = TRUE;

 

       //背景色

       glClearColor( 0.0f , 0.0f , 0.0f , 1.0f );

      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清缓存

       glMatrixMode(GL_MODELVIEW);//启动模型矩阵

       glLoadIdentity();//初始化模型矩阵

    //  绘制动作 

       glTranslatef(0.0, 0.0, -8.0);

 

       RenderScene();//绘制场景

 

       glFinish();//完成绘制

       SwapBuffers(wglGetCurrentDC());//双缓存应用:更新缓存

       bBusy = FALSE;*/

}

 

void CWSDView::OnLButtonDown(UINT nFlags, CPoint point)

{

       // TODO: 在此添加消息处理程序代码和/或调用默认值

       m_oldPoint = point;

    Invalidate(true);

       CView::OnLButtonDown(nFlags, point);

}

 

void CWSDView::OnLButtonUp(UINT nFlags, CPoint point)

{

       // TODO: 在此添加消息处理程序代码和/或调用默认值

       Invalidate(true);

       CView::OnLButtonUp(nFlags, point);

}

 

void CWSDView::OnMouseMove(UINT nFlags, CPoint point)

{

       //TODO: 在此添加消息处理程序代码和/或调用默认值

       if (nFlags & MK_LBUTTON) //左键旋转

       {

              rotate_x += (point.y - m_oldPoint.y) * 0.3;

              rotate_y += (point.x - m_oldPoint.x) * 0.3;

 

              m_oldPoint = point;

       }

       else if (nFlags & MK_RBUTTON) //右键平移

       {

              m_translateX += (point.x - m_oldPoint.x) * 0.003;

              m_translateY += (m_oldPoint.y - point.y) * 0.003;

 

              m_oldPoint = point;

       }

       Invalidate(true);

       CView::OnMouseMove(nFlags, point);

}

 

void CWSDView::OnRButtonDown(UINT nFlags, CPoint point)

{

       // TODO: 在此添加消息处理程序代码和/或调用默认值

       m_oldPoint = point;

       Invalidate(true);

 

       CView::OnRButtonDown(nFlags, point);

}

 

void CWSDView::OnRButtonUp(UINT nFlags, CPoint point)

{

       // TODO: 在此添加消息处理程序代码和/或调用默认值

 

       Invalidate(true);

       CView::OnRButtonUp(nFlags, point);

}

 

BOOL CWSDView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)

{

       // TODO: 在此添加消息处理程序代码和/或调用默认值

       m_scale += 0.1 * zDelta / 120;

       Invalidate(true);

 

       return CView::OnMouseWheel(nFlags, zDelta, pt);

}

 

 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值