http://www.gissky.net- GIS空间站

我要投稿 投稿指南 RSS订阅 网站资讯通告:
搜索: 您现在的位置: GIS空间站 >> 技术专栏 >> 软件开发 >> 正文

GIS系统三维地景仿真的设计之基础架构

作者:青岛郎锐    文章来源:GIS空间站    点击数:    更新时间:2006-11-3
摘要:
引言

  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 // OpenGL32库的头文件
#include // GLu32库的头文件
#include // 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, -0.5 * 10000.0, 0.5 * 10000.0, 1.0, 10000.0); glViewport(0, 0, rect.Width(), rect.Height()); // 重定视口
 glMatrixMode(GL_MODELVIEW); // 确定当前矩阵模式
 glLoadIdentity(); // 装载单位矩阵

  这里完成的主要工作有对投影模式的设置与对投影矩阵的建立以及对视口的重定等。其中,控制变量m_nViewMode的取值决定了投影模式(透视投影还是正射投影),并根据不同的投影模式调用函数gluPerspective()或glOrtho()建立相应的投影矩阵。函数gluPerspective()用于创建一个对称透视视景体,第一个参数定义了视野在X-Z平面的角度,取值范围为[0.0, 180.0];第二个参数是投影平面宽度与高度的比率;后两个参数分别为远近裁剪面沿Z负轴到视点的距离,总为正值。glOrtho()用于创建一个平行视景体(实际是创建一个正射投影矩阵,并以此矩阵乘以当前矩阵)。其近裁剪、远裁剪平面均为矩形,近裁剪矩形左下角点和右上角点的三维空间坐标分别为(left,bottom,-near)和(right,top,-near);远裁剪平面的相应空间坐标分别为(left,bottom,-far)和(right,top,-far)。这里所有的near、far值同时为正或同时为负。若未进行其他变换,正射投影的方向将平行于Z轴、视点朝向Z负轴。

  视口确定之后就可以着手对场景的绘制了。这主要在ReDraw()中完成,并在OnSize()、OnDraw()等需要重绘的地方被调用。由于这部分不属于OpenGL框架搭建的内容,因此该函数的实现将在后续的文章中进行详细介绍,这里不再赘述。

  小结

  本文主要介绍了OpenGL程序框架的一般搭建方法,为三维地景仿真处理系统的进一部开发提供了基本的OpenGL环境。读者需要注意的知识点有:对OpenGL的初始化处理;光源的设置;视口的设置等。本文所述程序在Windows 2000 Professional + SP4下由Microsoft Visual C++ 6.0编译通过。

Tags:GIS,3D  
责任编辑:gissky
关于我们 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 中国地图