游戏开发论坛

 找回密码
 立即注册
搜索
查看: 7401|回复: 8

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

[复制链接]

27

主题

418

帖子

455

积分

中级会员

Rank: 3Rank: 3

积分
455
QQ
发表于 2007-9-13 01:18:00 | 显示全部楼层 |阅读模式
以前曾经写过关于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.

27

主题

418

帖子

455

积分

中级会员

Rank: 3Rank: 3

积分
455
QQ
 楼主| 发表于 2007-9-13 01:27:00 | 显示全部楼层

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

这里是源代码。
我是用7Zip压缩的。
http://www.box.net/shared/cxim446zhu
那个tex.rar就是源代码

27

主题

418

帖子

455

积分

中级会员

Rank: 3Rank: 3

积分
455
QQ
 楼主| 发表于 2007-9-13 01:51:00 | 显示全部楼层

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

我建议只读取32位的TGA图形,其它的颜色深度似乎有些问题……

我的例子读取了三个TGA图形,
第一个没有透明信息,
第二个是背景透明,
第三个是文字透明,同时启用了TGA的压缩模式。

我把贴图贴到了前、后以及左,三个面。
后面的那个贴图不太正常,如果你能自己解决问题,那你就基本掌握OpenGL的贴图了。

请参考NeHe,红宝书或者 Super Bible 有关贴图的章节,
以便进一步学习使用 OpenGL 的贴图。

5

主题

755

帖子

757

积分

高级会员

Rank: 4

积分
757
发表于 2007-9-13 10:08:00 | 显示全部楼层

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

用Dephi还是Opengl还发到了DirectX区。。。。

27

主题

418

帖子

455

积分

中级会员

Rank: 3Rank: 3

积分
455
QQ
 楼主| 发表于 2007-9-13 18:49:00 | 显示全部楼层

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

这是综合区吧?

1367

主题

1993

帖子

2118

积分

金牌会员

Rank: 6Rank: 6

积分
2118
发表于 2007-9-17 17:11:00 | 显示全部楼层

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

up

197

主题

1041

帖子

1104

积分

金牌会员

Rank: 6Rank: 6

积分
1104
QQ
发表于 2007-9-17 18:09:00 | 显示全部楼层

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

n年前已不被编程语言局限

无用。

27

主题

418

帖子

455

积分

中级会员

Rank: 3Rank: 3

积分
455
QQ
 楼主| 发表于 2007-9-21 11:04:00 | 显示全部楼层

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

除非不写代码,不然是无法摆脱编程语言束缚的。

0

主题

2

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2007-10-1 20:35:00 | 显示全部楼层

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

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

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-21 00:54

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表