跳轉至內容

OpenGL 程式設計/GLStart/Tut3

來自華夏公益教科書

教程 3:繪製基本圖形

[編輯 | 編輯原始碼]

基本圖形是你可以輕鬆繪製的基本形狀。它可以是三角形、正方形,甚至是一個點。在本課中,我們將學習如何繪製一些基本圖形,包括:點、三角形和不同的多邊形。

即時模式

[編輯 | 編輯原始碼]

在 OpenGL 中進行繪製的最簡單方法是使用即時模式。為此,你使用 glBegin() 函式,它接受一個引數“模式”,即你想要繪製的物件型別。

以下是可能的模式及其含義的列表

GL_POINTS 在螢幕上繪製點。每個指定的頂點都是一個點。
GL_LINES 在螢幕上繪製線條。每兩個指定的頂點組成一條線。
GL_LINE_STRIP 在螢幕上繪製連線的線條。每個指定的頂點在指定的第一個和第二個頂點之後都會連線。
GL_LINE_LOOP 在螢幕上繪製連線的線條。最後一個指定的頂點與第一個指定的頂點相連。
GL_TRIANGLES 在螢幕上繪製三角形。每三個指定的頂點組成一個三角形。
GL_TRIANGLE_STRIP 在螢幕上繪製連線的三角形。在指定的前三個頂點之後,每個指定的頂點都會建立一個三角形。
GL_TRIANGLE_FAN 像 GL_TRIANGLE_STRIP 一樣繪製連線的三角形,但以扇形形狀繪製三角形。
GL_QUADS 在螢幕上繪製四邊形(四邊形)。每四個指定的頂點組成一個四邊形。
GL_QUAD_STRIP 在螢幕上繪製連線的四邊形。在指定的第一個四個頂點之後,每兩個指定的頂點都會組成一個連線的四邊形。
GL_POLYGON 在螢幕上繪製多邊形。多邊形可以由任意數量的邊組成。

當你完成繪製特定基本圖形的所有頂點後,在下一行放置 glEnd() 函式,該函式結束該基本圖形的繪製。

繪製點

[編輯 | 編輯原始碼]

讓我們用最簡單的模式 GL_POINTS 做一個例子。在使用 OpenGL 繪製點時,點的預設大小為 1 畫素寬和高。當你執行程式時,這將非常難以看到。要編輯要繪製的點的大小,可以使用 glPointSize() 函式,它接受一個引數,即你想要的點的大小。

現在在 Render() 函式中,在你編寫 glBegin() 程式碼之前,我們將設定點的大小為 10 畫素。

    glPointSize(10.0f);

之後,任何點的繪製都將以 10 畫素寬和高繪製。現在用 GL_POINTS 模式引數編寫 glBegin() 函式。然後在此之後,使用 glVertex3f() 函式指定要使用的頂點。對於這個例子,我們希望螢幕的右上角 (1.0,1.0,0.0) 和左下角 (-1.0,-1.0,0.0) 有一個點。繪製完這兩個點後,確保使用 glEnd() 函式結束繪製。

    glBegin(GL_POINTS); //starts drawing of points
      glVertex3f(1.0f,1.0f,0.0f);//upper-right corner
      glVertex3f(-1.0f,-1.0f,0.0f);//lower-left corner
    glEnd();//end drawing of points

以下是你的參考的整個渲染函式以及示例輸出。本教程此部分的完整程式碼可以在可下載檔案中找到。這個例子叫做“points”

void Render()
{     
    //clear color and depth buffer 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();//load identity matrix
    
    glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units
    
    glColor3f(0.0f,0.0f,1.0f); //blue color
    
    glPointSize(10.0f);//set point size to 10 pixels
    
    glBegin(GL_POINTS); //starts drawing of points
      glVertex3f(1.0f,1.0f,0.0f);//upper-right corner
      glVertex3f(-1.0f,-1.0f,0.0f);//lower-left corner
    glEnd();//end drawing of points
}

繪製線段環

[編輯 | 編輯原始碼]

我想要涵蓋 glBegin() 函式中的每一種模式,但這會佔用太多時間和空間。因此,我將涵蓋高階模式,並在需要時最有可能涵蓋其他模式。

