Delphi下的OpenGL开发入门_delphi吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:14,293贴子:
Delphi下的OpenGL开发入门收藏
OpenGL最初是由Silicon图形公司开发的底层图形库规范。你的系统中准确实现这个规范的部分,通常被称为OpenGL驱动,它允许你使用几何**(点,线,多边形,图像等等)来描述你希望表现的场景。让肉眼观察起来较为舒适的中等规模场景,通常在毫秒级的速度上实现,这意味着该库文件有足够的能力来支持你创建一个生机勃勃的虚拟世界。 OpenGL驱动一般以二进制库文件的形式提供。它能够动态的连接到你的程序中。在Windows平台上,它将是成为DLL的形式(在你的系统目录下检查opengl.dll)。自从Delphi能够使用任何DLL开始,它对OpenGL 3D编程的能力就像其他任何语言一样容易了。本文将帮助你获得在Delphi中进行OpenGL开发的有效知识。 数学基础 OpenGL拥有强大的数学基础,因此对它功能的限制完全取决于你的想象能力(译者注:没有做不到,只有想不到)。对于理解那些公理和引理,更好的是让我们立刻认识一个简单的3D坐标系统,它是3D编程中惯用的坐标系统。如下:
你应该如何理解你的屏幕(蓝色的方块)在场景中的放置位置呢?发出四条射线并形成屏幕的那个点,是该想象空间中的视点(point of view)。OpenGL让你调用两个简单的函数来定义这个场景 glMatrixMode(GL_PROJECTION); glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0); 在这个调用的过程中的-0.1,0.1,-0.1,0.1定义了这个可视屏幕的左上角和右下角坐标;0.3指定视愕狡聊坏木嗬?就好象“近剪贴板”(near clipping plane))同时25.0指定“远剪贴板”(far clipping plane)。任何近剪贴板前面的物体以及远剪贴板后面的物体都将不可见。当然,你能够任意摆弄这些数字,以使他们适合你需要的场景。 从基本元素(primitive)到对象 现在开始最有意思的部分:对象。OpenGL仅仅支持以下几种基本几何图形:点,线和多边形。没有表面或者更高级的图形(比如球状图形)能被作为基本图形元素绘制。但是它们能够用多边形完美的模仿出来。随意看看现代3D游戏,你会发现它们完全由三角形建立。因此,我们不会被此限制所约束。 对象的绘制非常类似Pascal语言编程。每个块都应该被begin-end包含着,更为确切的说是glBegin()和glEnd()。如同下面的例子: const S=1.0; D=5.0; ... glBegin(GL_TRIANGLES);
glVertex3f( -S, 0, D); glVertex3f(S, 0, D); glVertex3f(0, S, D); glE 这是个简单的三角形。它距离你的视点有5个单位,自身高1个单位,宽2个单位。 这是屏幕截图:
即使它看起来不象3D图形,但它是我们的初始块。在下面你可以看到这个例子的源代码。 在你开始钻研代码前,还有些话要说。每次OpenGL编程,都包含一些初始化输出设备的OS设定(OS-specific)代码。如果你使用Win32,你将需要设置像素格式以及建立显示上下文环境脱离windows设备上下文环境。如果windows系统级编程你并不很在行,你可以把如下的代码作为模版使用。FormCreate中被调用函数的详细信息可以参考帮助文档。 FILE: Tri.pas unit T interface uses OpenGL, Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComC type TForm1 = class(TForm) procedure FormCreate(Sender: TObject);
为客户提供快捷安全的数据库 数据恢复服务
procedure FormPaint(Sender: TObject); private procedure D //Draws an OpenGL scene on request public
var Form1: TForm1; implementation {$R *.DFM} procedure setupPixelFormat(DC:HDC); const pfd:TPIXELFORMATDESCRIPTOR = (
nSize:sizeof(TPIXELFORMATDESCRIPTOR); // size
nVersion:1; // version
dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or
PFD_DOUBLEBUFFER; // support double-buffering
iPixelType:PFD_TYPE_RGBA; // color type
cColorBits:24; // preferred color depth
cRedBits:0; cRedShift:0; // color bits (ignored)
cGreenBits:0; cGreenShift:0;
cBlueBits:0; cBlueShift:0;
cAlphaBits:0; cAlphaShift:0; // no alpha buffer
cAccumBits: 0;
cAccumRedBits: 0; // no accumulation buffer,
cAccumGreenBits: 0; // accum bits (ignored)
cAccumBlueBits: 0;
cAccumAlphaBits: 0;
cDepthBits:16; // depth buffer
cStencilBits:0; // no stencil buffer
cAuxBuffers:0; // no auxiliary buffers iLayerType:PFD_MAIN_PLANE; // main layer bReserved: 0; dwLayerMask: 0; dwVisibleMask: 0; dwDamageMask: 0; // no layer, visible, damage masks ); var pixelFormat: begin pixelFormat := ChoosePixelFormat(DC, @pfd); if (pixelFormat = 0) then
if (SetPixelFormat(DC, pixelFormat, @pfd) && TRUE) then
procedure GLI begin // set viewing projection glMatrixMode(GL_PROJECTION); glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0); // position viewer glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST);
procedure TForm1.FormCreate(Sender: TObject); var DC:HDC; RC:HGLRC; i: begin DC:=GetDC(Handle); //Actually, you can use any windowed control here SetupPixelFormat(DC); RC:=wglCreateContext(DC); //makes OpenGL window out of DC wglMakeCurrent(DC, RC); //makes OpenGL window active GLI //initialize OpenGL
procedure TForm1.D const S=1.0; D=5.0; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glLoadI glTranslatef(0.0, 0.0, -12.0); glBegin(GL_TRIANGLES); glVertex3f( -S, 0, D); glVertex3f(S, 0, D); glVertex3f(0, S, D); glE SwapBuffers(wglGetCurrentDC);
procedure TForm1.FormPaint(Sender: TObject);
end. FILE: Tri.dfm object Form1: TForm1 BorderStyle = bsDialog Caption = \'BASIC OpenGL Program\' ClientHeight = 318 ClientWidth = 373 OnCreate = FormCreate OnPaint = FormPaint end 3D历险 好了,让我们开始真正的3D吧。将先前的代码作为框架,我们增加一些画线的代码建立一个带阴影面的四面体。应该如何用基本图形元素来构建呢?我们使用四个三角形。一个在底部,另外三个作为侧面。这里就是生成他们的代码: procedure TForm1.D const D=1.5; H1=D/1.732; H2=D*1.732-H1; // D/H = tg(30) = 1/sqrt(3) HY=3.0; const //vertexes a1:TGLArrayf3=(-D, 0, -H1); //bootom left a2:TGLArrayf3=( D, 0, -H1); //bootom right a3:TGLArrayf3=( 0, 0, H2); //bootom back a4:TGLArrayf3=( 0, HY, 0); //top begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glLoadI glTranslatef(0.0, 0.0, -12.0); glBegin(GL_TRIANGLES); glVertex3fv(@a1); glVertex3fv(@a3); glVertex3fv(@a2); glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4); glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4); glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4); glE SwapBuffers(wglGetCurrentDC);
虽然看起来有点复杂,不过当你面对下面这张图时,它就很容易理解了。
我们定义顶点a1 - a4同时依据4个顶点位置建立指定的三角形。当你定义自己的三角形(或者其他的多边形),请使用如下的规则:始终按照逆时针顺序排列定点序号,就像你正在外部观看侧面一样。通过这个规则,我们可以指定指定a1-a2-a4,a1-a3-a2(仰视),a2-a3-a4和a3-a1-a4。 现在就替换Tri.pas中TForm1.Darw()部分,程序运行的效果不会体现出过多的变化。它看起来仍然不象三维图形。这是因为我们还没有设定任何光源。 LIGHTS! CAMERA! OPENGL! 在OpenGL中光源模式有两部分:光源自身(颜色,强度等等)和对象材质。材质,依次包括颜色,一些物理参数(比如不透明性光泽性)以及纹理。深入其中,这会是一个巨大的世界,我们将一步步地接近。 定义一个光源相当容易。 procedure GLI const light0_position:TGLArrayf4=( -8.0, 8.0, -16.0, 0.0); ambient: TGLArrayf4=( 0.3, 0.3, 0.3, 0.3); begin // set viewing projection glMatrixMode(GL_PROJECTION); glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0); // position viewer */ glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); // set lights glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_POSITION, @light0_position); glLightfv(GL_LIGHT0, GL_AMBIENT, @ambient); glEnable(GL_LIGHT0);
代码内的两个常量是必须的。一个定义光源位置(位于视点的后面的左上角),另外一个定义环境光线。这将产生少量的散乱光线,使你能够看到完全位于阴影中的某些物体。 虽然你可以使用光照设定光源,可是物体仍然没有绘制阴影。这是因为OpenGL需要知道你指定的每个多边形的“normal”以便进行光线计算(Normal是一个与表面正交的向量) 。如果你没有自己的向量函数库,可以使用以下方法计算三角形中三个顶点的normal。这个函数是以定点逆时针排列为基础的,因为normal是一个向量的叉积,如果你不遵守该规则,会使向量指向四面体内部。
function getNormal(p1,p2,p3:TGLArrayf3):TGLArrayf3; var a,b:TGLArrayf3; begin //make two vectors a[0]:=p2[0]-p1[0]; a[1]:=p2[1]-p1[1]; a[2]:=p2[2]-p1[2]; b[0]:=p3[0]-p1[0]; b[1]:=p3[1]-p1[1]; b[2]:=p3[2]-p1[2]; //calculate cross-product result[0]:=a[1]*b[2]-a[2]*b[1]; result[1]:=a[2]*b[0]-a[0]*b[2]; result[2]:=a[0]*b[1]-a[1]*b[0];
使用这个函数,就可以设定所有的计算光线必需的信息了: procedure TForm1.D const D=1.5; H1=D/1.732; H2=D*1.732-H1; // D/H = tg(30) = 1/sqrt(3) HY=3.0; const //vertexes a1:TGLArrayf3=(-D, 0, -H1); a2:TGLArrayf3=(D, 0, -H1); a3:TGLArrayf3=(0, 0, H2); a4:TGLArrayf3=(0, HY, 0); var n1, n2, n3, n4: TGLArrayf3; //normals begin n1 := getNormal(a1,a3,a2); n2 := getNormal(a1,a2,a4); n3 := getNormal(a2,a3,a4); n4 := getNormal(a3,a1,a4); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glEnable(GL_NORMALIZE); glShadeModel(GL_FLAT); glCullFace(GL_BACK); glLoadI glTranslatef(0.0, 0.0, -12.0); glBegin(GL_TRIANGLES); glNormal3fv(@n1); glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a3); glNormal3fv(@n2); glVertex3fv(@a1); glVertex3fv(@a2); glVertex3fv(@a4); glNormal3fv(@n3); glVertex3fv(@a2); glVertex3fv(@a3); glVertex3fv(@a4); glNormal3fv(@n4); glVertex3fv(@a3); glVertex3fv(@a1); glVertex3fv(@a4); glE SwapBuffers(wglGetCurrentDC);
这便是以上代码的效果:
现在,使用一点Delphi VCL提供的的东西。在窗体上放一个Timer,指定一个类成员“angle:single”并在每次Timer触发时让他增加1: procedure TForm1.Timer1Timer(Sender: TObject); begin angle:=angle+1.0; D
离一个充满生气的OpenGL仅差条线: glRotatef(angle, 0.0, 1.0, 0.0); 把它放在glBegin()内三角开始绘制前的位置上,这样你的阴影部分就可以旋转了,至此,一切结束。
看起来不错的
书名: 可视化OpenGL程序设计 作者: 费广正等编著 出版社: 清华大学出版社 出版日期: 2001 文摘: 本书对Delphi编程和OpenGL编程进行了完美的结合,首先讲解了如何在Delphi环境下正确设置环境进行OpenGL程序设计,然后介绍了OpenGL的基础知识和基本概念,并讲解了OpenGL的高级编程方法,最后通过实例对本书内容进行了全面总结。
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或您所在位置: &
 &  & 
NeHe的opengl教程delphi版.doc31页
本文档一共被下载:
次 ,您可免费全文在线阅读后下载本文档
文档加载中...广告还剩秒
需要金币:100 &&
你可能关注的文档:
??????????
??????????
NeHe的opengl教程delphi版 1 ----基本框架将CKER翻译的NeHe的VC 的OPENGL框架转成了Delphi版,希望对用Delphi学习OPENGL的兄弟有所帮助,不知为什么,我的Delphi环境下无法直接运行,但是在别的机器上好像没问题我的机器只能编译后运行EXE文件。感谢NeHe提供的这么好的框架,感谢CKER翻译的VC的资料
Program Project1;
Uses?? opengl,?? windows,?? M
Const?? WND_TITLE 'OPenGl 基本框架'; //标题Var?? // // 每一个OpenGL都被连接到一个着色描述表上。着色描述表将所有的OpenGL调用命令连?? // 接到Device Context 设备描述表 上,将OpenGL的着色描述表定义为hRC ,要让程序能?? // 够绘制窗口的话,还需要创建一个设备描述表,Windows的设备描述表被定义为 hDC,?? // DC将窗口连接到GDI Graphics Device Interface图形设备接口 。而RC将OpenGL连接?? // 到DC。?? // h_RC : HGLRC; // Rendering Context 着色描述表 。?? h_DC : HDC; // Device Context 设备描述表 h_Wnd : HWND; // 窗口句柄?? h_Instance : HINST; // 程序Instance 实例 。?? keys : Array[0..255] Of B // 用于键盘例程的数组 $R *.res // //重新设置OpenGL场景的大小,而不管窗口的大小是否已经改变 假定没有使用全屏模式 。?? //甚至无法改变窗口的大小时 例如在全屏模式下 ,它至少仍将运行一次————————?? //在程序开始时设置透视图。OpenGL场景的尺寸将被设置成它显示时所在窗口的大小。?? // Procedure glResizeWnd Width, Height: I // 重置并初始化GL窗口大小Begin?? If
Then // 防止高度为0,产生除0异常 Height :
1;?? glViewport 0, 0, Width, H // 重置当前的视口 Viewport //下面几行为透视图设置屏幕。意味着越远的东西看起来越小。这么做创建了一个现实?? //外观的场景。此处透视按照基于窗口宽度和高度的45度视角
正在加载中,请稍后...