Delphi下的OpenGL开发入门
原文地址:http://bdn.borland.com/article/0,1410,26401,00.html
概要:这篇文章犹如循序渐进教人做菜的食谱,使Delphi开发者获得OpenGL 3D 图形编程的有效知识。
原著:Alex Semichastny
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);
glEnd;
这是个简单的三角形。它距离你的视点有5个单位,自身高1个单位,宽2个单位。
这是屏幕截图:
即使它看起来不象3D图形,但它是我们的初始块。在下面你可以看到这个例子的源代码。
在你开始钻研代码前,还有些话要说。每次OpenGL编程,都包含一些初始化输出设备的OS设定(OS-specific)代码。如果你使用Win32,你将需要设置像素格式以及建立显示上下文环境脱离windows设备上下文环境。如果windows系统级编程你并不很在行,你可以把如下的代码作为模版使用。FormCreate中被调用函数的详细信息可以参考帮助文档。
FILE: Tri.pas
unit Tri;
inte易做图ce
uses
OpenGL, Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, ComCtrls;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
private
procedure Draw; //Draws an OpenGL scene on request
public
end;
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:integer;
begin
pixelFormat := ChoosePixelFormat(DC, @pfd);
if (pixelFormat = 0) then
exit;
if (SetPixelFormat(DC, pixelFormat, @pfd) <> TRUE) then
exit;
end;
procedure GLInit;
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);
end;
procedure TForm1.FormCreate(Sender: TObject);
var DC:HDC;
RC:HGLRC;
i:integer;
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
GLInit; //initialize OpenGL
end;
procedure TForm1.Draw;
const S=1.0; D=5.0;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glLoadIdentity;
glTranslatef(0.0, 0.0, -12.0);
glBegin(GL_TRIANGLES);
glVertex3f( -S, 0, D); glVertex3f(S, 0, D); glVertex3f(0, S, D);
glEnd;
SwapBuffers(wglGetCurrentDC);
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
Draw;
end;
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.Draw;
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);
glLoadIdentity;
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)
补充:软件开发 , Delphi ,