天天看點

OpenGL入門學習筆記(三)多邊形的繪制

多邊形的繪制

(一)多邊形的兩面與其繪制方法

從三維的角度來看,一個多邊形具有兩個面。

每一個面都可以設定不同的繪制方式:

  1. 填充;
  2. 隻繪制邊緣輪廓線;
  3. 隻繪制頂點;

其中“填充”是預設的方式。

可以為兩個面分别設定不同的方式。

glPolygonMode的原型是:

void glPolygonMode(GLenum face,GLenum mode);

用于控制多邊形的顯示方法。

face将确定顯示模式将适用于物體的哪些部分,控制多邊形的正面和背面的繪圖模式:

參數 含義
GL_FRONT 顯示模式将适用于物體的前向面(也就是物體能看到的面)
GL_BACK 顯示模式将适用于物體的後向面(也就是物體上不能看到的面)
GL_FRONT_AND_BACK 顯示模式将适用于物體的所有面

mode這個參數确定選中的物體的面以何種方式顯示(顯示模式):

參數 含義
GL_POINT 顯示頂點,多邊形用點顯示
GL_LINE 顯示線段,多邊形用輪廓顯示
GL_FILL 顯示面,多邊形采用填充形式
glPolygonMode(GL_FRONT, GL_FILL); // 設定正面為填充方式
glPolygonMode(GL_BACK, GL_LINE); // 設定反面為邊緣繪制方式
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 設定兩面均為頂點繪制方式
           

(二)反轉

正面

按照約定,如果多邊形的頂點以逆時針順序出現在螢幕上,它便稱為“正面”。

但也有一些表面比較特殊。例如“麥比烏斯帶”(請自己 Google 一下),可以全部使用“正面”或全部使用“背面”來表示。

glFrontFace

glFrontFace

是opengl的初級指令,有兩個基本作用,一是可以用來用在某些特殊場合(比如剔除面片),二是可以提高渲染效率。

函數原型:

void glFrontFace(GLenum mode);

作用是控制多邊形的正面是如何決定的。在預設情況下,mode是GL_CCW。

mode的值為:

參數 含義
GL_CCW 表示視窗坐标上投影多邊形的頂點順序為逆時針方向的表面為正面。
GL_CW 表示頂點順序為順時針方向的表面為正面。

頂點的方向又稱為環繞。

執行個體

void myDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glPolygonMode(GL_FRONT, GL_FILL); // 設定正面為填充模式
    glPolygonMode(GL_BACK, GL_LINE); // 設定反面為線形模式
    glFrontFace(GL_CCW); // 設定逆時針方向為正面
    glBegin(GL_POLYGON); // 按逆時針繪制一個正方形,在左下方
    glVertex2f(-, -);
    glVertex2f(, -);
    glVertex2f(, );
    glVertex2f(-, );
    glEnd();
    glBegin(GL_POLYGON); // 按順時針繪制一個正方形,在右上方
    glVertex2f(, );
    glVertex2f(, );
    glVertex2f(, );
    glVertex2f(, );
    glEnd();
    glFlush();
}
           

(三)剔除多邊形表面

在三維空間中,一個多邊形雖然有兩個面,但我們無法看見背面的那些多邊形,而一些多邊形雖然是正面的,但被其他多邊形所遮擋。如果将無法看見的多邊形和可見的多邊形同等對待,無疑會降低我們處理圖形的效率。在這種時候,可以将不必要的面剔除。

使用

glEnable(GL_CULL_FACE);

來啟動剔除功能(使

glDisable(GL_CULL_FACE);

可以關閉之)然後,使用

glCullFace

來進行剔除。

glCullFace()

參數包括

GL_FRONT

GL_BACK

GL_FRONT_AND_BACK

.

意義:前兩個參數分别表示禁用多邊形正面或者背面上的光照、陰影和顔色計算及操作,消除不必要的渲染計算,最後一個參數使用後,所有的多邊形都将被剔除,是以看見的就隻有點和直線。

(四)镂空多邊形

glEnable(GL_POLYGON_STIPPLE);

來啟動镂空模式(使用

glDisable(GL_POLYGON_STIPPLE);

可以關閉之)。

然後,使用

glPolygonStipple ()

來設定镂空的樣式。

void glPolygonStipple(const GLubyte *mask);

其中的參數 mask 指向一個長度為 128 位元組的空間,它表示了一個 32*32 的矩形應該如何镂空。其中:第一

個位元組表示了最左下方的從左到右(也可以是從右到左,這個可以修改)8 個像素是否镂空(1 表示不镂空,

顯示該像素;0 表示镂空,顯示其後面的顔色),最後一個位元組表示了最右上方的 8 個像素是否镂空。

但是,如果我們直接定義這個 mask 數組,像這樣:

static GLubyte Mask[] =
{
, , , , // 這是最下面的一行
, , , ,
, , , , // 麻
, , , , // 煩
, , , , // 的
, , , , // 初
, , , , // 始
, , , , // 化
, , , , // ,
, , , , // 不
, , , , // 建
, , , , // 議
, , , , // 使
, , , , // 用
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , ,  // 這是最上面的一行
};
           

這樣一堆資料非常缺乏直覺性,我們需要很費勁的去分析,才會發現它表示的竟然是一隻蒼蠅。

如果将這樣的資料儲存成圖檔,并用專門的工具進行編輯,顯然會友善很多。下面介紹如何做到這一點。

首先,用 Windows 自帶的畫筆程式建立一副圖檔,取名為 mask.bmp,注意儲存時,應該選擇“單色位圖”。

在“圖象”->“屬性”對話框中,設定圖檔的高度和寬度均為 32。

用放大鏡觀察圖檔,并編輯之。黑色對應二進制零(镂空),白色對應二進制一(不镂空),編輯完畢後保

存。

然後,就可以使用以下代碼來獲得這個 Mask 數組了。

static GLubyte Mask[];
FILE *fp;
fp = fopen("mask.bmp", "rb");
if( !fp )
exit();
// 移動檔案指針到這個位置,使得再讀 sizeof(Mask)個位元組就會遇到檔案結束
// 注意-(int)sizeof(Mask)雖然不是什麼好的寫法,但這裡它确實是正确有效的
// 如果直接寫-sizeof(Mask)的話,因為 sizeof 取得的是一個無符号數,取負号會有問題
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )
exit();
// 讀取 sizeof(Mask)個位元組到Mask
if( !fread(Mask, sizeof(Mask), , fp) )
exit();
fclose(fp);
           

好的,現在請自己編輯一個圖檔作為 mask,并用上述方法取得 Mask 數組,運作後觀察效果。

說明:繪制虛線時可以設定 factor 因子,但多邊形的镂空無法設定 factor 因子。請用滑鼠改變視窗的大小,

觀察镂空效果的變化情況。

#include <stdio.h>
#include <stdlib.h>
void myDisplay(void)
{
static GLubyte Mask[];
FILE *fp;
fp = fopen("mask.bmp", "rb");
if( !fp )
exit();
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )
exit();
if( !fread(Mask, sizeof(Mask), , fp) )
exit();
fclose(fp);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(Mask);
glRectf(-, -, , ); // 在左下方繪制一個有镂空效果的正方形
glDisable(GL_POLYGON_STIPPLE);
glRectf(, , , ); // 在右上方繪制一個無镂空效果的正方形
glFlush();
}
           
OpenGL入門學習筆記(三)多邊形的繪制

繼續閱讀