2024年5月11日发(作者:)
2010年海南省机械工程学会
Ⅱ-45
VB环境下OpenGL编程初探
杨亮曹阳
(海南优势资源化工材料应用技术教育部重点实验室,硅锆钛资源综合开发与利用
海南省重点实验室,海南大学材料与化工学院,海南海口570228)
摘要:
OpenGL是一种被广泛使用的三维图形与模型库,通常由C语言所开发。在种情况下,重
点讲述了VB中实现OpenGL图形开发的基本原理和具体实现方法,并针对OpenGL的像素格式、模型
变换、光照、材质、纹理、位图操作、平移、旋转、绘制几何图形等基本操作都作了细致的描述,
旨在将VB的应用拓展到三维图像处理领域,提高Opnegl编程效率和开发周期,结合两者的长处开发
出优秀的软件。
关键词:
VBOpenGL三维API
1引言
OpenGraphicsLibrary(开放性图形库)缩写
为OpenGL,是一套三维图形处理库,也是该领
域的工业标准。OpenGL被设计成独立于硬件,
独立于窗口系统,在运行各种操作系统的计算
机上都可用,并能在网络环境下以客户/服务器
模式工作,是专业图形处理、科学计算等高端
应用领域的标准图形库,主要应用方向包括飞
行训练、分子结构、研究、影视广告、CAD/
CAM/CAE、游戏娱乐、医学成像、计算机动
画制作和虚拟现实等。特别是Kinetix公司
的3DStudioMax就是其应用的突出的代表。
OpenGL是一组绘图命令的API集合,利用
这些API能够方便地描述二维和三维几何物体,
OpenGL的API集还提供了几何描述和图像图元、
显示列表、模型变换、反走样、物体、平移、
旋转、缩放、光照、纹理、材质、像素、位图、
文字、交互以及提高显示性能等方面的功能。
但是,OpenGL是一个包含120多个图形函数组
成的图形库,不包括任何窗口管理、用户交
互或文件I/O函数,使得OpenGL丧失了处
理窗口、用户输入命令的能力和缺乏面向对象
能力,不符合当前流行的软件设计思想。所以
必须在一定的语言环境中才能实现对OpenGL函
数的引用,最早使用OpenGL的编程语言是C语
[2]
[1]
言,随后又采用了C++或VC++,对于其它
语言环境下利用OpenGL图形函数开发图形应用
程序却较少有人研究,其他语言环境下OpenGL
编程方面的资料收集相对困难,这样更限制了
OpenGL在其他高级语言中的应用。
Vb是目前使用最广泛的编程语言,拥有数
目巨大的使用者。在VB编程环境下对OpenGL引
用来开发应用程序的研究较少,这对众多的VB
使用者来说是一种巨大的损失。VB中可利用
Windows提供的动态链接库OpenGL32.DLL和
GLU32.DLL来实现对OpenGL的调用来对图形进
行绘制
[4,5]
[3]
,而且还可以利用SCI公司提供的
GLUT32.DLL直接调用更多的图形函数进行图
形的开发,这样使OpenGL的开发更容易,同时
也使VB在能拓展到3D领域,使众多的VB使用
者能开发出美丽三维图像。
2实现过程
2.1Vb环境设置
新建一个标准EXE工程,在工程菜单下选
择引用,打开“引用”对话框,然后勾取“VB
OpenGLAPI1.2(ANSI)”项,从而实现VB对
OpenGL函数库的引用。然后在窗体stage上放置
两个PictureBox控件和一个时钟控件,并添加两
个模块。
一个OpenGL应用程序首先必须创建一个图
形操作描述表,然后再启动它,最后在所定义
Ⅱ-46
2010年海南省机械工程学会
的窗口内按常规方式调用OpenGL函数绘制图形。
Vb是基于窗口系统的可视化编程环境,对于每
个OpenGL程序都必须处理设备描述表,在创建
一个图形操作描述表之前,首先必须设置像素
格式。像素格式含有设备绘图界面的属性,这
些属性包括绘图界面是用RGBA模式还是颜色
表模式,像素缓存是用单缓存还是双缓存,以
及颜色位数、深度缓存和模板缓存所用的位数,
还有其它一些属性信息。每个OpenGL显示
设备都支持一种指定的像素格式。一般用一个
名为PIXELFORMATDESCRIPTOR的结构
来表示某个特殊的像素格式。我们将
FIXELFORMATDESCRIPTOR的结构放在一个名
为OpenGL的标准模块中EnableOpenGL过程中,
首先要定义FIXELFORMATDESCRIPTOR的像素
格式结构,代码如下:
ZeroMemorypfd,Len(pfd)用零来填充内存
区域,起点为PDF,大小为LEN(PDF)
pfd.nSize=Len(pfd)
pfd.nVersion=1
结构大小
版本号
wglMakeCurrentghDC,hRC使之成为当前绘
图描述表
这一模块的作用是创建了一个渲染上下文,
每一个OpenGL程序都必须和一个渲染上下文
(RC)相连接,在本程序中渲染上下文定义为
HRC,为了使能在窗口中绘制图像,必须定义上
下文句柄为HRC,渲染上下文可以使OpenGL把
绘制作用到设备上下文(DC)中来,设备上下
文连接图像设备接口(GDI)而渲染上下文则把
OpenGL连接到设备上下文。必须创建图形操作
描述表并启用渲染上下文后,才能调用OpenGL
函数在窗口内进行各种图形操作
[6]
。
2.2.加载图片并转化为纹理
建立一个名为LoadBMP的模块,用来加载
位图信息并转化为纹理。加载的位图图像的宽和
高必须是2的n次方,宽度和高度最小必须是64象
素,并且出于兼容性的原因,图像的宽度和高度
不应超过256象素。可用相应的处理软件将要转
化成纹理的图片加工成OpenGL要求的大小。声
明一个名为loadBMP的函数,用它来加载图片并
将其转化为二进制的数据信息。这里用一个
PictureBox控件来加载图片,必须将PictureBox控
件的ScaleMode属性设置为3-Pixd格式,才能调
用LoadBMP函数得到图片的像素信息。
PrivateFunctionloadBMP(ByValFilenameAs
String,ByRefTextureImg()AsGLubyte)AsBoolean
DimxAsLong,yAsLong,tempAsLong定义
临时的变量
Dimbi24BitInfoAsBITMAPINFO
定义BMP图片的格式
WithStage.Pict
.Picture=LoadPicture(Filename)
PictureBox控件加载BMP图
.Refresh
tw=.ScaleWidth
得到加载的BMP图片的宽度信息
th=.ScaleHeight
得到加载的BMP图片的高度信息
ReDimTextureImg(2,tw-1,th-1)
重新定义数组
EndWith
刷新PictureBox
pfd.dwFlags=PFD_DRAW_TO_WINDOW
OrPFD_SUPPORT_OPENGLOrPFD_DOUBLEBUFFER
OrPFD_GENERIC_FORMAT
绘图到Window,支持OpenGL,支持双缓
冲,通用模式
pfd.iPixelType=PFD_TYPE_RGBA
像素格式类型为RGBA
pfd.cColorBits=24
pfd.cDepthBits=16
pfd.cStencilBits=1
pfd.iLayerType=PFD_MAIN_PLANE
主层类型
PixFormat=ChoosePixelFormat(ghDC,pfd)
为设备描述表得到最匹配的像素格式,确定
Pdf结构是否存在
SetPixelFormatghDC,PixFormat,pfd如果
存在设备描述像素格式,把指定的像素格式赋
给指定的设备
hRC=wglCreateContext(ghDC)创建绘图描
述表
颜色索引位
深度缓冲区位数
2010年海南省机械工程学会
Ⅱ-47
Withbi24BitInfo.bmiHeader
头赋值
.biBitCount=24
位元存储
.biCompression=BI_RGB
.biPlanes=1
位图信息
TextureImage())Then
Status=True
glTexEnviGL_TEXTURE_ENV,
GL_TEXTURE_ENV_MODE,GL_MODULATE
纹理的贴图方式,与物体相溶合
glTexParameteriGL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER,GL_LINEAR
图像被放大时的采用线性滤波
glTexParameteriGL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,GL_LINEAR
图像被缩小时的采用线性滤波
glTexImage2DGL_TEXTURE_2D,0,3,tw,th,
0,GL_RGB,GL_UNSIGNED_BYTE,TextureImage
(0,0,0)
将图像信息TextureImage(0,0,0)形成纹理
EndIf
EraseTextureImage
EndFunction
2.3.绘制图形
由于在VB编程环境下只有窗体和PictureBox
控件具有绘制、显示图形的功能,并且他们的缺
省的像素格式都是Windows的GDI设置的,为了
使OpenGL命令绘制的图形能够在其上显示,必须
进行重新初始化它们的像素格式,并利用Opnegl
命令将窗口进行必要的渲染,这样才能绘制出高
质量的图形。
PrivateSubForm_Resize()
EnableOpenGLPic1.hDC
素格式
glClearColor0,0.5,0,0
glClearDepth1#
glEnableGL_DEPTH_TEST
glDepthFuncGL_LESS
glHintGL_PERSPECTIVE_CORRECTION_HINT,
GL_NICEST
打开光照,放置光源
glEnableglcLighting
glEnableglcLight0
允许深度测试
设置背景色为绿色
glShadeModelGL_SMOOTH
初始化PIC1控件的像
擦除纹理矩阵的内容
LoadGLTextures=Status
每个像素以几个
是否压缩
.biSize=Len(bi24BitInfo.bmiHeader)
‘BitmapInfoHeader结构大小
.biWidth=tw
需要处理位图宽度(单位:像素)
.biHeight=th
需要处理位图高度(单位:像素)
EndWith
GetDIBitsStage.Pict.hDC,Stage.Pict.Image,
0,th,TextureImg(0,0,0),bi24BitInfo,0
将来自一幅位图的二进制位复制到一幅与
设备无关的位图里。这里他将二进制位复制到
已经定义好的三维数组,它将某像素点的BLUE
分量存储到了(0,x,y)将GREEN分量存储到
(1,x,y),将RED分量存储到了(2,x,y)中,
这样就使得在调用纹理数组时,产生的图像的
颜色值的BLUE分量与RED分量互换的情况,所
以用下面的一段代码将纹理颜色分量进行调整。
Forx=0Totw-1
Fory=0Toth-1
temp=TextureImg(0,x,y)
TextureImg(0,x,y)=TextureImg(2,x,y)
TextureImg(2,x,y)=temp
Nexty
Nextx
loadBMP=True
EndFunction
下面是通过调用LaodBMP函数来加载图像
信息,并将位图转化为纹理。
FunctionLoadGLTextures()AsBoolean
DimStatusAsBoolean
DimTextureImage()AsGlbyte
Status=False'StatusIndicator
IfloadBMP(App.Path&"\tim.BMP",
Ⅱ-48
2010年海南省机械工程学会
DimPos(0To3)AsGlfloat
Pos(0)=0:Pos(1)=0:Pos(2)=5:Pos(3)=3
glLightfvltLight0,lpmPosition,Pos(0)
设置材质属性
Dimambient(0To3)AsGlfloat
DimDiffuse(0To3)AsGlfloat
DimSpecilar(0To3)AsGlfloat
DimShininess(0)AsGlfloat
ambient(0)=0.8:ambient(1)=0.8:ambient(2)=0.8:
ambient(3)=1
Diffuse(0)=0.8:Diffuse(1)=0.8:Diffuse(2)=0.8:
Diffuse(3)=1
Specilar(0)=0:Specilar(1)=1:Specilar(2)=1:S
pecilar(3)=3
Shininess(0)=25
glMaterialfvfaceFront,mprAmbient,ambient(0)
glMaterialfvfaceFront,mprDiffuse,Diffuse(0)
glMaterialfvfaceFront,mprSpecular,Specilar(0)
glMaterialfvfaceFront,mprShininess,
Shininess(0)
glEnableglcColorMaterial
DimwAsLong,hAsLong
w=Me.ScaleWidth:h=Me.ScaleHeight
Ifh=0Thenh=1
glViewport0,0,w,h
定义投影矩阵
glLoadIdentity重置模型观察矩阵
gluPerspective40#,w/h,1,100#定义视角
glMatrixModeGL_MODELVIEW
定义模型变换矩阵
glLoadIdentity
重置模型观察矩阵
glClearGL_COLOR_BUFFER_BITOrGL_DEPTH
_BUFFER_BIT
清除屏幕及深度缓
glLoadIdentity
glTranslatef0,0,-15
LoadGLTextures
glPolygonModefaceBack,pgmLine形背面以线填充
重置模型观察矩阵
移入屏幕15个单位
定义视见区
glMatrixModeGL_PROJECTION
glPolygonModefaceFront,pgmFILL
图形前面以全填充
glEnableglcTexture2D
Timer1.Enabled=True
EndSub
Timer事件能准确每隔一定的时间触发一次,
使程序运行在不同速度的计算机上的变化效果几
乎没有差别,使动画连续稳定。
PrivateSubTimer1_Timer
DimxAsInteger,yAsInteger,rAsInteger
StaticTAsInteger定义T为静态整型变量,
存储变化的角度值。
Dimpx1AsGLfloat,py1AsGLfloat,pz1As
Double,px2AsGLfloat,py2AsGLfloat,pz2AsDouble
glRotatef3,0,0,1使图像没Z轴旋转
以Px1、Px2、Py1、Py2、Pz1、Pz2六点来
组合成一个四边形,通过使用整数循环来产生
99×99的方格集合,为了使产生的方格居中,
将x.,y变量除以10再减去5。
glBeginbmQuads画矩形的开始语句,必须
以glEnd结束
Fory=1To100
Forx=1To100
px1=(x-1)/10-5
py1=(y-1)/10-5
pz1=Cos((y-1)/10*40/360*3.141592654
*2+t/180*3.141592654)
px2=(x)/10-5
py2=(y)/10-5
pz2=Cos(y/10*40/360*3.141592654*
2+t/180*3.141592654)
glTexCoord2f(x-1)/100,(y)/100
glVertex3fpx1,py2,pz2
利用x,y值可以直接计算纹理坐标,每个多
边形分别映射了纹理的1/99×1/99部分,纹理坐
标不同于网格坐标,纹理坐标以纹理图像的高
宽为单位1,网格以实际值为坐标每个网格的绘
制都是以逆时针绘制的。
glTexCoord2f(x-1)/100,(y-1)/100
glVertex3fpx1,py1,pz1
启用纹理映射
触发时钟事件
2010年海南省机械工程学会
Ⅱ-49
glTexCoord2f(x)/100,(y-1)/100
glVertex3fpx2,py1,pz1
glTexCoord2f(x)/100,(y)/100
glVertex3fpx2,py2,pz2
Nexty
Nextx
glEnd
SwapBuffersPic1.hDC交换缓冲区数据
glClearclrColorBufferBitOrclrDepthBufferBit清除
颜色缓存和深度缓冲,否则会使多幅图像
重叠在一起
EndSub
PrivateSubForm_Unload(CancelAsInteger)
wglMakeCurrent0,0清空当前绘图描述表
wglDeleteContexthRC
EndSub
EndSub
3结束语
本文对VB中应用OpenGL进行三维动画开
发过程作了一个详细的介绍,意在阐明VB中运
用OpenGL的基本原理和具体实现方法,对VB
程序员利用OpenGL起一抛砖引玉的作用。VB
与OpenGL结合可使VB方便的调用OpenGL的API
函数进行图形的绘制和场景的渲染,同时由于
Vb语言简单、实用、提高了开发的速度和软件
的质量,而且成本低。我们相信在不久的将来,
它们一定会发挥出巨大的作用。未来是光明的,
前景是诱人的。
致谢:
海南大学校基金(Kyjj0604)、
海南大学材料与化工学院课程群教学团队资助
项目。
删除绘图描述表
参考文献:
[1]潇湘工作室译.计算机技术译林精选系
列:OpenGL超级宝典[M].北京:人民邮电
出版社,2001-01-01:10-13
[2]史正中,郭继坤等。基于VB+OpenGL三
维地形实现[J],后勤工程学院学报,
2003年第1期:92-96
[3]欧训勇.OpenGL程序移植技术浅析
[J],计算机应用研究,2002:158-161
[4].王峰.用VisualBasic实现OpenGL三维
地形显示[J].测绘信息与工程,2000No.
3:13-17
[5]张晓宇,曲家文等.在VB6.0中利用
OpenGL进行图形编程[J].电脑学习,
2001(2):23-24
[6]荷塘月色创作组编著.如何使用
OpenGL开发程序[M].北京:北京理工大
学出版社,1999-01-01:208
作者简介:
杨亮:男,1979年5月生,实验师,海南大
学材料与化工学院,海南海口:570228
E-mail:YL5923@sina.com.cn


发布评论