51Testing软件测试论坛

标题: Delphi游戏编程导学——OpenGL入门 [打印本页]

作者: 51testing    时间: 2007-11-30 15:48
标题: 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[0..bp.Width,0..bp.Height,0..2] of Byte;
...
   for x := 0 to bp.Width -1 do
     for y := 0 to bp.Height - 1 do
     begin
       bb[x,y,0] := GetRvalue( bp.Canvas.Pixels[x,y] )
       bb[x,y,1] := GetGvalue( bp.Canvas.Pixels[x,y] );
       bb[x,y,2] := GetBvalue( bp.Canvas.Pixels[x,y] );
     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.






欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2