分享
 
 
 

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

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

{

贴图可以极大的节省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!运行一下看看效果

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有