NeHe的opengl教程delphi版(6)----纹理映射(贴图)

原创 2003年08月04日 10:15:00

{

贴图可以极大的节省CPU时间。呵呵,但是这一节费了我比较多的时间 : (

因为用到了opengl的辅助库,现在这个库的函数已经很少有人用了,但是我还是找到了,感谢zdcnow(磁效应),他给我提供的这个辅助库的delphi版本。在学习本节之前,请大家到网上下载glaux.dll、Glaux.pas文件,并加到项目中。

好了,让我们继续OPENGL之路.

首先我们需要加进SysUtils单元,因为我们这节要用到文件操作,我们还要将Glaux单元加进来。

然后我们在第一课的基础上加上几个变量,xrot , yrot 和 zrot 。这些变量用来使立方体绕X、Y、Z轴旋转。texture[] 为一个纹理分配存储空间。如果您需要不止一个的纹理,应该将数字1改成您所需要的数字。

}

VAR

   h_RC             : HGLRC;            // Rendering Context(着色描述表)。
   h_DC             : HDC;              // Device Context(设备描述表)
   h_Wnd            : HWND;             // 窗口句柄
   h_Instance       : HINST;            // 程序Instance(实例)。
   keys             : Array[0..255] Of Boolean; // 用于键盘例程的数组

   xrot,                                // X 旋转量 ( 新增 )
   yrot,                                // Y 旋转量 ( 新增 )
   zrot             : GLfloat;          // Z 旋转量 ( 新增 )

  Texture          : Array[0..1] Of GLuint; // 存储一个纹理 ( 新增 )

{然后引载入opengl32.dll中的两个过程,我们要用到他们}


Procedure glGenTextures(n: GLsizei; Var textures: GLuint); stdcall; external
   opengl32;
Procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external
   opengl32;

{接下来我们需要增加一个新的函数,用来再入图像,该函数的返回类型在Glaux.pas中定义如下:

TAUX_RGBImageRec= record
       sizeX, sizeY: GLint;
        data: pointer;
          end;
 PTAUX_RGBImageRec= ^TAUX_RGBImageRec;

具体含义会在后面介绍}

Function LoadBmp(filename: pchar): PTAUX_RGBImageRec;
Var
   BitmapFile       : Thandle;          // 文件句柄
Begin
   //接下来检查文件名是否已提供
   If Filename = '' Then                // 确保文件名已提供。
      result := Nil;                    // 如果没提供,返回 NULL
   //接着检查文件是否存在。
   BitmapFile := FileOpen(Filename, fmOpenWrite); //尝试打开文件
   //如果我们能打开文件的话,很显然文件是存在的。

   If BitmapFile > 0 Then               // 文件存在么?
      Begin
         //关闭文件。
         FileClose(BitmapFile);         // 关闭句柄
         //auxDIBImageLoad(Filename) 读取图象数据并将其返回。
         result := auxDIBImageLoadA(filename); //载入位图并返回指针
      End
   Else
      //如果我们不能打开文件,我们将返回NiL。
      result := Nil;                    // 如果载入失败,返回NiL。
End;

//接下来在创建一个新函数,用来载入纹理贴图

Function LoadTexture: boolean;

//Status 的变量。我们使用它来跟踪是否能够载入位图以及能否创建纹理。
// Status 缺省设为 FALSE (表示没有载入或创建任何东东)。
//TextureImage变量PTAUX_RGBImageRec类型  存储位图的图像记录。
//次记录包含位图的宽度、高度和数据。

Var
   Status           : boolean;
   TextureImage     : Array[0..1] Of PTAUX_RGBImageRec;
Begin
   Status := false;
   ZeroMemory(@TextureImage, sizeof(TextureImage)); // 将指针设为 NULL
   TextureImage[0] := LoadBMP('Texture.bmp');
   If TextureImage[0] <> Nil Then
      Begin
         Status := TRUE;                // 将 Status 设为 TRUE
         //现在使用中 TextureImage[0] 的数据创建纹理。
         //glGenTextures(1, texture[0]) 告诉OpenGL我们想生成一个纹理名字
         //(如果您想载入多个纹理,加大数字)。
         //glBindTexture(GL_TEXTURE_2D, texture[0]) 告诉OpenGL将纹理名字 texture[0] 绑定到纹理目标上。
         //2D纹理只有高度(在 Y 轴上)和宽度(在 X 轴上)。
         //主函数将纹理名字指派给纹理数据。
         //本例中我们告知OpenGL, &texture[0] 处的内存已经可用。
         //我们创建的纹理将存储在 &texture[0] 的 指向的内存区域。
         glGenTextures(1, texture[0]);  // 创建纹理
         glBindTexture(GL_TEXTURE_2D, texture[0]);  // 使用来自位图数据生成 的典型纹理
         //下来我们创建真正的纹理。
         //下面一行告诉OpenGL此纹理是一个2D纹理 ( GL_TEXTURE_2D )。
         //数字零代表图像的详细程度,通常就由它为零去了。
         //数字三是数据的成分数。因为图像是由红色数据,绿色数据,蓝色数据三种组分组成。
         //TextureImage[0].sizeX 是纹理的宽度。
         //如果您知道宽度,您可以在这里填入,但计算机可以很容易的为您指出此值。
         // TextureImage[0].sizey 是纹理的高度。
         //数字零是边框的值,一般就是零。
         // GL_RGB 告诉OpenGL图像数据由红、绿、蓝三色数据组成。
         //GL_UNSIGNED_BYTE 意味着组成图像的数据是无符号字节类型的。
         //最后... TextureImage[0].data 告诉OpenGL纹理数据的来源。
         //此例中指向存放在 TextureImage[0] 记录中的数据。

         // 生成纹理
         glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
            TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
            TextureImage[0].data);

         //下面的两行告诉OpenGL在显示图像时,
         //当它比放大得原始的纹理大(GL_TEXTURE_MAG_FILTER)
         //或缩小得比原始得纹理小(GL_TEXTURE_MIN_FILTER)时OpenGL采用的滤波方式。
         //通常这两种情况下我都采用 GL_LINEAR。这使得纹理从很远处到离屏幕很近时都平滑显示。
         //使用 GL_LINEAR需要CPU和显卡做更多的运算。
         //如果您的机器很慢,您也许应该采用 GL_NEAREST 。
         //过滤的纹理在放大的时候,看起来斑驳的很(马赛克啦)。
         //您也可以结合这两种滤波方式。在近处时使用 GL_LINEAR ,远处时 GL_NEAREST 。
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  // 线形滤波
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  // 线形滤波
      End;
   //现在我们释放前面用来存放位图数据的内存。
   //我们先查看位图数据是否存放在处。
   //如果是的话,再查看数据是否已经存储。
   //如果已经存储的话,删了它。
   //接着再释放 TextureImage[0] 图像结构以保证所有的内存都能释放。
   If assigned(TextureImage[0]) Then    // 纹理是否存在
      If assigned(TextureImage[0].data) Then // 纹理图像是否存在
         TextureImage[0].data := Nil;   // 释放纹理图像占用的内存
   TextureImage[0] := Nil;              // 释放图像结构
   // 最后返回状态变量。如果一切OK,变量 Status 的值为 TRUE 。否则为 FALSE
   result := Status;                    // 返回 Status
End;

//然后在 glInit 中增加很少的几行代码

Procedure glInit();
Begin
   If (Not LoadTexture) Then            // 调用纹理载入子例程( 新增 )
      exit;                             // 如果未能载入,退出( 新增 )
   glEnable(GL_TEXTURE_2D);             // 启用纹理映射( 新增 )
   glClearColor(0.0, 0.0, 0.0, 0.0);    // 黑色背景
   glShadeModel(GL_SMOOTH);             // 启用阴影平滑
   glClearDepth(1.0);                   // 设置深度缓存
   glEnable(GL_DEPTH_TEST);             // 启用深度测试
   glDepthFunc(GL_LESS);                // 所作深度测试的类型
   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正

End;

{现在我们绘制贴图过的立方体。这段代码被狂注释了一把,应该很好懂。开始两行代码 glClear() glLoadIdentity() 是第一课中就有的代码。 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 清除屏幕并设为我们在 InitGL() 中选定的颜色,本例中是黑色。深度缓存也被清除。模型观察矩阵也使用glLoadIdentity()重置。}

Procedure glDraw();
Begin
   glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
   glLoadIdentity();                    // 重置当前的模型观察矩阵
   glTranslatef(0.0, 0.0, -6.0);        // 移入屏幕6个单位

   //下面三行使立方体绕X、Y、Z轴旋转。
   //旋转多少依赖于变量 xrot , yrot 和 zrot 的值。
   glRotatef(xrot, 1.0, 0.0, 0.0);      // 绕X轴旋转
   glRotatef(yrot, 0.0, 1.0, 0.0);      // 绕Y轴旋转
   glRotatef(zrot, 0.0, 0.0, 1.0);      // 绕Z轴旋转

   //下一行代码选择我们使用的纹理。
   //如果在场景中使用多个纹理,应该使用
   //glBindTexture(GL_TEXTURE_2D, texture[ 所使用纹理对应的数字 ]) 来选择要绑定的纹理。
   //当想改变纹理时,应该绑定新的纹理。
   //有一点值得指出的是,
   //不能在 glBegin() 和 glEnd() 之间绑定纹理,
   //必须在 glBegin() 之前或 glEnd() 之后绑定。
   //注意我们在后面是如何使用 glBindTexture 来指定和绑定纹理的。

   glBindTexture(GL_TEXTURE_2D, texture[0]); // 选择纹理

   //为了将纹理正确的映射到四边形上,
   //必须将纹理的右上角映射到四边形的右上角,
   //纹理的左上角映射到四边形的左上角,
   //纹理的右下角映射到四边形的右下角,
   //纹理的左下角映射到四边形的左下角。
   //如果映射错误的话,图像显示时可能上下颠倒,侧向一边或者什么都不是。

   //glTexCoord2f 的第一个参数是X坐标。
   // 0.0是纹理的左侧。 0.5是纹理的中点, 1.0是纹理的右侧。
   //glTexCoord2f 的第二个参数是Y坐标。
   //0.0是纹理的底部。 0.5是纹理的中点, 1.0是纹理的顶部。
   //所以纹理的左上坐标是 X:0.0f,Y:1.0f ,
   //四边形的左上顶点是 X: -1.0f,Y:1.0f 。
   //其余三点依此类推。

   //试着玩玩 glTexCoord2f 的X,Y坐标参数。
   //把1.0改为0.5将只显示纹理的左半部分,
   //把0.0改为0.5将只显示纹理的右半部分。
   glBegin(GL_QUADS);
   // 前面
   glTexCoord2f(0.0, 0.0);
   glVertex3f(-1.0, -1.0, 1.0);         // 纹理和四边形的左下
   glTexCoord2f(1.0, 0.0);
   glVertex3f(1.0, -1.0, 1.0);          // 纹理和四边形的右下
   glTexCoord2f(1.0, 1.0);
   glVertex3f(1.0, 1.0, 1.0);           // 纹理和四边形的右上
   glTexCoord2f(0.0, 1.0);
   glVertex3f(-1.0, 1.0, 1.0);          // 纹理和四边形的左上
   // 后面
   glTexCoord2f(1.0, 0.0);
   glVertex3f(-1.0, -1.0, -1.0);        // 纹理和四边形的右下
   glTexCoord2f(1.0, 1.0);
   glVertex3f(-1.0, 1.0, -1.0);         // 纹理和四边形的右上
   glTexCoord2f(0.0, 1.0);
   glVertex3f(1.0, 1.0, -1.0);          // 纹理和四边形的左上
   glTexCoord2f(0.0, 0.0);
   glVertex3f(1.0, -1.0, -1.0);         // 纹理和四边形的左下
   // 顶面
   glTexCoord2f(0.0, 1.0);
   glVertex3f(-1.0, 1.0, -1.0);         // 纹理和四边形的左上
   glTexCoord2f(0.0, 0.0);
   glVertex3f(-1.0, 1.0, 1.0);          // 纹理和四边形的左下
   glTexCoord2f(1.0, 0.0);
   glVertex3f(1.0, 1.0, 1.0);           // 纹理和四边形的右下
   glTexCoord2f(1.0, 1.0);
   glVertex3f(1.0, 1.0, -1.0);          // 纹理和四边形的右上
   // 底面
   glTexCoord2f(1.0, 1.0);
   glVertex3f(-1.0, -1.0, -1.0);        // 纹理和四边形的右上
   glTexCoord2f(0.0, 1.0);
   glVertex3f(1.0, -1.0, -1.0);         // 纹理和四边形的左上
   glTexCoord2f(0.0, 0.0);
   glVertex3f(1.0, -1.0, 1.0);          // 纹理和四边形的左下
   glTexCoord2f(1.0, 0.0);
   glVertex3f(-1.0, -1.0, 1.0);         // 纹理和四边形的右下
   // 右面
   glTexCoord2f(1.0, 0.0);
   glVertex3f(1.0, -1.0, -1.0);         // 纹理和四边形的右下
   glTexCoord2f(1.0, 1.0);
   glVertex3f(1.0, 1.0, -1.0);          // 纹理和四边形的右上
   glTexCoord2f(0.0, 1.0);
   glVertex3f(1.0, 1.0, 1.0);           // 纹理和四边形的左上
   glTexCoord2f(0.0, 0.0);
   glVertex3f(1.0, -1.0, 1.0);          // 纹理和四边形的左下
   // 左面
   glTexCoord2f(0.0, 0.0);
   glVertex3f(-1.0, -1.0, -1.0);        // 纹理和四边形的左下
   glTexCoord2f(1.0, 0.0);
   glVertex3f(-1.0, -1.0, 1.0);         // 纹理和四边形的右下
   glTexCoord2f(1.0, 1.0);
   glVertex3f(-1.0, 1.0, 1.0);          // 纹理和四边形的右上
   glTexCoord2f(0.0, 1.0);
   glVertex3f(-1.0, 1.0, -1.0);         // 纹理和四边形的左上
   glEnd();

   xrot := xrot + 0.3;                  // X 轴旋转
   yrot := yrot + 0.2;                  // Y 轴旋转
   zrot := zrot + 0.4;                  // Z 轴旋转
