您的位置:首页 > 运维架构

基于MFC对话框的OpenGL三维图形开发

2014-04-11 13:29 453 查看
以三维动态球体模型来讲述基于MFC对话框的OpenGL编程
1.基本思想
在Windows98/NT平台下,GDI是原始窗口的图形接口。而GDI实现这些是通过一个设备描述表DC来实现的。现在通过OpenGL绘图需要创建绘图描述表RC。但是RC并不能直接完成绘图,只能与特定的DC联系起来,从而完成具体的绘图工作。最后要注意释放RC和DC。
2. 编程步骤
第一步,设置开发环境
现在以Windows2000为例,首先将glu.dll,glu32.dll,glut.dll,glut32.dll,opengl32.dll文件拷贝到操作系统WINNT/System32目录下,将gl.h,glaux.h,glu.h,glut.h拷贝到Microsoft Visual Studio/VC98/Include/GL目录中中,将glaux.lib,glu32.lib,glut32.lib,opengl32.lib拷贝到Microsoft Visual Studio/VC98/Lib目录中;然后在编译程序的时候选择Project|Setting菜单,在Link标签中的Object/library modules编辑框中输入“opengl32.lib, glut32.lib ,glu32.lib,glaux.lib”。到这时候环境就建立好了,可以进行下面的具体编程工作。
第二步,具体编程
本实例采用基于对话框的工程。至于用单文档方式和多文档方式其编程原理是一样的,这里不再作单独介绍。
2.1创建项目文件。选择File|New菜单项,新建一个基于对话框的项目文件MyDlgOpenGL;
2.2 修改对话框模板。删除对话框中的静态文本,调整控件的位置。
2.3 创建新类,添加消息映射。选择View|ClassWizard菜单项,打开MFC对话框,在Add Class之中选择New,以便添加一个新类COpenGL,且该类的基类选择generic CWnd;最后利用MFC ClassWizard为COpenGL类添加消息WM_CREATE,WM_PAINT的映射。
2.4 添加代码。
2.4.1 定义像素格式 ,创建OpenGL显示。
在OpenGL能够在一个绘图对象中绘图之前,该绘图对象必须初始化。为此引入像素格式的概念。像素格式能告诉OpenGL是否使用双缓存,颜色模式,颜色位数,深度位数等等重要信息。 它由一个被称作PIXELFORMATDESCRIPTOR的所描述。于是定义在OpenGL.h中定义函数int MySetPixelFormat(HDC hdc)。然后在OpenGL.cpp文件中加入如下代码:
int COpenGL::MySetPixelFormat(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 iPixelFormat;

// 为设备描述表得到最匹配的像素格式
if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
{
MessageBox("ChoosePixelFormat Failed", NULL, MB_OK);
return 0;
}

// 设置最匹配的像素格式为当前的像素格式
if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
{
MessageBox("SetPixelFormat Failed", NULL, MB_OK);
return 0;
}

return 1;
}
现在就可以在OnCreate函数中创建绘图描述表。其代码如下:
int COpenGL::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;

MySetPixelFormat(::GetDC(m_hWnd)); // 设置当前的绘图像素格式
hdc = ::GetDC(m_hWnd); // 获得绘图描述表
hglrc = wglCreateContext(hdc); // 创建绘图描述表
wglMakeCurrent(hdc, hglrc); // 使绘图描述表为当前调用现程的当前绘图描述表
return 0;
}
2.4.2 进行光照处理,添加OpenGL显示。
在OpenGL.h中定义函数LightShine函数,作为添加光源和材质属性的函数。在该函数中将创建两个光源,并使其位于不同位置,以产生不同的效果。定义:环境光,散射光,镜面光和镜面反射指数。因为没有一种光源完全由以上三种中的一种光源组成,所以任何一种光源都是由以上三种光源的光照成分组成的,即为混合光源。其成分值由RGBA定义。用材料对光的三原色的反射率来定义材料的颜色,与光源相对应,。代码如下:
void COpenGL::LightShine(void)
{

GLfloat mat_diffuse[4]={1,0.5,0.5,1.0};
GLfloat mat_specular[4]={1.0,1.0,1.0,1.0};
GLfloat mat_shininess[1]={100.0};
//光源 1
GLfloat light_position0[4]={0,500,500,0};
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
glLightfv(GL_LIGHT0,GL_POSITION,light_position0);
glEnable(GL_LIGHT0);
//光源 2
GLfloat light_position1[4]={1000,-1000,1000,0};
GLfloat mat_diffuse1[4]={0.5,0.5,1.0,1.0};
glLightfv(GL_LIGHT1,GL_DIFFUSE,mat_diffuse1);
glLightfv(GL_LIGHT1,GL_SPECULAR,mat_specular);
glLightfv(GL_LIGHT1,GL_SHININESS,mat_shininess);
glLightfv(GL_LIGHT1,GL_POSITION,light_position1);
glEnable(GL_LIGHT1);

//使模型能接受光照
glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
//计算定点法线
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);

}
2.4.3 定义绘图窗口
所绘球体在哪个区域内进行绘制以及这个区域的风格是怎样的必须需要进行定义。为下一步的绘图工作打下基础。那么可以在MyDlgOpenGLDlg.cpp的函数OnInitDialog()中加入如下代码:
CRect rect(7, 7, 300, 300); //定义绘图区域的大小
m_pDisplay->Create( NULL,
NULL,
//定义窗口风格
WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_VISIBLE,
rect,
this,
0);
2.4.4 绘制图象
在前面的准备之后,现在可以在OnPaint函数中绘制图象。在具体进行绘制物体时,需要注意的是:glPushMatrix()与glPopMatrix()的使用必须成对出现。此外,必须正确使用glScale() 函数和glRatate() 函数以及双缓存技术,以实现所绘球体的在指定窗口由远及近,由小变大的旋转。代码如下:
void COpenGL::OnPaint()
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
space+=0.005;
if(space>1.0)
space=0.1;
step = step + 1.0;
if (step > 360.0)
step = step - 360.0;
glPushMatrix();
glScalef(space,space,space);
glRotatef(step,0.0,1.0,0.0);
glRotatef(step,0.0,0.0,1.0);
glRotatef(step,1.0,0.0,0.0);

LightShine(); //添加光照属性
glutSolidSphere(1.0,20,16); //绘制球体
glPopMatrix();
glFlush();

SwapBuffers(hdc); //使用双缓存技术实现交换缓冲区

}
2.4.5 结束运行
在结束运行时,我们必须将一些环境变量释放。于是应该在添加的类COpenGL的析构函数中进行操作,以释放DC和删除RC。代码如下:
COpenGL::~COpenGL()
{
wglMakeCurrent(NULL, NULL) ;
wglDeleteContext(hglrc); //删除绘图描述表
::ReleaseDC (m_hWnd, hdc) ; //释放设备描述表
}

结语
利用Visual C++强大的窗口功能完成了OpenGL绘制球体的程序的编制工作,上述程序运行正常,其结果是一个动态的球体。理解了上述编程过程,就可以使我们自如地运用MFC进行其他的OpenGL编程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: