NeHe的opengl教程delphi版(7)----濾波 (轉)
{
這一課我會教您如何使用三種不同的紋理濾波方式。
教您如何使用鍵盤來移動場景中的,還會教您在OpenGL場景中應用簡單的光照。
這一課包含了很多內容,如果您對前面的課程有疑問的話,先回頭複習一下。
進入後面的程式碼之前,很好的理解基礎知識十分重要。
我們還是在第一課的程式碼上加以修改。
跟以前不一樣的是,只要有任何大的改動,我都會寫出整段程式碼。
首先我們還要加進SysUtils單元和Glaux單元。
}
Uses
SysUtils,
opengl,
,
Messages,
Glaux In '....GLAUXGlaux.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庫。
我知道和VC++都包含了glaux庫,但別的語言不能保證都有。
『譯者注:glaux是OpenGL輔助庫,根據OpenGL的跨平臺特性,
所有平臺上的程式碼都應通用。但輔助庫不是正式的OpenGL標準庫,
沒有出現在所有的平臺上。但正好在平臺上可用。
呵呵,BCB當然也沒問題了。』這裡我只對新增的程式碼做註解。
如果您對某行程式碼有疑問的話,請檢視教程六。
那一課很詳細的解釋了載入、建立紋理的內容。
在上一段程式碼後面及 glResizeWnd ()之前的位置,
我們增加了下面的程式碼。這和第六課中載入點陣圖的程式碼幾乎相同。
}
Function Loamp(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,
TextureImage[0].data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 線形濾波
//下面是建立紋理的新方法。 Mipmap!
//『譯者注:這個詞的中文我翻不出來,不過沒關係。看完這一段,您就知道意思最重要。』
//您可能會注意到當影像在螢幕上變得很小的時候,很多細節將會丟失。
//剛才還很不錯的圖案變得很難看。當您告訴OpenGL建立一個 mipmapped的紋理後,
//OpenGL將嘗試建立不同尺寸的高質量紋理。當您向螢幕繪製一個mipmapped紋理的時候,
//OpenGL將選擇它已經建立的外觀最佳的紋理(帶有更多細節)來繪製,
//而不僅僅是縮放原先的影像(這將導致細節丟失)。
//我曾經說過有辦法可以繞過OpenGL對紋理寬度和高度所加的限制——64、128、256,等等。
//辦法就是 gluBuild2DMipmaps。據我的發現,您可以使用任意的點陣圖來建立紋理。
//OpenGL將自動將它縮放到正常的大小。
//因為是第三個紋理,我們將它存到texture[2]。這樣本課中的三個紋理全都建立好了。
// 建立 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 紋理。
//我們使用三種顏色(紅,綠,藍)來生成一個2D紋理。
//TextureImage[0].sizeX 是點陣圖寬度,
//TextureImage[0].sizeY 是點陣圖高度,
//(====不知為什麼,delphi下這個沒有height這個引數,
//但是幫助中卻有,不知delphi再搞什麼,鬱悶ing......
//最後我在前面自己寫了一個gluBuild2DMipmaps,
//來載入glu32.dll中的gluBuild2DMipmaps函式=====)
//GL_RGB意味著我們依次使用RGB色彩。
//GL_UNSIGNED_BYTE 意味著紋理資料的單位是位元組。
//TextureImage[0].data指向我們建立紋理所用的點陣圖。
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; // 釋放紋理影像佔用的
TextureImage[0] := Nil; // 釋放影像結構
result := Status; // 返回 Status
End;
//接著應該載入紋理並初始化OpenGL設定了。
//GLInit函式的第一行使用上面的程式碼載入紋理。
//建立紋理之後,我們glEnable(GL_TEXTURE_2D)啟用2D紋理對映。
//陰影設為平滑陰影( smooth shading )。
//背景色設為黑色,我們啟用深度測試,然後我們啟用透視計算。
Procedure glInit(); // 此處開始對OpenGL進行所有設定
Begin
If (Not LoadTexture) Then // 呼叫紋理載入子例程
exit; // 如果未能載入,退出
glEnable(GL_TEXTURE_2D); // 啟用紋理對映
glShadeModel(GL_SMOOTH); // 啟用陰影平滑
glClearColor(0.0, 0.0, 0.0, 0.0); // 黑色背景
glClearDepth(1.0); // 設定深度快取
glEnable(GL_DEPTH_TEST); // 啟用深度測試
glDepthFunc(GL_LESS); // 所作深度測試的型別
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //高度最佳化的透視投影計算
//現在開始設定光源。下面下面一行設定環境光的發光量,
//光源light1開始發光。
//這一課的開始處我們我們將環境光的發光量存放在LightAmbient陣列中。
//現在我們就使用此陣列(半亮度環境光)。
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]); // 設定環境光
//接下來我們設定漫射光的發光量。它存放在LightDiffuse陣列中(全亮度白光)。
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]); // 設定漫射光
//然後設定光源的位置。
//位置存放在 LightPosition 陣列中
//(正好位於木箱前面的中心,X-0.0,Y-0.0,Z方向移向觀察者2個單位)。
glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // 光源位置
//最後,我們啟用一號光源。我們還沒有啟用GL_LIGHTING,
//所以您看不見任何光線。
//記住:只對光源進行設定、定位、甚至啟用,光源都不會工作。
//除非我們啟用GL_LIGHTING。
glEnable(GL_LIGHT1); // 啟用一號光源
End;
//下一段程式碼繪製貼圖立方體。我只對新增的程式碼進行註解。
//如果您對沒有註解的程式碼有疑問,回頭看看第六課。
Procedure glDraw(); // 從這裡開始進行所有的繪製
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除螢幕和深度快取
glLoadntity(); // 重置當前的模型觀察矩陣
//下三行程式碼放置並旋轉貼圖立方體。
//glTranslatef(0.0,0.0,z)將立方體沿著Z軸移動Z單位。
//glRotatef(xrot,1.0f,0.0f,0.0f)將立方體繞X軸旋轉xrot。
//glRotatef(yrot,0.0f,1.0f,0.0f)將立方體繞Y軸旋轉yrot。
glTranslatef(0.0, 0.0, z); // 移入/移出螢幕 z 個單位
glRotatef(xrot, 1.0, 0.0, 0.0); // 繞X軸旋轉
glRotatef(yrot, 0.0, 1.0, 0.0); // 繞Y軸旋轉
//下一行與我們在第六課中的類似。
//有所不同的是,這次我們繫結的紋理是texture[filter],
//而不是上一課中的texture[0]。
//任何時候,我們按下F鍵,filter 的值就會增加。
//如果這個數值大於2,變數filter 將被重置為0。
//初始時,變數filter 的值也將設為0。
//使用變數filter 我們就可以選擇三種紋理中的任意一種。
glBindTexture(GL_TEXTURE_2D, texture[filter]); // 選擇由filter決定的紋理
glBegin(GL_QUADS); // 開始繪製四邊形
//glNormal3f是這一課的新東西。Normal就是法線的意思,
//所謂法線是指經過面(多邊形)上的一點且垂直於這個面(多邊形)的直線。
//使用光源的時候必須指定一條法線。法線告訴OpenGL這個多邊形的朝向,並指明多邊形的正面和背面。
//如果沒有指定法線,什麼怪事情都可能發生:不該照亮的面被照亮了,多邊形的背面也被照亮....。
//對了,法線應該指向多邊形的外側。看著木箱的前面您會注意到法線與Z軸正向同向。
//這意味著法線正指向觀察者-您自己。這正是我們所希望的。
//對於木箱的背面,也正如我們所要的,法線背對著觀察者。
//如果立方體沿著X或Y軸轉個180度的話,前側面的法線仍然朝著觀察者,背面的法線也還是背對著觀察者。
//換句話說,不管是哪個面,只要它朝著觀察者這個面的法線就指向觀察者。
//由於光源緊鄰觀察者,任何時候法線對著觀察者時,這個面就會被照亮。
//並且法線越朝著光源,就顯得越亮一些。
//如果您把觀察點放到立方體內部,你就會法線裡面一片漆黑。
//因為法線是向外指的。如果立方體內部沒有光源的話,當然是一片漆黑。
// 前面
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;
//現在轉入WinMain()主函式。
//我們將在這裡增加開關光源、旋轉木箱、切換過濾方式以及將木箱移近移遠的控制程式碼。
//在接近WinMain()函式結束的地方你會看到SBuffers(hDC)這行程式碼。
//然後就在這一行後面新增如下的程式碼。
//程式碼將檢查L鍵是否按下過。
//如果L鍵已按下,但lp的值不是false的話,意味著L鍵還沒有鬆開,這時什麼都不會發生。
SwapBuffers(h_DC); // 快取 (雙快取)
If (keys[ord('L')] And Not lp) Then
Begin
//如果lp的值是false的話,
//意味著L鍵還沒按下,或者已經鬆開了,接著lp將被設為TRUE。
//同時檢查這兩個條件的原因是為了防止L鍵被按住後,
//這段程式碼被反覆,並導致窗體不停閃爍。
//lp設為true之後,就知道L鍵按過了,
//我們則據此可以切換光源的開/關:布林變數light控制光源的開關。
lp := true; // lp 設為 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設為FALSE
//然後對"F"鍵作相似的檢查。
//如果有按下"F"鍵並且"F"鍵沒有處於按著的狀態或者它就從沒有按下過,
//將變數fp設為true。這意味著這個鍵正被按著呢。
//接著將filter變數加一。如果filter變數大於2
//(因為這裡我們的使用的陣列是texture[3],大於2的紋理不存在),
//我們重置filter變數為0。
If (keys[ord('F')] And Not fp) Then // F鍵按下了麼?
Begin
fp := TRUE; // fp 設為 TRUE
inc(filter); // filter的值加一
If filter > 2 Then // 大於2了麼?
filter := 0; // 若是重置為0
End;
If Not keys[ord('F')] Then //F鍵放開了麼?
fp := FALSE; // 若是fp設為FALSE
//這四行檢查是否按下了PageUp鍵。若是的話,減少z變數的值。這樣DrawGLScene函式中包含的glTranslatef(0.0f,0.0f,z)呼叫將使木箱離觀察者更遠一點。
If keys[VK_PRIOR] Then //PageUp按下了?
z := z - 0.02; // 若按下,將木箱移向螢幕內部。
//接著四行檢查PageDown鍵是否按下,若是的話,增加z變數的值。這樣DrawGLScene函式中包含的glTranslatef(0.0f,0.0f,z)呼叫將使木箱向著觀察者移近一點。
If keys[VK_NEXT] Then // PageDown按下了麼?
z := z + 0.02; //若按下的話,將木箱移向觀察者。
//現在檢查方向鍵。按下左右方向鍵xspeed相應減少或增加。
//按下上下方向鍵yspeed相應減少或增加。
//記住在以後的教程中如果xspeed、yspeed的值增加的話,立方體就轉的更快。
//如果一直按著某個方向鍵,立方體會在那個方向上轉的越快。
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
執行一下看看效果
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-961046/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- NeHe的opengl教程delphi版(9)----星星 (轉)
- 漂亮的星星動畫:Jeff Molofee(NeHe) 的 OPENGL 教程-第九課 (轉)動畫
- OpenGL系列教程之一:OpenGL(轉)
- 用Delphi進行OpenGL程式設計學習心得 (轉)程式設計
- [Python影象處理] 四.影象平滑之均值濾波、方框濾波、高斯濾波及中值濾波Python
- OpenCV計算機視覺學習(4)——影像平滑處理(均值濾波,高斯濾波,中值濾波,雙邊濾波)OpenCV計算機視覺
- 幾種常見的濾波演算法(轉)演算法
- 【OpenCV】鄰域濾波:方框、高斯、中值、雙邊濾波OpenCV
- 數字濾波器和模擬濾波器(一)
- 卡爾曼濾波
- OpenCV 線性濾波OpenCV
- Python 影像處理 OpenCV (7):影像平滑(濾波)處理PythonOpenCV
- 濾波演算法——十大濾波演算法程式大全演算法
- 點雲濾波器與過濾器過濾器
- Delphi6/7 中XML 文件的應用 (轉)XML
- 卡爾曼濾波的原理說明
- [OpenGL]未來視覺5-抖音濾鏡視覺
- 引導濾波GuidedFilterGUIIDEFilter
- GLSL學習_高斯濾波
- Gabor濾波器學習
- 影象卷積與濾波卷積
- 空域濾波演算法演算法
- OpenGL著色器教程
- 華為CMPP原始碼delphi6版 (轉)原始碼
- 粒子濾波(Particle Filter)的通俗解釋Filter
- Kalman濾波器的原理與實現
- Android OpenGL 編寫簡單濾鏡Android
- Delphi資料庫程式設計教程(九) (轉)資料庫程式設計
- 音訊降噪-fir濾波器音訊
- 卡爾曼濾波器(Kalman Filters)Filter
- 濾波演算法總結演算法
- 頻率域濾波基本操作
- [轉載]基於頻譜分析儀的濾波器引數測試
- matlab 濾波器中用到的函式Matlab函式
- DELPHI的萬用字元比較(第五版) (轉)字元
- 遊戲製作詳解自----OpenGL入門教程(九)(轉)遊戲
- 遊戲製作詳解自----OpenGL入門教程(五)(轉)遊戲
- 遊戲製作詳解自----OpenGL入門教程(四)(轉)遊戲