{
這一課我會教您如何使用三種不同的紋理濾波方式。
教您如何使用鍵盤來移動場景中的對象,還會教您在OpenGL場景中應(yīng)用簡單的光照。
這一課包含了很多內(nèi)容,如果您對前面的課程有疑問的話,先回頭復(fù)習(xí)一下。
進(jìn)入后面的代碼之前,很好的理解基礎(chǔ)知識十分重要。
我們還是在第一課的代碼上加以修改。
跟以前不一樣的是,只要有任何大的改動,我都會寫出整段代碼。
首先我們還要加進(jìn)SysUtils單元和Glaux單元。
}
Uses
SysUtils,
opengl,
windows,
Messages,
Glaux In '../../GLAUX/Glaux.pas';
//下面幾行是增加新的變量。
//我們增加三個布爾變量。
// light 變量跟蹤光照是否打開。
//變量lp和fp用來存儲'L' 和'F'鍵是否按下的狀態(tài)。
//后面我會解釋這些變量的重要性。現(xiàn)在,先放在一邊吧。
light : Boolean; // 光源的開/關(guān)
lp : Boolean; // L鍵按下了么?
fp : Boolean; // F鍵按下了么?
//現(xiàn)在設(shè)置5個變量來控制繞x軸和y軸旋轉(zhuǎn)角度的步長,
//以及繞x軸和y軸的旋轉(zhuǎn)速度。
//另外還創(chuàng)建了一個z變量來控制進(jìn)入屏幕深處的距離。
xrot : GLfloat; // X 旋轉(zhuǎn)
yrot : GLfloat; // Y 旋轉(zhuǎn)
xspeed : GLfloat; // X 旋轉(zhuǎn)速度
yspeed : GLfloat; // Y 旋轉(zhuǎn)速度
z : GLfloat = -5.0 f; // 深入屏幕的距離
//接著設(shè)置用來創(chuàng)建光源的數(shù)組。
//我們將使用兩種不同的光。
//第一種稱為環(huán)境光。環(huán)境光來自于四面八方。
//所有場景中的對象都處于環(huán)境光的照射中。
//第二種類型的光源叫做漫射光。
//漫射光由特定的光源產(chǎn)生,并在您的場景中的對象表面上產(chǎn)生反射。
//處于漫射光直接照射下的任何對象表面都變得很亮,
//而幾乎未被照射到的區(qū)域就顯得要暗一些。
//這樣在我們所創(chuàng)建的木板箱的棱邊上就會產(chǎn)生的很不錯的陰影效果。
//創(chuàng)建光源的過程和顏色的創(chuàng)建完全一致。
//前三個參數(shù)分別是RGB三色分量,最后一個是alpha通道參數(shù)。
//因此,下面的代碼我們得到的是半亮(0.5f)的白色環(huán)境光。
//如果沒有環(huán)境光,未被漫射光照到的地方會變得十分黑暗。
LightAmbient : Array[0..3] Of GLfloat = (0.5, 0.5, 0.5, 1.0); //環(huán)境光參數(shù) ( 新增 )
//下一行代碼我們生成最亮的漫射光。
//所有的參數(shù)值都取成最大值1.0f。
//它將照在我們木板箱的前面,看起來挺好。
LightDiffuse : Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0); // 漫射光參數(shù) ( 新增 )
//最后我們保存光源的位置。
//前三個參數(shù)和glTranslate中的一樣。
//依次分別是XYZ軸上的位移。
//由于我們想要光線直接照射在木箱的正面,所以XY軸上的位移都是0.0。
//第三個值是Z軸上的位移。
//為了保證光線總在木箱的前面,
//所以我們將光源的位置朝著觀察者(就是您哪。)挪出屏幕。
//我們通常將屏幕也就是顯示器的屏幕玻璃所處的位置稱作Z軸的0.0點。
//所以Z軸上的位移最后定為2.0。
//假如您能夠看見光源的話,它就浮在您顯示器的前方。
//當(dāng)然,如果木箱不在顯示器的屏幕玻璃后面的話,您也無法看見箱子。
//『譯者注:我很欣賞NeHe的耐心。
//說真的有時我都打煩了,這么簡單的事他這么廢話干嘛?
//但如果什么都清楚,您還會翻著這樣的頁面看個沒完么?』
//最后一個參數(shù)取為1.0f。
//這將告訴OpenGL這里指定的坐標(biāo)就是光源的位置,以后的教程中我會多加解釋。
LightPosition : Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0); // 光源位置 ( 新增 )
//filter 變量跟蹤顯示時所采用的紋理類型。
//第一種紋理(texture 0) 使用gl_nearest(不光滑)濾波方式構(gòu)建。
//第二種紋理 (texture 1) 使用gl_linear(線性濾波) 方式,
//離屏幕越近的圖像看起來就越光滑。
//第三種紋理 (texture 2) 使用 mipmapped濾波方式,
//這將創(chuàng)建一個外觀十分優(yōu)秀的紋理。
//根據(jù)我們的使用類型,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';
{
現(xiàn)在載入一個位圖,并用它創(chuàng)建三種不同的紋理。
這一課使用glaux輔助庫來載入位圖,
因此在編譯時您應(yīng)該確認(rèn)是否包含了glaux庫。
我知道Delphi和VC++都包含了glaux庫,但別的語言不能保證都有。
『譯者注:glaux是OpenGL輔助庫,根據(jù)OpenGL的跨平臺特性,
所有平臺上的代碼都應(yīng)通用。但輔助庫不是正式的OpenGL標(biāo)準(zhǔn)庫,
沒有出現(xiàn)在所有的平臺上。但正好在Win32平臺上可用。
呵呵,BCB當(dāng)然也沒問題了。』這里我只對新增的代碼做注解。
如果您對某行代碼有疑問的話,請查看教程六。
那一課很詳細(xì)的解釋了載入、創(chuàng)建紋理的內(nèi)容。
在上一段代碼后面及 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); // 關(guān)閉句柄
result := auxDIBImageLoadA(filename); //載入位圖并返回指針
End
Else
result := Nil; // 如果載入失敗,返回NiL。
End;
Function LoadTexture: boolean; // 載入位圖并轉(zhuǎn)換成紋理
Var
Status : boolean; // Status 指示器
TextureImage : Array[0..1] Of PTAUX_RGBImageRec; // 創(chuàng)建紋理的存儲空間
Begin
Status := false;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // 將指針設(shè)為 NULL
TextureImage[0] := LoadBMP('Walls.bmp');
If TextureImage[0] <> Nil Then
Begin
Status := TRUE; // 將 Status 設(shè)為 TRUE
glGenTextures(1, texture[0]); // 創(chuàng)建紋理
//第六課中我們使用了線性濾波的紋理貼圖。
//這需要機(jī)器有相當(dāng)高的處理能力,但它們看起來很不錯。
//這一課中,我們接著要創(chuàng)建的第一種紋理使用 GL_NEAREST方式。
//從原理上講,這種方式?jīng)]有真正進(jìn)行濾波。
//它只占用很小的處理能力,看起來也很差。
//唯一的好處是這樣我們的工程在很快和很慢的機(jī)器上都可以正常運行。
//您會注意到我們在 MIN 和 MAG 時都采用了GL_NEAREST,
//你可以混合使用 GL_NEAREST 和 GL_LINEAR。
//紋理看起來效果會好些,但我們更關(guān)心速度,所以全采用低質(zhì)量貼圖。
//MIN_FILTER在圖像繪制時小于貼圖的原始尺寸時采用。
//MAG_FILTER在圖像繪制時大于貼圖的原始尺寸時采用。
// 創(chuàng)建 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]中的話,他將覆蓋前面創(chuàng)建的 GL_NEAREST紋理。
glBindTexture(GL_TEXTURE_2D, texture[1]); // 使用來自位圖數(shù)據(jù)生成 的典型紋理
// 生成紋理
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 線形濾波
//下面是創(chuàng)建紋理的新方法。 Mipmapping!
//『譯者注:這個詞的中文我翻不出來,不過沒關(guān)系。看完這一段,您就知道意思最重要。』
//您可能會注意到當(dāng)圖像在屏幕上變得很小的時候,很多細(xì)節(jié)將會丟失。
//剛才還很不錯的圖案變得很難看。當(dāng)您告訴OpenGL創(chuàng)建一個 mipmapped的紋理后,
//OpenGL將嘗試創(chuàng)建不同尺寸的高質(zhì)量紋理。當(dāng)您向屏幕繪制一個mipmapped紋理的時候,
//OpenGL將選擇它已經(jīng)創(chuàng)建的外觀最佳的紋理(帶有更多細(xì)節(jié))來繪制,
//而不僅僅是縮放原先的圖像(這將導(dǎo)致細(xì)節(jié)丟失)。
//我曾經(jīng)說過有辦法可以繞過OpenGL對紋理寬度和高度所加的限制——64、128、256,等等。
//辦法就是 gluBuild2DMipmaps。據(jù)我的發(fā)現(xiàn),您可以使用任意的位圖來創(chuàng)建紋理。
//OpenGL將自動將它縮放到正常的大小。
//因為是第三個紋理,我們將它存到texture[2]。這樣本課中的三個紋理全都創(chuàng)建好了。
// 創(chuàng)建 MipMapped 紋理
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST); // ( 新增 )
//下面一行生成 mipmapped 紋理。
//我們使用三種顏色(紅,綠,藍(lán))來生成一個2D紋理。
//TextureImage[0].sizeX 是位圖寬度,
//TextureImage[0].sizeY 是位圖高度,
//(====不知為什么,delphi下這個函數(shù)沒有height這個參數(shù),
//但是幫助中卻有,不知delphi再搞什么,郁悶ing......
//最后我在前面自己寫了一個gluBuild2DMipmaps,
//來載入glu32.dll中的gluBuild2DMipmaps函數(shù)=====)
//GL_RGB意味著我們依次使用RGB色彩。
//GL_UNSIGNED_BYTE 意味著紋理數(shù)據(jù)的單位是字節(jié)。
//TextureImage[0].data指向我們創(chuàng)建紋理所用的位圖。
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0].sizeX,
TextureImage[0].sizey, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data); //(新增) }
End;
If assigned(TextureImage[0]) Then // 紋理是否存在
If assigned(TextureImage[0].data) Then // 紋理圖像是否存在
TextureImage[0].data := Nil; // 釋放紋理圖像占用的內(nèi)存
TextureImage[0] := Nil; // 釋放圖像結(jié)構(gòu)
result := Status; // 返回 Status
End;
//接著應(yīng)該載入紋理并初始化OpenGL設(shè)置了。
//GLInit函數(shù)的第一行使用上面的代碼載入紋理。
//創(chuàng)建紋理之后,我們調(diào)用glEnable(GL_TEXTURE_2D)啟用2D紋理映射。
//陰影模式設(shè)為平滑陰影( smooth shading )。
//背景色設(shè)為黑色,我們啟用深度測試,然后我們啟用優(yōu)化透視計算。
Procedure glInit(); // 此處開始對OpenGL進(jìn)行所有設(shè)置
Begin
If (Not LoadTexture) Then // 調(diào)用紋理載入子例程
exit; // 如果未能載入,退出
glEnable(GL_TEXTURE_2D); // 啟用紋理映射
glShadeModel(GL_SMOOTH); // 啟用陰影平滑
glClearColor(0.0, 0.0, 0.0, 0.0); // 黑色背景
glClearDepth(1.0); // 設(shè)置深度緩存
glEnable(GL_DEPTH_TEST); // 啟用深度測試
glDepthFunc(GL_LESS); // 所作深度測試的類型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //高度優(yōu)化的透視投影計算
//現(xiàn)在開始設(shè)置光源。下面下面一行設(shè)置環(huán)境光的發(fā)光量,
//光源light1開始發(fā)光。
//這一課的開始處我們我們將環(huán)境光的發(fā)光量存放在LightAmbient數(shù)組中。
//現(xiàn)在我們就使用此數(shù)組(半亮度環(huán)境光)。
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]); // 設(shè)置環(huán)境光
//接下來我們設(shè)置漫射光的發(fā)光量。它存放在LightDiffuse數(shù)組中(全亮度白光)。
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]); // 設(shè)置漫射光
//然后設(shè)置光源的位置。
//位置存放在 LightPosition 數(shù)組中
//(正好位于木箱前面的中心,X-0.0,Y-0.0,Z方向移向觀察者2個單位<位于屏幕外面>)。
glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // 光源位置
//最后,我們啟用一號光源。我們還沒有啟用GL_LIGHTING,
//所以您看不見任何光線。
//記住:只對光源進(jìn)行設(shè)置、定位、甚至啟用,光源都不會工作。
//除非我們啟用GL_LIGHTING。
glEnable(GL_LIGHT1); // 啟用一號光源
End;
//下一段代碼繪制貼圖立方體。我只對新增的代碼進(jìn)行注解。
//如果您對沒有注解的代碼有疑問,回頭看看第六課。
Procedure glDraw(); // 從這里開始進(jìn)行所有的繪制
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度緩存
glLoadIdentity(); // 重置當(dāng)前的模型觀察矩陣
//下三行代碼放置并旋轉(zhuǎn)貼圖立方體。
//glTranslatef(0.0,0.0,z)將立方體沿著Z軸移動Z單位。
//glRotatef(xrot,1.0f,0.0f,0.0f)將立方體繞X軸旋轉(zhuǎn)xrot。
//glRotatef(yrot,0.0f,1.0f,0.0f)將立方體繞Y軸旋轉(zhuǎn)yrot。
glTranslatef(0.0, 0.0, z); // 移入/移出屏幕 z 個單位
glRotatef(xrot, 1.0, 0.0, 0.0); // 繞X軸旋轉(zhuǎn)
glRotatef(yrot, 0.0, 1.0, 0.0); // 繞Y軸旋轉(zhuǎn)
//下一行與我們在第六課中的類似。
//有所不同的是,這次我們綁定的紋理是texture[filter],
//而不是上一課中的texture[0]。
//任何時候,我們按下F鍵,filter 的值就會增加。
//如果這個數(shù)值大于2,變量filter 將被重置為0。
//程序初始時,變量filter 的值也將設(shè)為0。
//使用變量filter 我們就可以選擇三種紋理中的任意一種。
glBindTexture(GL_TEXTURE_2D, texture[filter]); // 選擇由filter決定的紋理
glBegin(GL_QUADS); // 開始繪制四邊形
//glNormal3f是這一課的新東西。Normal就是法線的意思,
//所謂法線是指經(jīng)過面(多邊形)上的一點且垂直于這個面(多邊形)的直線。
//使用光源的時候必須指定一條法線。法線告訴OpenGL這個多邊形的朝向,并指明多邊形的正面和背面。
//如果沒有指定法線,什么怪事情都可能發(fā)生:不該照亮的面被照亮了,多邊形的背面也被照亮....。
//對了,法線應(yīng)該指向多邊形的外側(cè)。看著木箱的前面您會注意到法線與Z軸正向同向。
//這意味著法線正指向觀察者-您自己。這正是我們所希望的。
//對于木箱的背面,也正如我們所要的,法線背對著觀察者。
//如果立方體沿著X或Y軸轉(zhuǎn)個180度的話,前側(cè)面的法線仍然朝著觀察者,背面的法線也還是背對著觀察者。
//換句話說,不管是哪個面,只要它朝著觀察者這個面的法線就指向觀察者。
//由于光源緊鄰觀察者,任何時候法線對著觀察者時,這個面就會被照亮。
//并且法線越朝著光源,就顯得越亮一些。
//如果您把觀察點放到立方體內(nèi)部,你就會法線里面一片漆黑。
//因為法線是向外指的。如果立方體內(nèi)部沒有光源的話,當(dāng)然是一片漆黑。
// 前面
glNormal3f(0.0, 0.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); // 紋理和四邊形的左上
// 后面
glNormal3f(0.0, 0.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); // 紋理和四邊形的左下
// 頂面
glNormal3f(0.0, 1.0, 0.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); // 紋理和四邊形的右上
// 底面
glNormal3f(0.0, -1.0, 0.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); // 紋理和四邊形的右下
// 右面
glNormal3f(1.0, 0.0, 0.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); // 紋理和四邊形的左下
// 左面
glNormal3f(-1.0, 0.0, 0.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 + xspeed; // xrot 增加 xspeed 單位
yrot := Yrot + yspeed; // yrot 增加 yspeed 單位
End;
//現(xiàn)在轉(zhuǎn)入WinMain()主函數(shù)。
//我們將在這里增加開關(guān)光源、旋轉(zhuǎn)木箱、切換過濾方式以及將木箱移近移遠(yuǎn)的控制代碼。
//在接近WinMain()函數(shù)結(jié)束的地方你會看到SwapBuffers(hDC)這行代碼。
//然后就在這一行后面添加如下的代碼。
//代碼將檢查L鍵是否按下過。
//如果L鍵已按下,但lp的值不是false的話,意味著L鍵還沒有松開,這時什么都不會發(fā)生。
SwapBuffers(h_DC); // 交換緩存 (雙緩存)
If (keys[ord('L')] And Not lp) Then
Begin
//如果lp的值是false的話,
//意味著L鍵還沒按下,或者已經(jīng)松開了,接著lp將被設(shè)為TRUE。
//同時檢查這兩個條件的原因是為了防止L鍵被按住后,
//這段代碼被反復(fù)執(zhí)行,并導(dǎo)致窗體不停閃爍。
//lp設(shè)為true之后,計算機(jī)就知道L鍵按過了,
//我們則據(jù)此可以切換光源的開/關(guān):布爾變量light控制光源的開關(guān)。
lp := true; // lp 設(shè)為 TRUE
light := Not light; // 切換光源的 TRUE/FALSE
If Not light Then // 如果沒有光源
glDisable(GL_LIGHTING) //禁用光源
Else // Otherwis
glEnable(GL_LIGHTING); //啟用光源
End;
If Not keys[ord('L')] Then //L鍵松開了么?
lp := FALSE; // 若是,則將lp設(shè)為FALSE
//然后對"F"鍵作相似的檢查。
//如果有按下"F"鍵并且"F"鍵沒有處于按著的狀態(tài)或者它就從沒有按下過,
//將變量fp設(shè)為true。這意味著這個鍵正被按著呢。
//接著將filter變量加一。如果filter變量大于2
//(因為這里我們的使用的數(shù)組是texture[3],大于2的紋理不存在),
//我們重置filter變量為0。
If (keys[ord('F')] And Not fp) Then // F鍵按下了么?
Begin
fp := TRUE; // fp 設(shè)為 TRUE
inc(filter); // filter的值加一
If filter > 2 Then // 大于2了么?
filter := 0; // 若是重置為0
End;
If Not keys[ord('F')] Then //F鍵放開了么?
fp := FALSE; // 若是fp設(shè)為FALSE
//這四行檢查是否按下了PageUp鍵。若是的話,減少z變量的值。這樣DrawGLScene函數(shù)中包含的glTranslatef(0.0f,0.0f,z)調(diào)用將使木箱離觀察者更遠(yuǎn)一點。
If keys[VK_PRIOR] Then //PageUp按下了?
z := z - 0.02; // 若按下,將木箱移向屏幕內(nèi)部。
//接著四行檢查PageDown鍵是否按下,若是的話,增加z變量的值。這樣DrawGLScene函數(shù)中包含的glTranslatef(0.0f,0.0f,z)調(diào)用將使木箱向著觀察者移近一點。
If keys[VK_NEXT] Then // PageDown按下了么?
z := z + 0.02; //若按下的話,將木箱移向觀察者。
//現(xiàn)在檢查方向鍵。按下左右方向鍵xspeed相應(yīng)減少或增加。
//按下上下方向鍵yspeed相應(yīng)減少或增加。
//記住在以后的教程中如果xspeed、yspeed的值增加的話,立方體就轉(zhuǎn)的更快。
//如果一直按著某個方向鍵,立方體會在那個方向上轉(zhuǎn)的越快。
If keys[VK_UP] Then // Up方向鍵按下了么?
xspeed := xspeed - 0.01; //若是,減少xspeed
If keys[VK_DOWN] Then //Down方向鍵按下了么?
xspeed := xspeed + 0.01; //若是,增加xspeed
If keys[VK_RIGHT] Then //Right方向鍵按下了么?
yspeed := yspeed + 0.01; //若是,增加yspeed
If keys[VK_LEFT] Then //Left方向鍵按下了么?
yspeed := yspeed - 0.01; //若是, 減少yspeed
If (keys[VK_ESCAPE]) Then // 如果按下了ESC鍵
finished := True
運行一下看看效果
新聞熱點
疑難解答
圖片精選