人气 407

[游戏程序] 用Delphi编写OpenGL导学——下[转帖] [复制链接]

九艺网 2017-3-10 17:02:21

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x

不说废话了,让我们看看如何用Delphi编写OpenGL吧。
以前也有人写过Delphi如何编写OpenGL,不过都是根据OpenGL教科书将编程语言翻译成了Delphi而已,并没有体现出Delphi的方便高效。我的教学会让你见识到Delphi编写OpenGL的方便和高效的。
为了实现我的说法,你需要一个函数库。这是外国朋友写的,主要是为了方便Delphi编写OpenGL程序。以后你不用再使用Delphi自带的糟糕的Opengl函数库了。函数库叫 DOT,你可以去 delphi3d.net下载。或者下载本贴的附件。我修改了代码,增加了对累积缓存(Accumulations buffers)的支持。大家按需选择吧。

我讲讲如何使用吧。首先把下载得到的压缩包里所有的文件解压到某个目录里,比如 D:\DOT。然后,运行Delphi,选择Tools菜单下的Options,在Options里选择Library,然后点击Library path旁边的 ... 在打开的对话框里还是点击 ... 接着选择刚才解压的目录(如D:\DOT)然后点击确定,再点Add,这样你刚才的解压目录就加到了库搜索路径里。你还要在Browsing path里增加你的解压目录,过程和Library path一样,我就不重复了。
不过,上述设置以后,你还无法在你的程序里调用DOT函数库。你还需要在程序的 uses 里增加至少四个项目,如下:
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DotWindow, GL, GLu, GLext;
最后四个就是你要增加的项目了。
现在,准备工作一切就绪,我们可以进入OpenGL的世界了!
首先,有几个窗体属性需要设置。在窗体设计窗口,单击选择窗体,然后在Object Inspector面板里,找到BorderIcons项,展开,把除了biSystemMenu以外的项都改成False。再找到BorderStyle,把值改成bsSingle。再把Height改成480,Width改成640。好了,窗体设置到此结束,可以写代码了。
新项目的代码如下,我们一步步让它画出一个可以由用户控制的正方形吧。
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
end.

