基于OpenGL三维软件开发

实验原理:

OpenGL在MFC下编程原理---- Windows操作系统对OpenGL的支持

在Windows下用GDI作图必须通过设备上下文(DeviceContext简写DC)调用相应的函数;用OpenGL作图也是类似,OpenGL函数是通过"渲染上下文"(RenderingContext简写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 |    // 格式必须支持OpenGL

PFD_DOUBLEBUFFER,     // 必须支持双缓冲

PFD_TYPE_RGBA,      // 申请 RGBA 格式

24,         // 24位色彩深度,即1.67千万的真彩色

0,0, 0, 0, 0, 0,     // 忽略的色彩位

0,         // 无Alpha缓存

0,         // 忽略Shift Bit

0,         // 无累加缓存

0,0, 0, 0,       // 忽略聚集位

32,         // 32位 Z-缓存 (深度缓存)

0,         // 无蒙板缓存

0,         // 无辅助缓存

PFD_MAIN_PLANE,      // 主绘图层

0,         // Reserved

0,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消息,写上如下代码:

intCTestGLInitialView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

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

return -1;

// TODO: Add your specialized creation code here

m_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 here

HGLRC 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 here

DrawScene();

}

8:运行一下,黑色的背景出来了。

9:这时,可以修改DrawScene()这个作图函数,作图。画出那个三角形和正方形来。写代码如下:

BOOL CTestGLInitialView::DrawScene()

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清除屏幕和深度缓存

glLoadIdentity();           // 重置当前的模型观察矩阵

glTranslatef(-1.5f,0.0f,-6.0f);       // 左移 1.5 单位,并移入屏幕 6.0

glBegin(GL_TRIANGLES);        // 绘制三角形

glColor3f(1.0f, 0.0f, 0.0f);

glVertex3f( 0.0f, 1.0f, 0.0f);       // 上顶点

glColor3f(0.0f, 1.0f, 0.0f);

glVertex3f(-1.0f,-1.0f,0.0f);       // 左下

glColor3f(0.0f, 0.0f, 1.0f);

glVertex3f( 1.0f,-1.0f,0.0f);       // 右下

glEnd();            // 三角形绘制结束

glTranslatef(3.0f,0.0f,0.0f);       // 右移3单位

glColor3f(0.0f, 0.0f, 1.0f);

glBegin(GL_QUADS);          //绘制正方形

glVertex3f(-1.0f, 1.0f, 0.0f);       // 左上

glVertex3f( 1.0f, 1.0f, 0.0f);       // 右上

glVertex3f( 1.0f,-1.0f,0.0f);       // 左下

glVertex3f(-1.0f,-1.0f,0.0f);       // 右下

glEnd();

SwapBuffers(m_pDC->GetSafeHdc());        // 交换缓冲区

return TRUE;

}

运行一下,发现图形没有出现,这个怎么回事呢。原来是因为还没有定义投影方式和视口。即用正交投影还是透视投影。定义投影,还要捕获WM_SIZE消息。写如下代码:

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

{

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

// TODO: Add your message handler code here

if (0 == cy)         // 防止被零除

{

cy = 1;          // 将Height设为1

}

glViewport(0, 0, cx, cy);     // 重置当前的视口

glMatrixMode(GL_PROJECTION);    // 选择投影矩阵

glLoadIdentity();        // 重置投影矩阵

// 设置视口的大小

gluPerspective(45.0f,(GLfloat)cx/(GLfloat)cy,0.1f,100.0f);

glMatrixMode(GL_MODELVIEW);      // 选择模型观察矩阵

glLoadIdentity();        // 重置模型观察矩阵

}

再运行一下,图形已经出来了。以后,就可以在DrawScene()写任何画图的代码了,当窗口重绘的时候,都可以自动适应。如果要做一段可以运动的3D图画,可以再捕获WM_TIMER消息,通过在OnCreate的时候定义一个时钟,再配合一些变量,就可以做简单的动画了。

读者可以在上面学习的基础上,继续完成下面的内容,以便增加对知识的掌握程度:

建议必做功能:包括基本的基于OpenGL的显示,在OpenGL初始化过的视图区绘制一个基本图形。

建议选做功能:绘制复杂例如曲线、曲面、不规则多面体以及其他实物的三维图形,图形的旋转,平移,放大、缩小等动画功能。

搬家于CSDN 2015-05-10

原文地址:https://www.cnblogs.com/arxive/p/11748193.html

时间: 2024-08-28 21:30:33

基于OpenGL三维软件开发的相关文章

基于模型的软件开发——互动出版网

这篇是计算机类的优质预售推荐>>>><基于模型的软件开发> 译者序 这是一本关于一种特定的软件设计方法实践的书.MBD(Model-Based Software Development,基于模型的软件开发)方法基本上是一种OO(Object-Oriented,面向对象)方法.其基本观点是:通过静态结构和动态结构的开发,生成面向对象的分析模型,然后通过工具的转换,进而转换为应用程序框架. 本书第一部分着眼于面向对象方法诞生的历史背景,使我们能够了解传统方法存在的问题,也就

