nehe opengl第七課:光照和鍵盤
光照和鍵盤控制:
在這一課裡,我們將新增光照和鍵盤控制,它讓程式看起來更美觀。
這一課我會教您如何使用三種不同的紋理濾波方式。教您如何使用鍵盤來移動場景中的物件,還會教您在opengl場景中應用簡單的光照。這一課包含了很多內容,如果您對前面的課程有疑問的話,先回頭複習一下。進入後面的**之前,很好的理解基礎知識十分重要。
我們還是在第一課的**上加以修改。跟以前不一樣的是,只要有任何大的改動,我都會寫出整段**。程式開始,我們先加上幾個新的變數。
下面幾行是新的。我們增加三個布林變數。 light 變數跟蹤光照是否開啟。變數lp和fp用來儲存'l' 和'f'鍵是否按下的狀態。後面我會解釋這些變數的重要性。現在,先放在一邊吧。
bool light; // 光源的開/關
bool lp; // l鍵按下了麼?
bool fp; // f鍵按下了麼?
現在設定5個變數來控制繞x軸和y軸旋轉角度的步長,以及繞x軸和y軸的旋轉速度。另外還建立了乙個z變數來控制進入螢幕深處的距離。
glfloat xrot; // x 旋轉
glfloat yrot; // y 旋轉
glfloat xspeed; // x 旋轉速度
glfloat yspeed; // y 旋轉速度
glfloat z=-5.0f; // 深入螢幕的距離
接著設定用來建立光源的陣列。我們將使用兩種不同的光。第一種稱為環境光。環境光來自於四面八方。所有場景中的物件都處於環境光的照射中。第二種型別的光源叫做漫射光。漫射光由特定的光源產生,並在您的場景中的物件表面上產生反射。處於漫射光直接照射下的任何物件表面都變得很亮,而幾乎未被照射到的區域就顯得要暗一些。這樣在我們所建立的木板箱的稜邊上就會產生的很不錯的陰影效果。
建立光源的過程和顏色的建立完全一致。前三個引數分別是rgb三色分量,最後乙個是alpha通道引數。
因此,下面的**我們得到的是半亮(0.5f)的白色環境光。如果沒有環境光,未被漫射光照到的地方會變得十分黑暗。
glfloat lightambient= ; // 環境光引數
下一行**我們生成最亮的漫射光。所有的引數值都取成最大值1.0f。它將照在我們木板箱的前面,看起來挺好。
glfloat lightdiffuse= ; // 漫射光引數
最後我們儲存光源的位置。前三個引數和gltranslate中的一樣。依次分別是xyz軸上的位移。由於我們想要光線直接照射在木箱的正面,所以xy軸上的位移都是0.0f。第三個值是z軸上的位移。為了保證光線總在木箱的前面,所以我們將光源的位置朝著觀察者(就是您哪。)挪出螢幕。我們通常將螢幕也就是顯示器的螢幕玻璃所處的位置稱作z軸的0.0f點。所以z軸上的位移最後定為2.0f。假如您能夠看見光源的話,它就浮在您顯示器的前方。當然,如果木箱不在顯示器的螢幕玻璃後面的話,您也無法看見箱子。『譯者注:我很欣賞nehe的耐心。說真的有時我都打煩了,這麼簡單的事他這麼廢話幹嘛?但如果什麼都清楚,您還會翻著這樣的頁面看個沒完麼?』
最後乙個引數取為1.0f。這將告訴opengl這裡指定的座標就是光源的位置,以後的教程中我會多加解釋。
glfloat lightposition= ; // 光源位置
gluint filter; // 濾波型別
gluint texture[3]; // 3種紋理的儲存空間
現在載入乙個位圖,並用它建立三種不同的紋理。這一課使用glaux輔助庫來載入位圖,因此在編譯時您應該確認是否包含了glaux庫。我知道delphi和vc++都包含了glaux庫,但別的語言不能保證都有。『譯者注:glaux是opengl輔助庫,根據opengl的跨平台特性,所有平台上的**都應通用。但輔助庫不是正式的opengl標準庫,沒有出現在所有的平台上。但正好在win32平台上可用。呵呵,bcb當然也沒問題了。』這裡我只對新增的**做註解。如果您對某行**有疑問的話,請檢視教程六。那一課很詳細的解釋了載入、建立紋理的內容。
在上一段**後面及resizeglscene()之前的位置,我們增加了下面的**。這和第六課中載入點陣圖的**幾乎相同。
這段**呼叫前面的**載入位圖,並將其轉換成3個紋理。status 變數跟蹤紋理是否已載入並被建立了。
int loadgltextures() // 載入點陣圖並轉換成紋理
free(textureimage[0]); // 釋放影象結構}
最後我們返回 status 變數。如果一切ok,status 變數的值為true。否則為false。
return status; // 返回 status 變數}
接著應該載入紋理並初始化opengl設定了。initgl函式的第一行使用上面的**載入紋理。建立紋理之後,我們呼叫
glenable(gl_texture_2d)啟用2d紋理對映。陰影模式設為平滑陰影( smooth shading )。背景色設為黑色,我們啟用深度測試,然後我們啟用優化透視計算。
現在開始設定光源。下面下面一行設定環境光的發光量,光源light1開始發光。這一課的開始處我們我們將環境光的發光量存放在lightambient陣列中。現在我們就使用此陣列(半亮度環境光)。在int initgl(glvoid)函式中新增下面的**。
gllightfv(gl_light1, gl_ambient, lightambient); // 設定環境光
接下來我們設定漫射光的發光量。它存放在lightdiffuse陣列中(全亮度白光)。
gllightfv(gl_light1, gl_diffuse, lightdiffuse); // 設定漫射光
然後設定光源的位置。位置存放在 lightposition 陣列中(正好位於木箱前面的中心,x-0.0f,y-0.0f,z方向移向觀察者2個單位《位於螢幕外面》)。
gllightfv(gl_light1, gl_position,lightposition); // 設定光源位置
最後,我們啟用一號光源。我們還沒有啟用gl_lighting,所以您看不見任何光線。記住:只對光源進行設定、定位、甚至啟用,光源都不會工作。除非我們啟用gl_lighting。
glenable(gl_light1); // 啟用一號光源
下一段**繪製貼圖立方體。我只對新增的**進行註解。如果您對沒有註解的**有疑問,回頭看看第六課。
int drawglscene(glvoid) // 從這裡開始進行所有的繪製
現在轉入winmain()主函式。我們將在這裡增加開關光源、旋轉木箱、切換過濾方式以及將木箱移近移遠的控制**。在接近winmain()函式結束的地方你會看到swapbuffers(hdc)這行**。然後就在這一行後面新增如下的**。
**將檢查l鍵是否按下過。如果l鍵已按下,但lp的值不是false的話,意味著l鍵還沒有鬆開,這時什麼都不會發生。
swapbuffers(hdc); // 交換快取
if (keys['l'] && !lp) // l 鍵已按下並且鬆開了?
else // 否則}
下面的**檢視是否鬆開了"l"鍵。如果鬆開,變數lp將設為false。這意味著"l"鍵沒有按下。如果不作此檢查,光源第一次開啟之後,就無法再關掉了。計算機會以為"l"鍵一直按著呢。
if (!keys['l']) // l鍵鬆開了麼?
然後對"f"鍵作相似的檢查。如果有按下"f"鍵並且"f"鍵沒有處於按著的狀態或者它就從沒有按下過,將變數fp設為true。這意味著這個鍵正被按著呢。接著將filter變數加一。如果filter變數大於2(因為這裡我們的使用的陣列是texture[3],大於2的紋理不存在),我們重置filter變數為0。
if (keys['f'] && !fp) // f鍵按下了麼?
}if (!keys['f']) // f鍵放開了麼?
這四行檢查是否按下了pageup鍵。若是的話,減少z變數的值。這樣drawglscene函式中包含的gltranslatef(0.0f,0.0f,z)呼叫將使木箱離觀察者更遠一點。
if (keys[vk_prior]) // pageup按下了?
接著四行檢查pagedown鍵是否按下,若是的話,增加z變數的值。這樣drawglscene函式中包含的gltranslatef(0.0f,0.0f,z)呼叫將使木箱向著觀察者移近一點。
if (keys[vk_next]) // pagedown按下了麼
現在檢查方向鍵。按下左右方向鍵xspeed相應減少或增加。按下上下方向鍵yspeed相應減少或增加。記住在以後的教程中如果xspeed、yspeed的值增加的話,立方體就轉的更快。如果一直按著某個方向鍵,立方體會在那個方向上轉的越快。
if (keys[vk_up]) // up方向鍵按下了麼?
if (keys[vk_down]) // down方向鍵按下了麼?
if (keys[vk_right]) // right方向鍵按下了麼?
if (keys[vk_left]) // left方向鍵按下了麼?
像前幾課一樣,我們最後還需要更正窗體的標題。
if (keys[vk_f1]) // f1按下了麼?}}
}}
第七課 光照和鍵盤
這一課我會教您如何使用三種不同的紋理濾波方式。教您如何使用鍵盤來移動場景中的物件,還會教您在opengl場景中應用簡單的光照。這一課包含了很多內容,如果您對前面的課程有疑問的話,先回頭複習一下。進入後面的 之前,很好的理解基礎知識十分重要。我們要在第一課的 上進行改動就可以了。我們將要增加乙個loa...
C語言第七課
主要內容 結構體 很重要,掌握 一 結構體的宣告 結構體是一種比較靈活的資料型別,與oc要學的類很相似 結構體是一種自己定義的資料型別示例 struct 結構體名 student 定義乙個學生型別 由結構體型別修飾的變數,叫結構體變數 定義 struct 結構體名 變數名 示例 struct stu...
第七課 C變數
第七課c變數 7.1 c 變數介紹 變數是程式可操作的儲存區的名稱。c 中每個變數都有特定的型別,型別決定了變數儲存的大小和布局,該範圍內的值都可以儲存在記憶體中,運算子可應用於變數上。變數的名稱可以由字母 數字和下劃線字元組成。它必須以字母或下劃線開頭。大寫字母和小寫字母是不同的,因為c 是大小寫...