基于OpenGL三维软件开发
- 格式:docx
- 大小:20.78 KB
- 文档页数:6
实验一基于OpenGL三维软件开发实验目的:1、熟悉c\c++编程,了解基于控制台编程和基于MFC编程。
2、了解OpenGL三维显示的机制,了解OpenGL的开发库类型以及开发库的功能。
3、会配置OpenGL开发环境,合理应用OpenGL头文件(.h),编译静态链接库(.lib文件),运行时的动态链接库(.dll文件)开发应用程序。
4、会使用OpenGL结合控制台程序或者MFC开发出一个能够绘制三维图形的应用程序。
实验原理:OpenGL在MFC下编程原理---- Windows操作系统对OpenGL的支持在Windows下用GDI作图必须通过设备上下文(Device Context简写DC)调用相应的函数;用OpenGL作图也是类似,OpenGL函数是通过"渲染上下文"(Rendering Context简写RC)完成三维图形的绘制。
Windows下的窗口和设备上下文支持"位图格式"(PIXELFORMAT)属性, 和RC 有着位图结构上的一致。
只要在创建RC时与一个DC建立联系(RC也只能通过已经建立了位图格式的DC来创建),OpenGL的函数就以通过RC对应的DC画到相应的显示设备上。
这里还有以下需要注意的方面:1.一个线程只能拥有一个渲染上下文RC,也就是说,用户如果在一个线程内对不同设备作图,只能通过更换与RC对应的DC来完成,而RC在线程保持不变(当然,删除旧的RC后再创建新的是可以的)。
与此对应,一个RC也只能属于一个线程,不能被不同线程同时共享。
2.设定DC位图格式等于设定了相应的窗口的位图格式,并且DC和窗口的位图格式一旦确定就不能再改变。
3.一个RC虽然可以更换DC,在任何时刻只能利用一个DC(这个DC称为RC的当前DC),但由于一个窗口可以让多个DC作图从而可以让多个线程利用多个RC在该窗口上执行OpenGL操作。
4.现在的Windows下的OpenGL版本对OpenGL和GDI在同一个DC上作图有一定的限制。
当使用双缓存用OpenGL产生动画时,不能使用GDI函数向该DC作图。
5.不建议用ANSI C在Windows下编写OpenGL程序。
这样的程序虽然具有跨平台的可移植性(比如很多SGI的例子程序),但是它们不能利用Windows操作系统的很多特性,实用价值不大。
---- 用VC来编写OpenGL程序经过上面的分析,用VC来调用OpenGL作图的方法流程如下:1.先设置显示设备DC的位图格式(PIXELFORMAT)属性。
这通过填充一个PIXELFORMATDESCRIPTOR的结构来完成,该结构决定了OpenGL作图的物理设备的属性,比如该结构中的数据项dwFlags中PFD_DOUBLEBUFFER位如果没有设置(置1),通过该设备的DC上作图的OpenGL命令就不可能使用双缓冲来做动画。
有一些位图格式(PIXELFORMAT)是DC支持的,而有一些DC就不支持了。
所以程序必须先用ChoosePixelFormat来选择DC所支持的与指定位图格式最接近的位图格式,然后用SetPixelFormat设置DC的位图格式。
2.利用刚才的设备DC建立渲染上下文RC(wglCreateContext),使得RC与DC建立联系(wglMakeCurrent)。
3.调用OpenGL函数作图。
由于线程与RC一一对应,OpenGL函数的参数中都不指明本线程RC的句柄。
4.作图完毕以后,先通过置当前线程的RC为NULL(::wglMakeCurrent(NULL, NULL);),断开当前线程和该渲染上下文的联系,由此断开与DC的联系。
所以在后面删除RC的时候要先判断以下RC句柄的有效性(if (m_hrc) ::wglDeleteContext(m_hrc);)。
再根据情况释放(ReleaseDC)或者删除(DeleteDC)DC。
实验步骤:1:新建一个MFC的工程,单文档的工程。
2:工程建好之后,可以先编译运行一下。
下面就是要把View的窗口初始化为OpenGL的编程环境。
当然以下所有的操作都是在View类中进行的。
先在Project->Settings->Link中,加上opengl32.lib glu32.lib glut.lib glaux.lib,然后在View.h的类定义view.cpp中加上如下引用。
这个大家都知道。
#include <gl\gl.h>#include <gl\glu.h>#include <gl\glut.h>#include <gl\glaux.h>3:在PreCreateWindow(CREATESTRUCT& cs)这个函数中可以修改一下窗口的风格,比如说窗口的名称背景什么的,当然也可以不修改,如果想修改的话,需要对WNDCLASSEX和CREATESTRUCT这两个结构比较熟悉。
在这里,我不进行修改。
采用默认的风格。
4:下面开始正题,首先要让窗口支持OpenGL,那就必须要对PIXELFORMATDESCRIPTOR这个结构有所了解,先在View类view.cpp中新建一个函数SetupPixFormat(CDC *pDC),公有私有无所谓,如下:BOOL CTestGLInitialView::SetupPixFormat(CDC *pDC) //比如工程名叫TestGLInitial{static PIXELFORMATDESCRIPTOR pfd = //定义像素格式{sizeof(PIXELFORMATDESCRIPTOR), // 上述格式描述符的大小1, // 版本号PFD_DRAW_TO_WINDOW | // 格式支持窗口PFD_SUPPORT_OPENGL | // 格式必须支持OpenGLPFD_DOUBLEBUFFER, // 必须支持双缓冲PFD_TYPE_RGBA, // 申请RGBA 格式24, // 24位色彩深度,即1.67千万的真彩色0, 0, 0, 0, 0, 0, // 忽略的色彩位0, // 无Alpha缓存0, // 忽略Shift Bit0, // 无累加缓存0, 0, 0, 0, // 忽略聚集位32, // 32位Z-缓存(深度缓存)0, // 无蒙板缓存0, // 无辅助缓存PFD_MAIN_PLANE, // 主绘图层0, // Reserved0, 0, 0 // 忽略层遮罩};int nIndex = ChoosePixelFormat(pDC->GetSafeHdc(), &pfd); //选择刚刚定义的像素格式if( nIndex == 0 ) return FALSE;return SetPixelFormat(pDC->GetSafeHdc(), nIndex, &pfd); //设置像素格式}这个函数的主要目的就是设置窗口的像素格式,使之支持OpenGL,明白这点就行了。
在创建窗口的时候,调用这个函数。
5:刚刚那个函数是用来在创建窗口是调用的,在创建窗口时,还需要对OpenGL的环境做一些初始化,再定义一个函数InitialGL(),如下:BOOL CTestGLInitialView::InitialGL(){glShadeModel(GL_SMOOTH); // 启用阴影平滑glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 黑色背景glClearDepth(1.0f); // 设置深度缓存glEnable(GL_DEPTH_TEST); // 启用深度测试glDepthFunc(GL_LEQUAL); // 所作深度测试的类型glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告诉系统对透视进行修正return TRUE; // 初始化OK}6:现在可以捕获WM_CREATE消息了。
但是,还要先定义一个CClientDC*的成员,这个成员指向View窗口自己,是用来传递给SetupPixFormat(CDC *pDC)函数的,没别的意思。
现在,来捕获WM_CREATE消息,写上如下代码:int CTestGLInitialView::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CView::OnCreate(lpCreateStruct) == -1)return -1;// TODO: Add your specialized creation code herem_pDC = new CClientDC(this);SetupPixFormat(m_pDC);HGLRC hrc = wglCreateContext(m_pDC->GetSafeHdc());wglMakeCurrent(m_pDC->GetSafeHdc(), hrc);InitialGL();return 0;}当然,当窗口关闭的时候,还应该要释放一些资源。
捕获WM_DESTROY消息,写下如下代码:void CTestGLInitialView::OnDestroy(){CView::OnDestroy();// TODO: Add your message handler code hereHGLRC hrc = wglGetCurrentContext();wglMakeCurrent(NULL, 0);wglDeleteContext(hrc);delete m_pDC;}现在可以编译一下了,没有错误。
7:现在,OpenGL的环境已经初始化差基本完成,可以开始做图了。
先定义一个作图的函数DrawScene(),写上如下的代码:BOOL CTestGLInitialView::DrawScene(){glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存glLoadIdentity(); // 重置当前的模型观察矩阵SwapBuffers(m_pDC->GetSafeHdc()); // 交换缓冲区return TRUE;}然后,要在OnDraw中,调用这个函数:void CTestGLInitialView::OnDraw(CDC* pDC){CTestGLInitialDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereDrawScene();}8:运行一下,黑色的背景出来了。