副标题#e#
暂时不谈论OpenGL的宝贵配景和光亮前途,单凭其实用性和有效性就足以使其成为我们图形输出编程的首选。可是在实际工程应用中措施员没须要仔细地深究OpenGL的运作机制,也往往不需要把握各类高级的结果建造,真正需要的是最简便地操作这个得力的东西实现输出数据的可视化,如波形、谱图、立体统计图表等的显示。有鉴于此,本文总结出了在C++Builder中OpenGL编程的实用框架。笔者颠末实践,对付一般的图形输出的应用,此框架足以应付。对付巨大些的措施可以在本框架的基本长举办扩充。
在Windows情况下用OpenGL编程至少要相识如下预备常识:
OpenGL自己:对付一般的应用,我们可以认为OpenGL就是一套与窗口系统和操纵系统无关的三维图形函数库。
DC和RC:每个Win32应用措施都有一个设备描写表(Device Context)简称DC,在这个设备描写表中包括了图形奈何显示在窗口的配置( GDI)信息。挪用OpenGL函数必需利用设备描写表才气正确地在窗口输出。图形操纵描写表(Rendering Context)简称RC,是一种设备描写表的形式,在图形操纵描写表中存放一些OpenGL和操纵系统相接洽的信息。图形操纵描写表是通报所有OpenGL呼吁的端口。
像素名目:像素名目界说了OpenGL画图的属性,建设图形操纵描写表首先要界说象素名目。它由这样一个数据布局实现
typedef struct tagPIXELFORMATDESCRIPTOR
{
WORD nSize; //布局巨细
WORD nVersion; //版本
DWORD dwFlags; //象素缓冲的位符号
BYTE iPixelType; //RGBA模式或颜色索引模式
BYTE cColorBits; //颜色位数
BYTE cRedBits; //RGBA模式下R所占位数
BYTE cRedShift; //RGBA模式下R位数偏移
BYTE cGreenBits; //RGBA模式下G所占位数
BYTE cGreenShift; //RGBA模式下G位数偏移
BYTE cBlueBits; //RGBA模式下B所占位数
BYTE cBlueShift; //RGBA模式下B位数偏移
BYTE cAlphaBits; //RGBA模式下Alpha所占位数
BYTE cAlphaShift; //RGBA模式下Alpha位数偏移
BYTE cAccumBits; //累计缓冲区位面总数
BYTE cAccumRedBits; //累计缓冲区R位面总数
BYTE cAccumGreenBits; //累计缓冲区G位面总数
BYTE cAccumBlueBits; //累计缓冲区B位面总数
BYTE cAccumAlphaBits; //累计缓冲区Alpaha位面总数
BYTE cDepthBits; //深度缓冲位数
BYTE cStencilBits; //模板缓冲位数
BYTE cAuxBuffers; //Win32 下不支持
BYTE iLayerType; //不再利用
BYTE bReserved; //0
DWORD dwLayerMask; //不再利用
DWORD dwVisibleMask; //0
DWORD dwDamageMask; //不再利用
} PIXELFORMATDESCRIPTOR;
双缓冲技能:OpenGL支持一个显示缓冲和一个非显示缓冲。缺省的环境是所有的OpenGL绘制呼吁在非显示缓冲中绘制,绘制完成后再将其内容拷贝到显示缓冲区中(利用SwapBuffers函数)。双缓冲使图象转换更滑腻,这就是在快速动画(如波形等的及时输出)时没有屏幕闪烁的玄妙地址。
反走样技能:实际中需要画出的往往是曲线,由于计较机以离散点生成图形,曲线上会有锯齿,这就是一种走样现象。在用一般语言绘图时,这一现象是难以制止的。OpenGL中操作殽杂技能,把本来界线的锯齿部门用低饱和度的点补上从而实现反走样,到达滑腻的界线结果。
好,我们此刻可以启用下面的措施框架了。
在*.h文件的类声明中添加private成员:
private:
HGLRC hRC;
HDC hDC;
以下是相应*.cpp文件
首先加上两个包括文件:
#include <gl\gl.h> //措施利用OpenGL的焦点函数
#include <gl\glu.h> //措施利用实用库中的函数
#p#副标题#e#
一、在FormCreate()函数中完成OpenGL的初始化
利用OpenGL必需首先举办一些初始化事情,详细包括以下步调:
1、建设DC
hDC=GetDC(Handle);
此句获取一个设备描写表,TForm1->Handle中生存有Form的窗口句柄;许多环境下我们但愿在一个Panel中输出图形,那么可以用Panel1->Handle作为此函数的参数。
2、建设RC
(1)界说像素名目
static PIXELFORMATDESCRIPTOR pfd={
sizeof(PIXELFORMATDESCRIPTOR), //此布局的巨细
1, //此布局的版本
PFD_DRAW_TO_WINDOW| //在窗口上画图(而不是在位图上)
PFD_SUPPORT_OPENGL| //在窗口中支持利用OpenGL
PFD_DOUBLEBUFFER, //利用双缓冲模式
PFD_TYPE_RGBA, //利用RGBA色彩模式
24, //存储颜色数据的位数
0,0,0,0,0,0,
0,0,0,0,0,0,0,
32, //深度缓冲区巨细
0,0,
PFD_MAIN_PLANE, //在主平面上画图
0,
0,0,0
};
(2)选择最佳像素名目
int iPixelFormat=ChoosePixelFormat(hDC,&pfd);
选择一最适合上述pfd布局的像素名目,并把生存索引号。
SetPixelFormat(hDC,iPixelFormat,&pfd);
按选择的索引号配置设备描写表的像素名目。
(3)用DC建设RC
hRC=wglCreateContext(hDC);
用指定的设备描写表发生一个图形操纵描写表,使它在该设备描写表上画图,而且有与此设备描写表沟通的像素名目。
3、指定当前的DC、RC
wglMakeCurrent(hDC,hRC);
把发生的图形操纵描写表置为当前的,措施从此的所有OpenGL函数都通过此图形操纵描写表执行,并将图形绘制在设备描写表引用的设备上。
到此就完成了初始化事情,这些步调根基上是牢靠的(像素名目标参数配置也是如此),对付一般的应用可以直接利用上述语句。
二、在FormDestroy()中作清理事情以释放资源
1、清屏
glClearColor(0.0,0.0,0.0,1.0);
配置配景致为玄色。
glClear(GL_COLOR_BUFFER_BIT);
清屏以防备对今后窗口操纵的影响。
2、当前DC、RC置空
wglMakeCurrent(NULL,NULL);
使不再有当前的图形操纵描写表。
3、删除DC、RC
wglDeleteContext(hRC);
删除该图形操纵描写表。
DeleteObject(hDC);
删除该设备描写表。
假如在同一个措施里对多个窗体用画图必需严格举办清理,不然输出会呈现杂乱。
三、在FormPaint()中实施画图的相关操纵
#p#分页标题#e#
每当窗体重画时举办画图的行动。OnPaint事件大概由系统触发譬喻置为当前窗口;也可以由措施触发即在需要改变画图时挪用TForm->FormPaint(Sender)。把所有画图操纵统一归入FormPaint()事件的响应函数中使我们很容易节制画图的机缘,措施变得很有层次。
1、画图筹备
(1)指定DC
HDC hDC;
hDC=wglGetCurrentDC();
在多个设备描写表如多个画图面板时有须要指定从此OpenGL呼吁输出的方针。
(2)清屏
动态的图形输出必需有清屏的操纵将上此画图的功效以配景致包围掉,以便画新的图形。
glClearColor(0.0,0.0,0.0,1.0);
配景致以玄色为例。
glClear(GL_COLOR_BUFFER_BIT);
清屏呼吁。
(3)启动反走样成果(可选)
glEnable(GL_BLEND);
启动殽杂。
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
指定殽杂的属性。
glEnable(GL_LINE_SMOOTH);
启动线反走样。
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
指定为线反走样且为最好质量。
留意在画图竣事后要有相应的封锁反走样的操纵,以防备影响措施今后的操纵,语句如下
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
2、画图
挪用自界说的画图函数RenderSence()。
3、缓冲操纵
glFlush();
强制完成画图事情。
SwapBuffers(hDC);
完成两个图形缓冲区的互换,把画完的非显示缓冲图形显示出来。
四、编写画图函数
即界说RenderSence()函数,完成真正的画图操纵。实际上是把工程计较的功效作为参数挪用OpenGL的各类画图库函数。详细函数与画法请参阅有关书籍。我们把纯真的画图和结果设定单列出来作为一个函数供FormPaint()挪用,这样的布局使绘图编程变得很是机动。更巨大的环境可以写多个自界说画图函数,也可以引入参数列表。
五、视口调动
OpenGL中有多种图形调动,个中视口调动是较量简朴并且常用的调动方法,所以也归为本框架的一部门。事实上只需要利用一个函数
glViewport(0,0, ClientWidth, ClientHeight);
此函数可以指定全部图形最后投影的一个矩形区域,上句以整个窗体的客户区为例。在FormResize()事件响应函数中挪用这个函数可以使图形在窗体巨细形状变革时保持沟通比例的缩放。