引言 GIS(地理信息系统)、GPS(全球定位系统)和RS(卫星遥感技术)三大空间科学技术并称为"3S"技术,被认为是21世纪信息科学技术发展的重要前沿技术。特别是进入新世纪,GIS已经列为我国信息产业中的支柱产业之一。在各种地形数字仿真应用系统中,核心应用系统无一不是高度依赖空间数据,无一不是基于GIS技术平台。GIS是一个知识面非常宽的应用技术学科,本系列文章将从三维地景仿真的角度对其进行介绍,其间将对DEM数字高程模型和OpenGL等主要技术进行介绍。
此类GIS应用软件通常多建立在OpenGL平台之上,本系统也不例外。在实现其他特殊功能之前,必须首先正确配置、安装好OpenGL环境,然后才能进行各种实用功能的开发。下面将对OpenGL做一个简短的介绍,并开始OpenGL应用程序框架的搭建工作。
OpenGL概述 OpenGL是一种到图形硬件的软件接口。从本质上说,它是一个完全可移植并且速度很快的3D图形和建模库。通过使用OpenGL,可以创建视觉质量接近射线跟踪程序的精致漂亮的3D图形。但是它在执行速度上要比射线跟踪程序快好几个数量级。OpenGL使用的是由Silicon Graphcs(SGI)公司精心开发的优化算法,这家公司在计算机图形和动画领域是公认的业界领袖。开发者可以利用OpenGL提供的150多个图形函数轻松建立三维模型并进行三维实时交互。这些函数并不要求开发者将三维物体模型的数据写成固定的数据格式,这样一 来开发者就不仅可以直接使用自己的数据,而且还可以利用其他格式的数据源,能在很大程度上缩短软件的开发周期。
OpenGL不仅可对整个三维模型进行渲染并绘制出逼真的三维景象,而且还可以进行三维交互、动作模拟等处理。其提供的基本功能具体包含以下几方面的内容:
(1)模型绘制。在OpenGL中通过对点、线和多边形等基本形体的绘制可以构造出非常复杂的三维模型。OpenGL经常通过使用模型的多边形及其顶点来描述三维模型。
(2)模型观察。在建立了三维模型后,可以通过OpenGL的描述来观察此模型。此观察过程是通过一系列的坐标变换来实现的。这种变换使得观察者能够在视点位置得到与之相适应的三维模型场景。投影变换的类型对模型的观察有很大的影响,在不同投影变换下得到的三维模型场景也是不同的。在模型观察过程的最后还要对场景进行裁剪和缩放,以决定整个三维模型场景在屏幕上的显示。
(3)颜色模式的指定。在OpenGL中可以指定模型的颜色模式(RGBA模式和颜色表模式)。除此之外,还可以通过选择模型的着色方式(平面着色和光滑着色)来对整个三维场景进行着色处理。
(4)光照效果。为使OpenGL绘制的三维模型更加逼真还必须增加光照效果。目前OpenGL仅提供了对辐射光、环境光、镜面光和漫反射光的管理方法,另外还可以指定模型表面的反射特性。
(5)图象效果增强。在增强三维场景图象效果方面,OpenGL也提供了一系列相关函数。这些函数通过反走样、混合和雾化等处理来增强图象效果。其中,反走样用于改善图象中线形图形的锯齿使其更平滑;混合用于处理模型的半透明效果;雾化使场景图象从视点到远处逐渐褪色,使其更接近现实情况。
(6)位图和图象处理。OpenGL提供有专门进行位图和图象处理的函数。
(7)纹理映射。真实物体的表面普遍存在纹理,如果建立的三维模型场景缺少此细节将显得不够真实,为更逼真地表现三维场景,OpenGL提供了纹理映射的功能。OpenGL提供的纹理映射函数可以很方便地把纹理图象贴到场景多边形上。
(8)双缓存技术。OpenGL提供的双缓存技术主要用于实时动画,为获得平滑的动画效果,需要先在内存中生成下一帧图象,然后再将其从内存拷贝到屏幕。
(9)人机交互。OpenGL提供了方便的三维图形人机交互接口,通过此接口用户可以选择修改三维景观中的物体。
OpenGL应用程序框架的建立 首先建立一个单文档应用程序,并将需要用到的头文件和导入库添加到工程,以便能够顺利通过编译。在VC++中,OpenGL的头文件一般是存放在系统头文件目录的子目录GL中,所以在指定包含的时候要指定一下相对路径:
#include <gl\gl.h> // OpenGL32库的头文件 #include <gl\glu.h> // GLu32库的头文件 #include <gl\glaux.h> // GLaux库的头文件 |
这里的gl.h是基本头文件,glu.h是应用头文件,大多数应用程序都需要同时包含这两个头文件,glaux.h是辅助头文件,只在需要使用的情况下包含。接下来调出"Project Settings"对话框并在"Link"选项页中添加glu32.lib、glaux.lib和OpenGL win32实现的标准导入库opengl32.lib到工程。
接下来初始化OpenGL,这也是本文最重要的部分。先大致讲一下基本步骤:首先获取需要在上面绘图的设备环境(DC)并为该设备环境设置像素格式,然后创建基于该设备环境的OpenGL设备。最后,初始化OpenGL绘制场景及状态设置。前三步的实现过程在SetOpenGLInterface()函数中实现:
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, // 无alpha缓存 0, // 忽略转换位 0, // 无累计位 0, 0, 0, 0, 32, // 32位深度缓存 0, // 无模版缓存 0, // 无辅助缓存 PFD_MAIN_PLANE, // 主绘制层 0, // 保留 0, 0, 0 // 忽略的层掩模 }; m_pDC = GetDC(); // 得到设备环境句柄 int iFormat = ChoosePixelFormat(m_pDC->m_hDC, &pfd); // 设置象素格式 SetPixelFormat(m_pDC->m_hDC, iFormat, &pfd); m_hGlrc = wglCreateContext(m_pDC->m_hDC); // 创建渲染上下文 wglMakeCurrent(m_pDC->m_hDC, m_hGlrc); // 设置一个线程的当前绘图描述表 |
这里首先对描述像素存储格式的PIXELFORMATDESCRIPTOR结构变量进行了填充,在得到设备环境句柄后调用ChoosePixelFormat()和SetPixelFormat()函数以返回并设置最佳匹配的像素格式。最后调用wglCreateContext()创建一个渲染上下文RC并将其作为参数通过wglMakeCurrent()来建立一个当前的绘图描述表,并在绘制完毕后(通常在WM_DESTORY消息发出后执行)将其释放:
ReleaseDC(m_pDC); // 释放DC if (m_hGlrc != NULL) // 释放RC wglDeleteContext(m_hGlrc); |
经过上面的处理OpenGL就已经初始化完毕了,但为了达到逼真的视觉效果还有必要进一步设置一下场景,这在InitOpenGL()函数中完成。具体的工作包括对光源的各种定义:
GLfloat light_position[] = {0.0, 0.0, 1.0, 0.0}; // 定义光源的位置坐标 glLightfv(GL_LIGHT0, GL_POSITION, light_position); GLfloat light_ambient[] = {0.0, 0.0, 0.0, 1.0}; // 定义环境反射光 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0}; // 定义漫反射光 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0}; // 定义镜面反射光 glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); GLfloat light_model_ambient[] = {0.4f, 0.4f, 0.4f, 1.0f}; // 定义光模型参数 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_model_ambient); GLfloat local_view[] = {0.0}; glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view); |
以及各项相关功能的使能设置:
glEnable(GL_LIGHTING); // GL_LIGHTING有效 glEnable(GL_LIGHT0); // GL_LIGHT0有效 glEnable(GL_DEPTH_TEST); // 允许深度比较 glDepthFunc(GL_LESS); // 激活深度比较 glClearColor(0.1f, 0.1f, 0.5f, 0.0f); // 设置蓝色背景 glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); // 权衡图像质量与绘制速度 |
通常,SetOpenGLInterface()和InitOpenGL()在WM_CREATE消息发出后即被执行,以确保在程序启动之初完成对OpenGL的环境设置。在视图初始化更新完毕后,还要进行最后的处理--进行视口的定义,下面给出的这段InitViewPort()函数实现代码将完成此功能:
CRect rect; // 得到绘图客户区的大小 GetClientRect(rect); glMatrixMode(GL_PROJECTION); // 设置投影模式 glLoadIdentity(); // 装载单位矩阵 if (m_nViewMode == 0) // 建立一个透视投影矩阵 gluPerspective(90.0, rect.Width() / rect.Height(), 1.0, 10000.0); if (m_nViewMode == 1) // 建立一个正射投影矩阵 glOrtho(-0.5 * 10000.0, 0.5 * 10000.0, -
阅读(1650)
(责任编辑:城市网)
|