End;

{最后,关于用作纹理的图像我想有几点十分重要,并且您必须明白。此图像的宽和高必须是2的n次方;宽度和高度最小必须是64象素;并且出于兼容性的原因,图像的宽度和高度不应超过256象素。如果您的原始素材的宽度和高度不是64,128,256象素的话,使用图像处理软件重新改变图像的大小。可以肯定有办法能绕过这些限制,但现在我们只需要用标准的纹理尺寸。}

//OK!运行一下看看效果

NeHe OpenGL教程 第六课 纹理映射

学习如何使用纹理映射有很多的好处。比如说,你想绘制一颗导弹从屏幕上飞过。这节课之前,你可能想通过使用多边形来组成导弹,再加上一些颜色。通过使用纹理映射,你可以使用一张导弹的图片来绘制导弹,然后让这张图...
  • ygc87
  • ygc87
  • 2011年09月20日 01:49
  • 2534

opengl学习笔记1:vs2013 nehe教程第一课 创建窗口

近来需要想学习一下opengl,但是小白没有任何基础,也非计算机专业出身,只能一步一步学习nehe的程序来学习了。这里实现了在WIN10 vs2013 opengl2.0 环境下跑通nehe教程第一课...
  • caimagic
  • caimagic
  • 2016年01月29日 15:11
  • 1032

