教程的這一節在2000年一月徹底重寫了一遍。將會教您如何設置一個 OpenGL窗口。它可以只是一個窗口或是全屏幕的、可以任意 大小、任意色彩深度。此處的代碼很穩定且很強大,您可以在您所有的OpenGL項目中使用。我所有的教程都將基於此節的代碼!所有的錯誤都有被報告。所以應該沒有內存泄漏,代碼也很容易閱讀和修改。感謝Fredric Echols對代碼所做的修改!
現在就讓我們直接從代碼開始吧。第一件事是打開VC然後創建一個新工程。如果您不知道如何創建的話,您也許不該學習OpenGL,而應該先學學VC。某些版本的VC需要將 bool 改成 BOOL , true 改成 TRUE , false 改成 FALSE ,請自行修改。
在您創建一個新的Win32程序(不是console控制檯程序)後,您還需要鏈接OpenGL庫文件。在VC中操作如下:Project-> Settings,然後單擊LINK標籤。在"Object/Library Modules"選項中的開始處(在 kernel32.lib 前)增加 OpenGL32.lib GLu32.lib 和 GLaux.lib 後單擊OK按鈕。現在可以開始寫您的OpenGL程序了。
代碼的前4行包括了我們使用的每個庫文件的頭文件。如下所示:
#include <windows.h> // Header File For Windows Windows的頭文件
#include <GL/gl.h> // Header File For The OpenGL32 Library 包含最新的gl.h,glu.h庫
#include <GL/glut.h> // Header File For The GLu32 Library 包含OpenGL實用庫
//#include <gl\glaux.h> // Header File For The Glaux Library
接下來您需要設置您計劃在您的程序中使用的所有變量。本節中的例程將創建一個空的OpenGL窗口,因此我們暫時還無需設置大堆的變量。餘下需要設置的變量不多,但十分重要。您將會在您以後所寫的每一個OpenGL程序中用到它們。
第一行設置的變量是Rendering Context(着色描述表)。每一個OpenGL都被連接到一個着色描述表上。着色描述表將所有的OpenGL調用命令連接到Device Context(設備描述表)上。我將OpenGL的着色描述表定義爲 hRC 。要讓您的程序能夠繪製窗口的話,還需要創建一個設備描述表,也就是第二行的內容。Windows的設備描述表被定義爲 hDC 。DC將窗口連接到GDI(Graphics Device Interface圖形設備接口)。而RC將OpenGL連接到DC。第三行的變量
hWnd 將保存由Windows給我們的窗口指派的句柄。最後,第四行爲我們的程序創建了一個Instance(實例)。
HGLRC hRC=NULL; // 窗口着色描述表句柄
HDC hDC=NULL; // OpenGL渲染描述表句柄
HWND hWnd=NULL; // 保存我們的窗口句柄
HINSTANCE hInstance; // 保存程序的實例
下面的第一行設置一個用來監控鍵盤動作的數組。有許多方法可以監控鍵盤的動作,但這裏的方法很可靠,並且可以處理多個鍵同時按下的情況。
active 變量用來告知程序窗口是否處於最小化的狀態。如果窗口已經最小化的話,我們可以做從暫停代碼執行到退出程序的任何事情。我喜歡暫停程序。這樣可以使得程序不用在後臺保持運行。
fullscreen 變量的作用相當明顯。如果我們的程序在全屏狀態下運行, fullscreen 的值爲TRUE,否則爲FALSE。這個全局變量的設置十分重要,它讓每個過程都知道程序是否運行在全屏狀態下。
bool keys[256]; // 保存鍵盤按鍵的數組
bool active=TRUE; // 窗口的活動標誌,缺省爲TRUE
bool fullscreen=TRUE; // 全屏標誌缺省,缺省設定成全屏模式
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // WndProc的定義
下面的代碼的作用是重新設置OpenGL場景的大小,而不管窗口的大小是否已經改變(假定您沒有使用全屏模式)。甚至您無法改變窗口的大小時(例如您在全屏模式下),它至少仍將運行一次--在程序開始時設置我們的透視圖。OpenGL場景的尺寸將被設置成它顯示時所在窗口的大小。
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // 重置OpenGL窗口大小
{
if (height==0) // 防止被零除
{
height=1; // 將Height設爲1
}
glViewport(0, 0, width, height); // 重置當前的視口
下面幾行爲透視圖設置屏幕。意味着越遠的東西看起來越小。這麼做創建了一個現實外觀的場景。此處透視按照基於窗口寬度和高度的45度視角來計算。0.1f,100.0f是我們在場景中所能繪製深度的起點和終點。
glMatrixMode(GL_PROJECTION)指明接下來的兩行代碼將影響projection matrix(投影矩陣)。投影矩陣負責爲我們的場景增加透視。 glLoadIdentity()近似於重置。它將所選的矩陣狀態恢復成其原始狀態。調用 glLoadIdentity()之後我們爲場景設置透視圖。
glMatrixMode(GL_MODELVIEW)指明任何新的變換將會影響 modelview matrix(模型觀察矩陣)。模型觀察矩陣中存放了我們的物體訊息。最後我們重置模型觀察矩陣。如果您還不能理解這些術語的含義,請彆着急。在以後的教程裏,我會向大家解釋。只要知道如果您想獲得一個精彩的透視場景的話,必須這麼做。
glMatrixMode(GL_PROJECTION); // 選擇投影矩陣
glLoadIdentity(); // 重置投影矩陣
// 設置視口的大小
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // 選擇模型觀察矩陣
glLoadIdentity(); // 重置模型觀察矩陣
}
接下的代碼段中,我們將對OpenGL進行所有的設置。我們將設置清除屏幕所用的顏色,打開深度緩存,啓用smooth shading(陰影平滑),等等。這個例程直到OpenGL窗口創建之後纔會被調用。此過程將有返回值。但我們此處的初始化沒那麼複雜,現在還用不着擔心這個返回值。
int InitGL(GLvoid) // 此處開始對OpenGL進行所有設置
{
<span style="white-space:pre"> </span>glShadeModel(GL_SMOOTH); // 啓用陰影平滑
下一行設置清除屏幕時所用的顏色。如果您對色彩的工作原理不清楚的話,我快速解釋一下。色彩值的範圍從0.0f到1.0f。0.0f代表最黑的情況,1.0f就是最亮的情況。glClearColor 後的第一個參數是Red Intensity(紅色分量),第二個是綠色,第三個是藍色。最大值也是1.0f,代表特定顏色分量的最亮情況。最後一個參數是Alpha值。當它用來清除屏幕的時候,我們不用關心第四個數字。現在讓它爲0.0f。我會用另一個教程來解釋這個參數。
通過混合三種原色(紅、綠、藍),您可以得到不同的色彩。希望您在學校裏學過這些。因此,當您使用glClearColor(0.0f,0.0f,1.0f,0.0f),您將用亮藍色來清除屏幕。如果您用 glClearColor(0.5f,0.0f,0.0f,0.0f)的話,您將使用中紅色來清除屏幕。不是最亮(1.0f),也不是最暗 (0.0f)。要得到白色背景,您應該將所有的顏色設成最亮(1.0f)。要黑色背景的話,您該將所有的顏色設爲最暗(0.0f)。
<span style="white-space:pre"> </span>glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 黑色背景
接下來的三行必須做的是關於depth buffer(深度緩存)的。將深度緩存設想爲屏幕後面的層。深度緩存不斷的對物體進入屏幕內部有多深進行跟蹤。我們本節的程序其實沒有真正使用深度緩存,但幾乎所有在屏幕上顯示3D場景OpenGL程序都使用深度緩存。它的排序決定那個物體先畫。這樣您就不會將一個圓形後面的正方形畫到圓形上來。深度緩存是OpenGL十分重要的部分。
<span style="white-space:pre"> </span>glClearDepth(1.0f); // 設置深度緩存
glEnable(GL_DEPTH_TEST); // 啓用深度測試
glDepthFunc(GL_LEQUAL); // 所作深度測試的類型
接着告訴OpenGL我們希望進行最好的透視修正。這會十分輕微的影響性能。但使得透視圖看起來好一點。
<span style="white-space:pre"> </span>glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告訴系統對透視進行修正
最後,我們返回TRUE。如果我們希望檢查初始化是否OK,我們可以查看返回的 TRUE或FALSE的值。如果有錯誤發生的話,您可以加上您自己的代碼返回FALSE。目前,我們不管它。
<span style="white-space:pre"> </span>return TRUE; // 初始化 OK
}