51testing 发表于 2007-11-30 15:48:28

Delphi游戏编程导学——OpenGL入门

这次我结合以前的教学,把入门知识给大家讲解完整,让摸不到门路的朋友尽快找到感觉。
我使用的OpenGL接口文件还是那个DOT,因为我很喜欢在VCL环境里编程,这样才能体现Delphi的高效。
关于DOT的安装,以及绘制简单的图形等等,请参考我以前的教学:
http://bbs.gameres.com/showthread.asp?threadid=66287
好了,开始我们这次的主题吧。
按照OpenGL官方的说法,纹理和贴图是两个概念。
纹理被称为material, 贴图被称为texture.
(其实中文是我自己翻译的,我完全是为了方便自己的理解)。
我们这次主要讲的是贴图,因为纹理的使用只要参照NeHe的教学或者红宝书/Super Bible 就能掌握了。
而贴图要实现,就不是很容易了。因为涉及到如何将硬盘(也可以是其它媒介)上的图形文件读取,并
转换成OpenGL的贴图格式这样的问题。
Delphi里想读取一个图形文件是很简单的,比如 bmp 图形的读取
var
bp : TBitmap;
...
bp := TBitmap.Create;
bp.LoadFromFile('name.bmp');
...
bp.Free
要转换成OpenGL的贴图格式,其实很简单,只要读取bmp图形的RGB值,
然后按照RGB的顺序保存到一个Byte数组里就行了。
var
   bb : array of Byte;
...
   for x := 0 to bp.Width -1 do
   for y := 0 to bp.Height - 1 do
   begin
       bb := GetRvalue( bp.Canvas.Pixels )
       bb := GetGvalue( bp.Canvas.Pixels );
       bb := GetBvalue( bp.Canvas.Pixels );
   end;
...
但是这次我可不想费劲来使用bmp图形,因为DOT里为我们准备好了更加方便的贴图生成方式。
好了,让我们来看看实际的代码吧。
//和上次教学里的代码一样的地方,我就不说了,重点看看新加的东西
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DotWindow, GL, GLu, GLext, TGA2;
//uses这里我只加了一个对 TGA2 单元的引用
type
TForm1 = class(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 BuildTexture;
    procedure DrawScene;
public
    { Public declarations }
end;
//这里我加了一个新函数 BuildTexture,是用于生成贴图的
var
Form1: TForm1;
implementation
{$R *.dfm}
//看看这个新函数的内容吧
procedure TForm1.BuildTexture;
var
bp      : TTGAImage;
//增加对 TGA2 单元的引用就是为了读取 tga 图形
//这里先声名一个tga图形类的变量
begin
//定义贴图的方式
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
//下面两句先申请内存,然后读取程序所在目录里的tga文件
bp := TTGAImage.Create;
bp.LoadFromFile('tex02.tga');
//如果你的显卡不支持BGR格式,就需要下面的语句
//bp.BGRtoRGB;
//分配贴图对象的号码
glBindTexture(GL_TEXTURE_2D, 100);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
            GL_LINEAR);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
            GL_LINEAR);
//这里是实际分配数据的地方,最后的参数直接读取bp的Data值就行了
          glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                     64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, bp.Data);
//创建第二个贴图,直接读取新的文件就可以了
bp.LoadFromFile('tex01.tga');
//bp.BGRtoRGB;
glBindTexture(GL_TEXTURE_2D, 200);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
            GL_LINEAR);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
            GL_LINEAR);
          glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                     64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, bp.Data);
//这是第三个贴图
bp.LoadFromFile('tex00.tga');
//bp.BGRtoRGB;
glBindTexture(GL_TEXTURE_2D, 300);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
            GL_LINEAR);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
            GL_LINEAR);
          glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                     64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, bp.Data);
bp.Free;
end;
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);
//绘制物体前调用分配的贴图
//前
glBindTexture(GL_TEXTURE_2D, 100);
glBegin(GL_QUADS);
    glColor3f(1, 0, 0);
//每个顶点前都要设置贴图坐标
    glTexCoord2F(0, 0);
    glVertex3f(-0.5,-0.5, 0.5);
    glTexCoord2F(1, 0);
    glVertex3f(0.5,-0.5, 0.5);
    glTexCoord2F(1, 1);
    glVertex3f(0.5, 0.5, 0.5);
    glTexCoord2F(0, 1);
    glVertex3f(-0.5, 0.5, 0.5);
glEnd;
//后
glBindTexture(GL_TEXTURE_2D, 300);
glBegin(GL_QUADS);
    glColor3f(0, 1, 0);
    glTexCoord2F(0, 0);
    glVertex3f(-0.5,-0.5,-0.5);
//    glVertex3f(0.5, -0.5,-0.5);
    glTexCoord2F(1, 0);
    glVertex3f(-0.5, 0.5,-0.5);
//    glVertex3f(-0.5, -0.5,-0.5);
    glTexCoord2F(1, 1);
    glVertex3f(0.5, 0.5,-0.5);
//    glVertex3f(-0.5, 0.5,-0.5);
    glTexCoord2F(0, 1);
    glVertex3f(0.5,-0.5,-0.5);
//    glVertex3f(0.5, 0.5,-0.5);
glEnd;
//左
glBindTexture(GL_TEXTURE_2D, 200);
glBegin(GL_QUADS);
    glColor3f(0, 0, 1);
    glTexCoord2F(0, 0);
    glVertex3f(-0.5,-0.5,-0.5);
    glTexCoord2F(1, 0);
    glVertex3f(-0.5,-0.5, 0.5);
    glTexCoord2F(1, 1);
    glVertex3f(-0.5, 0.5, 0.5);
    glTexCoord2F(0, 1);
    glVertex3f(-0.5, 0.5,-0.5);
glEnd;
//右
glBegin(GL_QUADS);
    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;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
dotSetDisplayMode(0, 0, 0, 0);
end;
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
else
begin
    Self.Height := 600;
    Self.Width:= 800;
end;
Self.Context.QuickPF(32, 0, 24, 0, 0);
Self.Context.InitGL;
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
//打开贴图模式
glEnable(GL_TEXTURE_2D);
glClearColor(0, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
    gluPerspective(60.0, Self.ClientWidth / Self.ClientHeight, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
//调用新函数
BuildTexture;
end;
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;
procedure TForm1.FormPaint(Sender: TObject);
begin
DrawScene;
end;

end.

页: [1]
查看完整版本: Delphi游戏编程导学——OpenGL入门