線段環至少需要兩個頂點。之後指定的每個頂點都與之前指定的頂點和第一個指定的頂點相連。因此,如果我們在視窗左側、視窗右側、頂部和底部放置一個頂點,我們將得到一個旋轉的正方形。

讓我們在 OpenGL 中完成這個圖。首先,我們使用 glBegin() 函式並傳遞 GL_LINE_LOOP 引數,告訴 OpenGL 我們要開始繪製線段環。然後,我們傳遞四個頂點來建立旋轉的正方形。第一個頂點位於視窗左側 (-1.0f,0.0f,0.0f),第二個頂點位於視窗底部 (0.0f,-1.0f,0.0f),第三個頂點位於視窗右側 (1.0f,0.0f,0.0f),第四個也是最後一個頂點位於視窗頂部 (0.0f,1.0f,0.0f)。然後,我們確保放入 glEnd() 以告訴 OpenGL 我們已經完成繪製線段環。

    glBegin(GL_LINE_LOOP);//start drawing a line loop
      glVertex3f(-1.0f,0.0f,0.0f);//left of window
      glVertex3f(0.0f,-1.0f,0.0f);//bottom of window
      glVertex3f(1.0f,0.0f,0.0f);//right of window
      glVertex3f(0.0f,1.0f,0.0f);//top of window
    glEnd();//end drawing of line loop

以下是完整的 Render() 函式以及示例輸出。在本章的可下載檔案中查詢名為“lineLoop”的專案檔案。

void Render()
{     
    //clear color and depth buffer 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();//load identity matrix
    
    glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units
    
    glColor3f(0.0f,0.0f,1.0f); //blue color
    
    glBegin(GL_LINE_LOOP);//start drawing a line loop
      glVertex3f(-1.0f,0.0f,0.0f);//left of window
      glVertex3f(0.0f,-1.0f,0.0f);//bottom of window
      glVertex3f(1.0f,0.0f,0.0f);//right of window
      glVertex3f(0.0f,1.0f,0.0f);//top of window
    glEnd();//end drawing of line loop
}

繪製三角形

[編輯 | 編輯原始碼]

三角形由三個頂點組成。對於這個例子,我們將使用常規的 GL_TRIANGLES 模式來繪製兩個並排的三角形。

首先,我們要在左側繪製一個三角形。因此,我們需要在左側繪製三個頂點來表示一個三角形,並在視窗右側繪製三個頂點來表示第二個三角形。請注意,你不需要兩個 glBegin() 函式來繪製兩個三角形。由於 GL_TRIANGLES 是複數(意味著單詞末尾沒有“S”),它可以在一個 glBegin() 和 glEnd() 函式呼叫之間處理多個三角形。

請注意,我在圖的右下角寫下了頂點的座標。以下是繪製這兩個三角形的程式碼。

    glBegin(GL_TRIANGLES);//start drawing triangles
      glVertex3f(-1.0f,-0.1f,0.0f);//triangle one first vertex
      glVertex3f(-0.5f,-0.25f,0.0f);//triangle one second vertex
      glVertex3f(-0.75f,0.25f,0.0f);//triangle one third vertex
      //drawing a new triangle
      glVertex3f(0.5f,-0.25f,0.0f);//triangle two first vertex
      glVertex3f(1.0f,-0.25f,0.0f);//triangle two second vertex
      glVertex3f(0.75f,0.25f,0.0f);//triangle two third vertex
    glEnd();//end drawing of triangles

以下是此例子的完整 Render() 函式以及示例輸出。要檢視完整程式碼,請參見可下載檔案中的“triangle”專案資料夾。

void Render()
{     
    //clear color and depth buffer 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();//load identity matrix
    
    glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units
    
    glColor3f(0.0f,0.0f,1.0f); //blue color
    
    glBegin(GL_TRIANGLES);//start drawing triangles
      glVertex3f(-1.0f,-0.25f,0.0f);//triangle one first vertex
      glVertex3f(-0.5f,-0.25f,0.0f);//triangle one second vertex
      glVertex3f(-0.75f,0.25f,0.0f);//triangle one third vertex
      //drawing a new triangle
      glVertex3f(0.5f,-0.25f,0.0f);//triangle two first vertex
      glVertex3f(1.0f,-0.25f,0.0f);//triangle two second vertex
      glVertex3f(0.75f,0.25f,0.0f);//triangle two third vertex
    glEnd();//end drawing of triangles
}

