delphi版的opengl入门.docx
《delphi版的opengl入门.docx》由会员分享,可在线阅读,更多相关《delphi版的opengl入门.docx(18页珍藏版)》请在冰豆网上搜索。
delphi版的opengl入门
第一、准备好OpenGL
windows平台下:
OpenGL是由SGI公司开发的低层三维图形API,目前已经成为工业标准,由独立非赢利组织ARB管理。
它在WINDOWS中以动态链接库的形式存在,Win95osr2以上版本及WinNT自带有微软公司实现的OpenGL。
但本人推荐使用SGI实现的OpenGL来调试程序,快速可靠而且功能丰富,缺点是它是纯软件实现,无法利用硬件加速。
下载了opengl95.exe或opengl2.exe之后执行之,按提示安装即可。
默认情况情况下会在C:
\oglsdk,包括了VC和BC的库及头文件,还有两个演示程序,不妨看看,FlyintheSky在窗口中移动鼠标就可控制飞行了,还有一份说明书,也不妨看看。
相关文件请到资源区下载
Linux平台下:
装一个Mesa好了,另外在gtk+(GtkGLArea)/qt(QGLWidget+QGLContext)中均包括了OpenGL支持构件(WIDGET),gnome下有许多OpenGL的应用。
注意在LD_LIBRARY_PATH加上必要的路径,详见各软件的安装说明(通常叫README或INSTALL)。
Solaris:
OpenGLLibrary
装上随Solaris发售的OpenGLlibrary。
如果执行以下命令:
>cd/usr/openwin/lib
>lslibGL*
结果显示如下:
libGL.so@libGLU.so@libGLw.so@
libGL.so.1*libGLU.so.1*libGLw.so.1*
则意味着OpenGL运行库已经装好了。
通常LD_LIBRARY_PATH里会有该目录,如果没有自己加上就成。
在/usr/openwin/include/GL下有以下头文件:
gl.hglu.hglxmd.hglxtokens.h
glmacros.hglx.hglxproto.h
在sun的网站有OpenGL开发者FAQ,可参阅。
MacOS:
OpenGLSDKforApple
OS/2:
不详。
BeOS:
不详。
2*******************************************************************
本文的2.1-2.4部分是针对BorlandC++Builder用户的头文件是O
C++5.0以上版本的头文件也行。
将C:
\oglskd\bclib下的文件拷至$BCB\Lib下。
为便于编写代码,要将opengl的帮助文件加入搜索范围。
在BCB3.0中可用Help|Customize调出OpenHelp设定程
序,在每一页中用Edit|AddFiles到\programfile\common\BorlandShared\MSHelp下找到必要的文件。
说明:
系统安装的dll与程序链接时使用的lib要一致,否则像素格式设置调用会失败。
2.2、GLUT库
为了在初期简化编程负担,可以使用独立于平台的GLUT库,在网上可以找到库、源文件、说明书,基于GLUT的
WINDOWS应用程序是WIN32CONSOL程序,主程序是intmain(int,void**),在其中可以只用两三行打开一个窗口,
并以填写几个回调函数的方式实现程序功能,省掉了与窗口系统打交道的麻烦。
另外,该库是做跨平台应用的首选
,它在几乎所有的平台上都可用。
目前还没有找到将glut与VCL可视开发结合的方法,所以本教程并没使用它。
安装glut运行库:
将这些DLL文件(V3.6)(V3.7β)复制到windows\system下,其中有两种版本的dll,分别对应
MS(*32.dll)和SGI实现的OpenGL(*.dll)。
将其中的glut.h复制到$BCB\Include\gl下,用BCB的implib.exe制作导
入库(*.lib),放到$BCB\Lib下。
GLUT使用指南<稍候>
2.3、GLAUX库
有一个glaux库(即redBook所用的编程环境),可以大简化窗口界面设定过程,但太过简陋,不推荐使用。
可
是为了便于阅读RedBook,现将在BCB中使用glaux的方法简述如下:
安装glaux运行库:
将BCB版aux库的DLL文件复制到windows\system下,将其中的glauximp.lib复制到$BCB\lib
下,或者用BCB的implib.exe制作导入库(*.lib)再复制到$BCB\Lib下。
BCB中已经带有aux库的头文件,aux库的源
码在VC中带有。
在程序之前加入:
USELIB("C:
\ProgramFiles\Borland\CBuilder3\Lib\glauximp.lib");
引号中为导入库所在的位置和名字。
GLAUX使用指南<稍候>
2.4、VCL元件
在CBuilder/Delphi环境下还可以使用各种VCL元件,常见的有:
下载并展开后,在BCB中加以安装即可,详情请自
行查阅其自带的readme,以后有空再逐个解说。
本人推荐使用DanielPlakosh的,简洁易用且带源程序,还可以用
BMP格式的图象作纹理。
本教程后期将会基于TOpenGLPanel,但前面会用通用的方法,不必借助任何附加元件。
DanielPlakoshsaid:
“Feelfreetowhateveryouwantwiththecomponent”
说明:
该控件对中文支持不灵,另外其内部会自动调用wglMakeCurrent(null,null),所以在OnMouse事件中进
行选取时要调用先MakeOpenGLPanelCurrent()。
TOpenglPanel安装说明:
如果曾经装过老版本的TOpenGLPanel,请先御掉。
在File菜单下选CloseAllFile以关闭所有文件。
在Component菜单下选InstallComponent。
在InstallComponent对话框中选IntoNewPackage页<必须IntoNewPackage>
在InotNewPackage页中如下填写各项:
UnitFileName:
填入或浏览(Browse)寻找含路径的单元文件名,如:
C:
\OpenGLv0.3BCB3\Component\TOpenGLPanel.cpp//不必完全相同,就看你把文件放在哪了
SearchPath:
这一条应该会自动填好。
如:
c:
\OpenGLv0.3BCB3\Component\
PackageFileName:
应该填为OpenGLPanel_DP
PackageDescription:
应该填为OpenGLPanelComponent
单击OK按纽
当提示“PackageOpenGLPanel_DP.bplwillbebuilttheninstalled.Conitnue?
”时点“Yes”。
当编译完成后,在File菜单下选SaveAll,用默认的文件名!
现在OpenGLPanelComponent就装好了,你可以在工具栏的最右端发现它。
调整BCB3的include及Lib的路径,例如:
INCLUDE:
$(BCB)\include;$(BCB)\include\vcl;c:
\dplakosh\openglv0.3bcb3\component
LIB:
$(BCB)\lib\obj;$(BCB)\lib;c:
\dplakosh\openglv0.3bcb3\component
//不必完全一样,你的文件在哪就填哪
$(BCB)代表CBuilder所在目录。
在你的系统路径中加入元件所在的目录,以便程序运行。
2.5、非BorlandC++Builder用户
BorlandC++/OWL
Delphi/Pascal+API
VisiIt是很好用的,不过封装得太厉害,对于学习者
3******************************************************************************
如果使用Aux/Glut/VCL则可免去这一步。
如果在窗口系统中使用OpenGL则必须给窗口加上WS_CLIPCHILDREN和WS_CLIPSIBLINGS两个属性,否则只能得到
黑屏。
注:
只在MDI应用中需要这样做。
在BCB中可在任何窗口控件的CREATEPARAMS成员函数中加入如下语句使之支持OpenGL:
//--以TForm为例
//--记得在unit1.h中classTForm1的priviate部分加入原型:
//--void__fastcallCreateParams(TCreateParams&Params);
//------------------------------------------
TForm1:
:
CreateParams(TCreateParams&Params)
{
//先调用父类中的成员函数,该函数继承自TWindowControl类
TForm:
:
CreateParams(Params);
Params.Style|=(WS_CLIPCHILDREN|WS_CLIPSIBLINGS);
}
//--------------------------------------
样本工程
所谓窗口控件是指从TWindowControl派生出来的各类控件,通常可见的控件都是窗口件,前面提到过TOpenglP
anel就是以TCustomPanel为基类派生的,查看其源码就会发现它对窗口属性的修改与上面所述完全相同。
注:
这是
最简的示例,为使程序在256色等环境中能正常运行,还要在此处理调色板问题
4***************************************************
OpenGL是一种基于客户/服务器和管道(PipeLine)的图形库。
即一个应用程序(客户)将各种命令和数据写入管道,这命令和数据将被暂时保存起来,图形库(服务器)直到收到一条专门的指令才会开始处理它们,并将处理结果通过管道传给用户。
所以OpenGL应用程序的基本结构就是:
建立管道根据需要向管道中写入数据和指令关闭管道在Windows95/NT环境中,这个管道就是OpenGL着色环境——(OpenGLRenderContext)简称RC。
因此建立管道实际上就是获取一个可用的RC。
而在Windows的GDI系统中进行图形显示是通过图形设备上下文——(DeviceContext)简称DC——进行的。
所以获取RC就是:
①先获取一个DC,②调整这个DC的象素格式(PixelFormat)以便OpenGL库进行绘制,③用DC去调用wglCreateContext(hDC)建立一个RC,④调用wglMakeCurrent(hRC,hDC)将刚才建立的RC指定为当前的RC。
当一个RC不再使用时就可以删除它,方法是:
使RC不是“当前RC”:
wglMakeCurrent(NULL,NULL);//不再有当前RCwglMakeCurrent(hAnotherRC,hDC);//另一个RC成为当前RCwglDEleteContent(hRC);//删除之
为了避免反复建设/删除RC所带来的不必要的开支,我们在TForm1中定义了hDC、hRC以保存DC和RC,并在TForm1的构造函数中建立并保存RC,直到清除这个Form即Destory()成员函数运行时才删除RC和DC。
主要代码如下:
void__fastcallTForm1:
:
CreateParams(TCreateParams&Params){//再次说明:
只在MDI应用有必要进行修改。
2000.2.17. TForm:
:
CreateParams(Params);//调用原有函数预处理 Params.Style|=WS_CLIPCHILDREN|WS_CLIPSIBLINGS;//加上必要的属性}//----------------------------------------------------__fastcallTForm1:
:
TForm1(TComponent*Owner) :
TForm(Owner){ hDC=GetDC(Handle);//获取一个DC,TForm1.Handle中保存有Form的窗口句柄 SetDCPixelFormat(hDC);//调整该DC的象素格式 hRC=wglCreateContext(hDC);//用这种DC去创建一个RC wglMakeCurrent(hDC,hRC);//指定当前DC、当前RC为hDC、hRC}//-------------------------------------------------------------------void__fastcallTForm1:
:
SetDCPixelFormat(HDChDC){ //本函数用于调整DC的象素格式,如缓冲区、颜色数等 //先不深究,只要知道它的作用就行intnPixelFormat;staticPIXELFORMATDESCRIPTORpfd={sizeof(PIXELFORMATDESCRIPTOR), //Sizeofthisstructure 1, //Versionofthisstructure PFD_DRAW_TO_WINDOW| //DrawtoWindow(nottobitmap) PFD_SUPPORT_OPENGL| //SupportOpenGLcallsinwindow PFD_DOUBLEBUFFER //Doublebufferedmode PFD_TYPE_RGBA, //RGBAColormode 24, //Want24bitcolor 0,0,0,0,0,0, //Notusedtoselectmode 0,0, //Notusedtoselectmode 0,0,0,0,0, //Notusedtoselectmode 32, //Sizeofdepthbuffer 0, //Notusedtoselectmode 0, //Notusedtoselectmode PFD_MAIN_PLANE, //Drawinmainplane 0, //Notusedtoselectmode 0,0,0}; //Notusedtoselectmode //ChooseapixelformatthatbestmatchesthatdescribedinpfdnPixelFormat=ChoosePixelFormat(hDC,&pfd); //SetthepixelformatforthedevicecontextSetPixelFormat(hDC,nPixelFormat,&pfd);}//-----------------------------------------------------------------void__fastcallTForm1:
:
FormPaint(TObject*Sender){ //该Form的绘制响应函数glClearColor(0.5,0.7,0.9,1.0);//指定背景颜色(依次为RGBA)glClear(GL_COLOR_BUFFER_BIT);//用背景色清窗口RenderScence(); //场景绘制SwapBuffers(hDC); //切交缓冲区,这就是可以启动图形库处理流程并得相应结果的两条命令之一 //如果当前RC相联DC具有DoubleBuffer的PixelFormat则用本命令 //否则就是单缓冲DC,用glFlush(void)进行更新。
}//-----------------------------------------------------void__fastcallTForm1:
:
FormDestroy(TObject*Sender){wglMakeCurrent(NULL,NULL); //取消当前RC和当前DCwglDeleteContext(hRC); //删除该RCDeleteObject(hDC); //删除WindowsDC。
}//-------------------------------------------------------------------
5**************************************************************************
如果用过3DS/LIGHTWAVE等任何一种三维图形软件包,就可以发现制作一个三维场景无非以下几项工作:
建模:
制作各种物体。
放置:
将做好的各物体通过平移、旋转等放到场景空间的适当位置。
上色:
给物体模型指定颜色或表面纹理。
打灯:
在场景中适当位置放置几盏灯以照亮场景。
摄像:
在空间适当位置放上适当角度的摄像机,以得到所需的视觉效果。
用OpenGL开发应用程序与之类似,通常是:
设定视见体
定义光源
生成场景
而三维图形生成的流程如下:
放置几何变换:
平移、旋转、缩放等
视见变换:
裁剪、消隐、投影等
视见体设定:
视见体有两种:
正投影体和透视投影体,正投影视见体中的物体在屏幕上的投影不会出现近大远小的现象,而透视投影视体则与人眼的观察结果类似,离观察点越远的物体在屏幕上的投影越小,因此透视投影体中的观察结果看起来更真实一些。
定义透视投影体的方法是:
glFrustum(left,right,bottom,top,near,far);
//物体在这六个参数界定的范围内可见,超出边界将被裁掉。
//left,bottom,代表左下right,top代表右上
定义透视投影体的方法是:
glOrtho(left,right,bottom,top,near,far);
//物体在这六个参数界定的范围内可见,超出边界将被裁掉。
综上所述,一个三维图形应用程序在建好OpenGLPipleline之后就要向管道发如下一系列的命令,以建立一个三维观察环境:
//1、设定视见体,在窗体的Resize事件时
void__fastcallTForm1:
:
FormResize(TObject*Sender)
{
glViewport(0,0,Width,Height);
//使用Form窗体的指定区域为显示区
//如改为Width/4,Height/4,Width/2,Width/2,
//则只用Form1的-窗体的中间1/4进行显示
glMatrixMode(GL_PROJECTION);//切换到投影矩阵栈
glLoadIdentity();//清除投影矩阵
glFrustum(1.0,-1.0,-1.0,1.0,1.0,-1.0);
//指定透视视见体范围
//超出部分将被裁去
//或正投影glOrtho(1.0,-1.0,-1.0,1.0,1.0,-1.0);
glMatrixMode(GL_MODELVIEW);//切换到模型视见矩阵栈
glLoadIdentity();//清除视见矩阵
}
6*******************************************************************
OpenGL中从三维场景到屏幕图形要经历如下所示的变换过程:
其中四种坐标经常要在程序中用到:
世界坐标,物体坐标,设备坐标和眼坐标。
世界坐标是OpenGL中用来描述场景的坐标,Z+轴垂直屏幕向外,X+从左到右,Y+轴从下到上,是右手笛卡尔坐标系统。
我们用这个坐标系来描述物体及光源的位置。
将物体放到场景中也就是将物体平移到特定位置、旋转一定角度,这些操作就是坐标变换。
OpenGL中提供了glTranslate*/glRotate*/glScale*三条坐标变换命令,利用OpenGL的矩阵运算命令,则可以实现任意复杂的坐标变换。
非常重要:
OpenGL中有一个坐标变换矩阵栈(ModelView),栈顶就是当前坐标变换矩阵,进入OpenGL管道的每个坐标(齐次坐标)都会先乘上这个矩阵,结果才是对应点在场景中的世界坐标。
OpenGL中的坐标变换都是通过矩阵运算完成的,与图形学课本的描述完全一致。
要注意的是变换中的矩阵乘法是左乘,而矩阵乘法与算术乘法不同,不符合交换律(万一不明白去看矩阵代数书好了)。
glTranslate*(x,y,z):
平移,参数为各轴向的移动量。
glRotate(d,x,y,z):
旋转,第一个参数为转动的度数,后三个参数表明是否绕该轴旋转。
通常x,y,z中只有一个为1,其余为0,用连续几条旋转命令完成复杂旋转。
由于矩阵运算的左乘特点,旋转命令的顺序与旋转动作的顺序正好相反。
物体坐标是以物体某一点为原点而建立的“世界坐标”,该坐标系仅对该物体适用,用来简化对物体各部分坐标的描述。
物体放到场景中时,各部分经历的坐标变换相同,相对位置不变,所以可视为一个整体,与人类的思维习惯一致。
眼坐标是以视点为原点,以视线的方向为Z+轴正方向的坐标系中的方向。
OpenGL管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视见体)之内的场景才会进入下一阶段的计算。
同样的,有投影变换矩阵栈(Projection),栈顶矩阵就是当前投影变换矩阵,负责将场景各坐标变换到眼坐标,由所得到的结果是裁剪后的场景部分,称为裁剪坐标。
前面提到过的视见体设定其实就是在建立该矩阵。
OpenGL的重要功能之一就是将三维的世界坐标经过变换、投影等计