新手上路:Jeff Molofee(NeHe) 的 OPENGL 教程-第一课

Jeff Molofee(NeHe) 的 OPENGL 教程#1
  • cker
  • cker
  • 2001年04月28日 00:04
  • 4229

【OpenGL】nehe教程第一课学习笔记

nehe教程的第一课主要讲了OpenGL程序的创建。 它引用了最基本的gl.h、glu.h、glaux.h三个头文件。 包含了五个函数,分别是InitGL、ResizeGLScene、DrawGLSc...
  • lzh1590
  • lzh1590
  • 2017年03月22日 16:22
  • 243

对OpenGL的初步认识及多版本框架介绍(基于NeHe的OpenGL教程)

由于以后接触的技术和图形有关,所以最近也是来学学习一下opengl的相关知识点。当然有看到《opengl编程指南》这本红宝书,但是对于初学者来言,这本书需要花很多精力,所以我找到了《NeHe的open...
  • aptx704610875
  • aptx704610875
  • 2014年06月30日 01:25
  • 1453

NeHe OpenGL系列教程(中英文版附带VC++源码)中英文系列

NeHe OpenGL教程(中英文版附带VC++源码)中英文系列 Lesson 01-lesson 02 创建一个OpenGL窗口: 如何创建三角形和四边形 http://ieee...
  • jmppok
  • jmppok
  • 2013年12月16日 10:25
  • 1866

[OpenGL] Simple Bump mapping(简单凹凸纹理映射)

reference:原文地址 code:下载源代码 注:这份代码年代比较久远了,直接跑会提示各种未定义标识符,经过查阅发现这些都是glew中的。如果想要通过编译,首先需要配置并include gl...
  • ZJU_fish1996
  • ZJU_fish1996
  • 2016年08月21日 22:48
  • 2589

OpenGL学习脚印: 环境纹理映射(environment mapping)

写在前面 上一节初步学习了使用cubeMap创建天空包围盒,本节继续深入Cubemap这个主题,学习环境纹理贴图。本节示例程序均可以从我的github下载。 本节内容整理自: 1....
  • ziyuanxiazai123
  • ziyuanxiazai123
  • 2016年09月16日 21:41
  • 3308

glscene:delphi 开源的十分好用的opengl控件

虽然我之前一直都不知道3D是怎么做出来的,看了下asphyre、delphix也是云里雾里。直到装了glscene。网站:www.glscene.org 网站上说:glscene is an Open...
  • seewind
  • seewind
  • 2006年09月12日 13:16
  • 3080

OpenGL学习脚印: 二维纹理映射(2D textures)

写在前面 前面两节介绍了向量和矩阵,以及坐标和转换相关的数学,再继续讨论模型变换等其他包含数学内容的部分之前,本节介绍二维纹理映射,为后面学习做一个准备。纹理映射本身也是比较大的主题,本节只...
  • ziyuanxiazai123
  • ziyuanxiazai123
  • 2016年05月20日 17:17
  • 15834
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:NeHe的opengl教程delphi版(6)----纹理映射(贴图)
举报原因:
原因补充:

(最多只允许输入30个字)