繪製多邊形

[編輯 | 編輯原始碼]

多邊形由至少三個頂點組成,這些頂點連線在一起形成一個形狀。在這個例子中,我們將使用 GL_POLYGON 模式來繪製一個六邊形。

GL_POLYGON 模式允許你繪製任意數量邊形的形狀。由於 GL_POLYGON 是一個單數詞(意味著單詞末尾沒有“S”),你只能在一個 glBegin() 和 glEnd() 函式呼叫之間繪製一個多邊形。另外,你指定的最後一個頂點會自動連線到第一個指定的頂點。當然,由於多邊形是一個封閉的形狀,就像三角形一樣,形狀將用你指定的顏色填充(目前為藍色)。以下是我們的六邊形的圖。

(注意:這不能用於 凹多邊形)

以下是繪製這個多邊形的程式碼

    glBegin(GL_POLYGON);//begin drawing of polygon
      glVertex3f(-0.5f,0.5f,0.0f);//first vertex
      glVertex3f(0.5f,0.5f,0.0f);//second vertex
      glVertex3f(1.0f,0.0f,0.0f);//third vertex
      glVertex3f(0.5f,-0.5f,0.0f);//fourth vertex
      glVertex3f(-0.5f,-0.5f,0.0f);//fifth vertex
      glVertex3f(-1.0f,0.0f,0.0f);//sixth vertex
    glEnd();//end drawing of polygon

以下是完整的 Render() 函式以及示例輸出。在包含的可下載檔案中查詢“polygon”專案資料夾中的完整程式碼。

void Render()
{     
    //clear color and depth buffer 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();//load identity matrix
    
    glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units
    
    glColor3f(0.0f,0.0f,1.0f); //blue color
    
    glBegin(GL_POLYGON);//begin drawing of polygon
      glVertex3f(-0.5f,0.5f,0.0f);//first vertex
      glVertex3f(0.5f,0.5f,0.0f);//second vertex
      glVertex3f(1.0f,0.0f,0.0f);//third vertex
      glVertex3f(0.5f,-0.5f,0.0f);//fourth vertex
      glVertex3f(-0.5f,-0.5f,0.0f);//fifth vertex
      glVertex3f(-1.0f,0.0f,0.0f);//sixth vertex
    glEnd();//end drawing of polygon
}

顯示列表

[編輯 | 編輯原始碼]

使用 OpenGL 即時模式有一些缺點。例如,頂點資料必須在繪製時動態傳輸到圖形記憶體。這可以透過使用顯示列表來改進。顯示列表本質上是採用 glBegin()/glEnd() 命令序列並以有效的方式將其儲存在圖形卡側。

(待辦事項:稍後詳細說明,請參閱 [1] 以獲取一些資訊 - glGenLists(), glNewList(), glEndList(), glCallList(), glDeleteLists())

頂點陣列和頂點緩衝區

[編輯 | 編輯原始碼]

顯示列表也有一些缺點。一旦編譯,顯示列表就是靜態的,無法更改。此外,由多個基本圖形共享的頂點在繪製時仍然需要多次表示和變換。這非常低效。

頂點陣列頂點緩衝區解決了這些問題。思路很簡單,就是使用陣列儲存頂點資料。使用 glDrawArrays(),可以使用這些頂點繪製基本圖形。

為了在影片記憶體中儲存資料,可以使用頂點緩衝區(glGenBuffer()、glBindBuffer()、glBufferData()、glDeleteBuffers())。 頂點緩衝區存在兩種型別。

  • GL_ARRAY_BUFFER 用於儲存實際的頂點資料。
  • GL_ELEMENT_ARRAY_BUFFER 用於儲存指向儲存在獨立的 GL_ARRAY_BUFFER 中的頂點的索引,從而允許在多個圖元中重用頂點。

(待辦事項:稍後詳細說明,舉例)

華夏公益教科書