基于git的软件开发中并行工程管理以及版本控制系统概要

并行工程师什么,这里就不再解释(不懂请百度),实际上,在软件开发过程中,涉及到多人合作的以项目小组形式完成开发的软件(这里指广义上)或多或少都使用了并行工程的概念,在正式的项目开发中,项目小组成员总是分工合作每人完成一部分,然后再合并起来,而且,在实际应用中,尽管使用的是瀑布模型完成开发,但总是所有项目小组成员同时开始完成自己的部分,这,其实已经是并行工程了,我们可以自豪的宣布:我们在开发过程中使用了并行 工程这种高大上的玩意来提高开发速度,所以,老板你得给我们涨工资! 很简单吧,看起来好简单的

12 信息2班 《基于Android的软件开发》课程成绩

作业 作业01:为 TextView 添加监听器和后退按钮. (参考教材第02章)作业02:完善GeoQuiz应用,堵住漏洞. (参考教材第05章)作业03:日期格式化. (参考教材第08章)作业04:更多对话框. (参考教材第12章)作业05:在 HelloMoon 应用中播放视频. (参考教材第13章)作业06:用于列表的空视图. (参考教材第16章)作业07:使用外部存储. (参考教材第17章) 作业成绩 作业 1 作业 2 作业 3 作业 4 作业 5 作业 6 作业 7 备注 李秋萍

C语言基于NIOSII的软件开发及流水灯设计

一.Quartus II 12.1 (32-Bit)进行硬件设计 1.所需要的系统元器件组成 2.系统电路图 二.Nios II 12.1 Software Build Tools for Eclipse进行软件学号及流水灯设计 1.程序代码 /* * "Hello World" example. * * This example prints 'Hello from Nios II' to the STDOUT stream. It runs on * the Nios II 'st

基于OpenGL的三维曲面动态显示实现

在使用Visual C++的MFC AppWizard建立应用程序框架后,生成了多个类,与OpenGL编程相关的类是视图类,主要的显示任务都在其中完成. 1.基于OpenGL绘图的基本设置 1.1 设置必要的编译链接环境 OpenGL的图形编程接口包括的主要函数和库函数被封装在动态链接库中,因此在项目中要添加 OpenGL32.dll.glu32.dll和glaux.dll三个库.同时在应用程序的视类头文件中加入OpenGL头文件说明: #include"gl\gl.h" #inclu

百家基于ACIS的软件ZWCAD.ZW3D.v2016.Beta3.Win32_64 2DVD

世界上已有数百家基于ACIS的软件ZWCAD.ZW3D.v2016.Beta3.Win32_64 2DVD     增加了三维功能和VBA支持的增强版本.中望CAD专业版除了具备中望CAD 2008版(标准版)的全部功能外,增加了支持三维实体的显示.编辑和建模及渲染,同时提供VBA的开发接口支持,客户可以方便的使用VB开发工具进行二次开发.中望CAD专业版是国内第一套以强大的二维设计为基础.同时融合基本三维设计功能的CAD解决方案,主要面对建筑.机械.家具和制造领域内以二维绘图为主,同时也用到部

在云计算推动下的软件开发

什么是云计算 对云计算的定义有多种说法.对于到底什么是云计算,至少可以找到100种解释.现阶段广为接受的是美国国家标准与技术研究院(NIST)定义:云计算是一种按使用量付费的模式,这种模式提供可用的.便捷的.按需的网络访问, 进入可配置的计算资源共享池(资源包括互联网,服务器,存储,应用软件,服务),这些资源能够被快速提供,只需投入很少的管理工作,或与服务供应商进行很少的交互.本文将着重讨论云计算与传统软件开发的联系与相互关系. 云计算(cloud computing)是一种基于Internet

这群超酷的开发者,是如何轻松搞定软件开发?

前些日子我看到两则有关线上Office的新闻,一是空客的十三万员工将全部迁移到谷歌的在线文档套件G Suite:二是腾讯发布在线文档产品,可以与微软Excel和Word互转.在网页里就能写文档.做电子表格,对于20年前熟练地玩耍着Office 97的我来说这是极难以想像的.时至今日,不单是Office,连同图像处理.3D模型设计都可以在一张网页内轻松完成. 这些创新的背后是无数位软件开发人员智慧的结晶,如果说Software is eating the world, 那么developers a

软件工程与软件开发模型、软件开发方法

什么是软件工程? 软件工程一直以来都缺乏一个统一的定义. IEEE给出的定义是:软件工程是:1.将系统化的.严格约束的.可质量化的方法应用于软件的开发.运行和维护,即将工程化应用于软件:2.在1中所述方法的研究. 比较认可的一种定义是:软件工程是研究和应用如何以系统性的.规范化的.可定量的过程化方法去开发和维护软件,以及如何把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来. 什么是软件开发方法(或软件开发过程)? 软件开发方法找不到统一的定义,但是我们说极限编程(Extr