{ 这一课我会教您如何使用三种不同的纹理滤波方式。 教您如何使用键盘来移动场景中的对象,还会教您在OpenGL场景中应用简单的光照。 这一课包含了很多内容,如果您对前面的课程有疑问的话,先回头复习一下。 进入后面的代码之前,很好的理解基础知识十分重要。 我们还是在第一课的代码上加以修改。 跟以前不一样的是,只要有任何大的改动,我都会写出整段代码。
首先我们还要加进SysUtils单元和Glaux单元。 }
Uses SysUtils, opengl, windows, Messages, Glaux In ''''..\..\GLAUX\Glaux.pas'''';
//下面几行是增加新的变量。
//我们增加三个布尔变量。 // light 变量跟踪光照是否打开。 //变量lp和fp用来存储''''L'''' 和''''F''''键是否按下的状态。 //后面我会解释这些变量的重要性。现在,先放在一边吧。 light : Boolean; // 光源的开/关 lp : Boolean; // L键按下了么? fp : Boolean; // F键按下了么?
//现在设置5个变量来控制绕x轴和y轴旋转角度的步长, //以及绕x轴和y轴的旋转速度。 //另外还创建了一个z变量来控制进入屏幕深处的距离。 xrot : GLfloat; // X 旋转 yrot : GLfloat; // Y 旋转 xspeed : GLfloat; // X 旋转速度 yspeed : GLfloat; // Y 旋转速度
z : GLfloat = -5.0 f; // 深入屏幕的距离
//接着设置用来创建光源的数组。 //我们将使用两种不同的光。 //第一种称为环境光。环境光来自于四面八方。 //所有场景中的对象都处于环境光的照射中。 //第二种类型的光源叫做漫射光。 //漫射光由特定的光源产生,并在您的场景中的对象表面上产生反射。 //处于漫射光直接照射下的任何对象表面都变得很亮, //而几乎未被照射到的区域就显得要暗一些。 //这样在我们所创建的木板箱的棱边上就会产生的很不错的阴影效果。 //创建光源的过程和颜色的创建完全一致。 //前三个参数分别是RGB三色分量,最后一个是alpha通道参数。
//因此,下面的代码我们得到的是半亮(0.5f)的白色环境光。 //如果没有环境光,未被漫射光照到的地方会变得十分黑暗。 LightAmbient : Array[0..3] Of GLfloat = (0.5, 0.5, 0.5, 1.0); //环境光参数 ( 新增 ) //下一行代码我们生成最亮的漫射光。 //所有的参数值都取成最大值1.0f。 //它将照在我们木板箱的前面,看起来挺好。 LightDiffuse : Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0); // 漫射光参数 ( 新增 ) //最后我们保存光源的位置。 //前三个参数和glTranslate中的一样。 //依次分别是XYZ轴上的位移。 //由于我们想要光线直接照射在木箱的正面,所以XY轴上的位移都是0.0。 //第三个值是Z轴上的位移。 //为了保证光线总在木箱的前面, //所以我们将光源的位置朝着观察者(就是您哪。)挪出屏幕。 //我们通常将屏幕也就是显示器的屏幕玻璃所处的位置称作Z轴的0.0点。 //所以Z轴上的位移最后定为2.0。 //假如您能够看见光源的话,它就浮在您显示器的前方。 //当然,如果木箱不在显示器的屏幕玻璃后面的话,您也无法看见箱子。 //『译者注:我很欣赏NeHe的耐心。 //说真的有时我都打烦了,这么简单的事他这么废话干嘛? //但如果什么都清楚,您还会翻着这样的页面看个没完么?』 //最后一个参数取为1.0f。 //这将告诉OpenGL这里指定的坐标就是光源的位置,以后的教程中我会多加解释。 LightPosition : Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0); // 光源位置 ( 新增 )
//filter 变量跟踪显示时所采用的纹理类型。 //第一种纹理(texture 0) 使用gl_nearest(不光滑)滤波方式构建。 //第二种纹理 (texture 1) 使用gl_linear(线性滤波) 方式, //离屏幕越近的图像看起来就越光滑。 //第三种纹理 (texture 2) 使用 mipmapped滤波方式, //这将创建一个外观十分优秀的纹理。 //根据我们的使用类型,filter 变量的值分别等于 0, 1 或 2 。 //下面我们从第一种纹理开始。 //texture为三种不同纹理分配储存空间。 //它们分别位于在 texture[0], texture[1] 和 texture[2]中。
filter : GLuint; // 滤波类型 texture : Array[0..2] Of GLuint; // 3种纹理的储存空间
Procedure glGenTextures(n: GLsizei; Var textures: GLuint); stdcall; external opengl32;
Procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external opengl32;
Function gluBuild2DMipmaps(target: GLenum; components, width, height: GLint; format, atype: GLenum; data: Pointer): Integer; stdcall; external glu32 name ''''gluBuild2DMipmaps'''';
{ 现在载入一个位图,并用它创建三种不同的纹理。 这一课使用glaux辅助库来载入位图, 因此在编译时您应该确认是否包含了glaux库。 我知道Delphi和VC++都包含了glaux库,但别的语言不能保证都有。 『译者注:glaux是OpenGL辅助库,根据OpenGL的跨平台特性, 所有平台上的代码都应通用。但辅助库不是正式的OpenGL标准库, 没有出现在所有的平台上。但正好在Win32平台上可用。 呵呵,BCB当然也没问题了。』这里我只对新增的代码做注解。 如果您对某行代码有疑问的话,请查看教程六。 那一课很详细的解释了载入、创建纹理的内容。 在上一段代码后面及 glResizeWnd ()之前的位置, 我们增加了下面的代码。这和第六课中载入位图的代码几乎相同。 }
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); // 关闭句柄 result := auxDIBImageLoadA(filename); //载入位图并返回指针 End Else result := Nil; // 如果载入失败,返回NiL。 End;
Function LoadTexture: boolean; // 载入位图并转换成纹理 Var Status : boolean; // Status 指示器 TextureImage : Array[0..1] Of PTAUX_RGBImageRec; // 创建纹理的存储空间 Begin Status := false; ZeroMemory(@TextureImage, sizeof(TextureImage)); // 将指针设为 NULL TextureImage[0] := LoadBMP(''''Walls.bmp''''); If TextureImage[0] <> Nil Then Begin Status := TRUE; // 将 Status 设为 TRUE glGenTextures(1, texture[0]); // 创建纹理 //第六课中我们使用了线性滤波的纹理贴图。 //这需要机器有相当高的处理能力,但它们看起来很不错。 //这一课中,我们接着要创建的第一种纹理使用 GL_NEAREST方式。 //从原理上讲,这种方式没有真正进行滤波。 //它只占用很小的处理能力,看起来也很差。 //唯一的好处是这样我们的工程在很快和很慢的机器上都可以正常运行。 //您会注意到我们在 MIN 和 MAG 时都采用了GL_NEAREST, //你可以混合使用 GL_NEAREST 和 GL_LINEAR。 //纹理看起来效果会好些,但我们更关心速度,所以全采用低质量贴图。 //MIN_FILTER在图像绘制时小于贴图的原始尺寸时采用。 //MAG_FILTER在图像绘制时大于贴图的原始尺寸时采用。
// 创建 Nearest 滤波贴图 glBindTexture(GL_TEXTURE_2D, texture[0]); // 生成纹理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // ( 新增 ) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // ( 新增 )
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX, TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0].data);
//下个纹理与第六课的相同,线性滤波。唯一的不同是这次放在了 //texture[1]中。因为这是第二个纹理。如果放在 //texture[0]中的话,他将覆盖前面创建的 GL_NEAREST纹理。 glBindTexture(GL_TEXTURE_2D, texture[1]); // 使用来自位图数据生成 的典型纹理 // 生成纹理 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX, TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, &nb [1] [2] [3] [4] 下一页 [系统软件]InstallShield Express for delphi制作安装程序定… [常用软件]InstallShield Express制作Delphi数据库安装程序 [Delphi程序]为什么选择Delphi.Net ? [Delphi程序]《关于VisiBroker For Delphi的使用》(4) [Delphi程序]Delphi 程序员代码编写标准指南 [Delphi程序]转贴:Conversion to Delphi 6: Missing unit Pro… [Delphi程序]Borland Delphi 9 的新特性 [Delphi程序]Delphi 键盘码表 [Delphi程序]Chuck Jazdzewski的离开意味着Delphi的终结吗? [Delphi程序]Delphi Access violations 问题的解决之道
|