首先是uses里增加DotWindow, GL, GLu, GLext,变成
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DotWindow, GL, GLu, GLext;
然后给窗体添加几个事件,增加几个变量和函数,最终代码如下
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DotWindow, GL, GLu, GLext;
type
  TForm1 = class(TDotForm)    //注意这里,要把原来的TForm改成现在的TDotForm      
    procedure FormPaint(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    bFullScreen : Bool;             //决定是否用全屏显示
    rX, rY      : GLuint;           //旋转角度
    procedure DrawScene;
    procedure LoadExtensions;
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
程序首先创建窗体,产生OnCreate事件,这时调用FormCreate过程。在这个过程里,初始化OpenGL的一些参数
procedure TForm1.FormCreate(Sender: TObject);
begin
  bFullScreen := False;
  rX := 360;
  rY := 360;
  if bFullScreen then
  begin
    dotSetDisplayMode(800, 600, 32, 60);
    Self.BorderStyle := bsNone;
    Self.Height := 600;
    Self.Width  := 800;
    Self.WindowState := wsMaximized;
    Self.Context.DC  := GetDC(Self.Handle);
    ShowCursor(False);
  end;
  Self.Context.QuickPF(32, 0, 24, 0, 0);
  Self.Context.InitGL;
  LoadExtensions;
  glShadeModel(GL_SMOOTH);
  glEnable(GL_DEPTH_TEST);
  glClearColor(0, 0, 0, 0);
  glMatrixMode(GL_PROJECTION);
    gluPerspective(60.0, Self.ClientWidth / Self.ClientHeight, 1.0, 100.0);
  glMatrixMode(GL_MODELVIEW);

end;
书上能找到的内容我就不讲了,我只讲DOT特有的函数
dotSetDisplayMode
要用到四个参数,前两个设置屏幕的分辨率(比如640,480;1024,768),第三个设置颜色深度(8,16,32 还是选择32吧,省得麻烦),最后一个设置屏幕刷新率(60最保险)
Self.Context.QuickPF
用于设置像素格式的。函数默认设置了双缓存,共有五个参数(原版是四个)。分别设置 色彩缓存位数,透明缓存位数,深度缓存位数,模版缓存位数以及 累积缓存位数。
Self.Context.InitGL
利用刚才设置的像素格式,生成OpenGL的Context(还是不要乱翻译的好  

                               
登录/注册后可看大图
);
注意:Self. 可以不用写,我写出来是为了防止混乱。
LoadExtensions
用于调用OpenGL的扩展功能。函数定义如下
procedure TForm1.LoadExtensions;
  procedure Load(const ext: String);
  begin
    if not glext_LoadExtension(ext) then
      raise Exception.Create('This demo requires ' + ext + '!');
  end;
begin
  {*****************************************************************************
    Load all required OpenGL extensions here, and throw an exception if any of
    them are not found.
   ****************************************************************************}
  Load('GL_ARB_multitexture');
  Load('GL_EXT_texture_filter_anisotropic');
end;
OpenGL的初始化完成了。
窗体显示任何东西,都会产生OnPaint事件,所以在FormPaint过程里添加OpenGL的绘图函数
procedure TForm1.FormPaint(Sender: TObject);
begin
  DrawScene;
end;
DrawScene 函数定义如下
procedure TForm1.DrawScene;
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glLoadIdentity;
  glTranslatef(0, 0, -3);
  glRotatef(rX, 1, 0, 0);
  glRotatef(rY, 0, 1, 0);
  glBegin(GL_QUADS);
    glColor3f(1, 0, 0);
    glVertex3f(-0.5,-0.5, 0.5);
    glVertex3f(0.5,-0.5, 0.5);
    glVertex3f(0.5, 0.5, 0.5);
    glVertex3f(-0.5, 0.5, 0.5);
///////////////////////////////////////
    glColor3f(0, 1, 0);
    glVertex3f(-0.5,-0.5,-0.5);
    glVertex3f(-0.5, 0.5,-0.5);
    glVertex3f(0.5, 0.5,-0.5);
    glVertex3f(0.5,-0.5,-0.5);
//////////////////////////////////////
    glColor3f(0, 0, 1);
    glVertex3f(-0.5,-0.5,-0.5);
    glVertex3f(-0.5,-0.5, 0.5);
    glVertex3f(-0.5, 0.5, 0.5);
    glVertex3f(-0.5, 0.5,-0.5);
//////////////////////////////////////
    glColor3f(1, 1, 0);
    glVertex3f(0.5,-0.5,-0.5);
    glVertex3f(0.5, 0.5,-0.5);
    glVertex3f(0.5, 0.5, 0.5);
    glVertex3f(0.5,-0.5, 0.5);
/////////////////////////////////////
    glColor3f(1, 0, 1);
    glVertex3f(-0.5, 0.5,-0.5);
    glVertex3f(-0.5, 0.5, 0.5);
    glVertex3f(0.5, 0.5, 0.5);
    glVertex3f(0.5, 0.5,-0.5);
////////////////////////////////////
    glColor3f(1, 1, 1);
    glVertex3f(-0.5,-0.5,-0.5);
    glVertex3f(0.5,-0.5,-0.5);
    glVertex3f(0.5,-0.5, 0.5);
    glVertex3f(-0.5,-0.5, 0.5);
  glEnd;
  Self.Context.PageFlip;
end;
对了,别忘了在程序关闭时,会产生OnClose事件,所以要在FormClose过程里加一个函数调用
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  dotSetDisplayMode(0, 0, 0, 0);
end;
如果使用了全屏显示,调用dotSetDisplayMode(0, 0, 0, 0)可以恢复原来的屏幕设置。窗口模式调用此函数没有任何不良影响。
现在运行程序就能看见一个正方形了。但是还不能控制。这时就要用到FormKeyDown过程了。
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    VK_UP:
    begin
      if rX = 0 then
        rX := 360;
      Dec(rX);
      DrawScene;
    end;
    VK_DOWN:
    begin
      if rX = 720 then
        rX := 360;
      Inc(rX);
      DrawScene;
    end;
    VK_LEFT:
    begin
      if rY = 0 then
        rY := 360;
      Dec(rY);
      DrawScene;
    end;
    VK_RIGHT:
    begin
      if rY = 720 then
        rY := 360;
      Inc(rY);
      DrawScene;
    end;
    VK_ESCAPE:
      Close;
  end;
end;
现在运行程序,就可以用键盘上的方向键控制正方体旋转了,而且只要按键盘的Esc键就能退出程序了。
怎么样,简单吗?
什么,不简单?!你按照OpenGL教材上的方法,或者用C/C++编写我这个程序以后再发表意见吧。
DOT让我们摆脱了繁琐的OpenGL初始化设置(当然不只如此,DOT更方便的功能需要你更深入的学习OpenGL才能体会到)。
Delphi让我们不用为创建、修改窗体,响应键盘消息等等基本Windows编程而费神。
两者的结合让我们可以轻松编写OpenGL程序了!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

QQ|手机版|小黑屋|九艺游戏动画论坛 ( 津ICP备2022000452号-1 )

GMT+8, 2024-4-19 02:46 , Processed in 0.055303 second(s), 23 queries .

Powered by Discuz! X3.4  © 2001-2017 Discuz Team.