OpenGL之繪畫三角形

OpenGL之繪畫三角形

OpenGL三角形屬於多邊形.演示程式如上圖:下載

  1. 按鼠標左鍵點擊繪畫三角形,繪畫時頂點的走向為逆時針三角形為正面,否則為背面.
  2. 按+鍵加大直線寬度
  3. 按-鍵減小直線寬度
  4. 按S鍵切換抗鋸齒功能
  5. 按.鍵切換三角形點畫模式
  6. 按C鍵切換三角形隱面裁剪
  7. 按1鍵填充模式
  8. 按2鍵線框模式
  9. 按3鍵頂點模式
  10. 按4鍵每三個頂點組成三角形
  11. 按5鍵頂點相連的三角形
  12. 按6鍵第一個頂點作為三角形的共同頂點

繪畫三角形

  1. glBegin(GL_TRIANGLES);準備繪畫三角形
  2. glVertex3f(x1,y1,z1);繪畫三角形頂點1
  3. glVertex3f(x2,y2,z2);繪畫三角形頂點2
  4. glVertex3f(x3,y3,z3);繪畫三角形頂點3
  5. glEnd();結束繪畫
glBegin()繪畫直線參數 簡介
GL_TRIANGLES 每三個頂點組成三角形
GL_TRIANGLE_STRIP 頂點相連的三角形
GL_TRIANGLE_FAN 第一個頂點作為三角形的共同頂點

因屏幕由像素組成,三角形邊緣會產生鋸齒,啟用抗鋸齒算法後會變得平滑,並修改邊緣像素的顏色:

  1. glEnable(GL_POLYGON_SMOOTH);啟用多邊形的平滑模式(抗鋸齒功能)
  2. glEnable(GL_BLEND);啟用混合

多邊形模式(正面默認為填充模式)

void glPolygonMode(GLenum face,GLenum mode);

多邊形面(face) 簡介
GL_FRONT 多邊形正面:頂點的走向為逆時針(默認)
GL_BACK 多邊形背面:頂點的走向為順時針
GL_FRONT_AND_BACK 正面與背面

 

多邊形模式(mode) 簡介
GL_FILL 填充模式:對多邊形內部進行顏色填充(默認)
GL_LINE 線框模式:多邊形只繪畫直先不填充
GL_POINT 頂點模式:只繪畫多邊形頂點

設置多邊形隱面裁剪

3D圖形渲染的工作量非常大,把不可見的面剔除則可節減大量變換和渲染時間.

  1. glEnable(GL_CULL_FACE);啟用隱面裁剪
  2. glCullFace(GL_BACK);設背面為隱面
  3. glFrontFace(GL_CCW);多邊形正面使用逆時針
正面模式(MODE) 簡介
GL_CCW 多邊形正面使用逆時針
GL_CW 多邊形反面使用順時針

多邊形點畫模式可用於簡單的填充(不太常用)

void glPolygonStipple(GLushort * mask);

mask:掩碼大小寬8byte*高16byte=128(byte)=1024(bit),1填充像素,0不填充

  1. glEnable(GL_POLYGON_STIPPLE);啟用點畫模式
  2. glPolygonStipple(mask);設置掩碼

 

OpenGL之繪畫直線

OpenGL之繪畫直線

OpenGL支持基本幾何直線繪畫,使用glVertex()生成繪畫相連直線的演示程式如上圖:下載

  1. 按鼠標左鍵點擊繪畫相連直線
  2. 按+鍵加大直線寬度
  3. 按-鍵減小直線寬度
  4. 按S鍵切換直線抗鋸齒功能
  5. 按.鍵切換直線點畫模式(虛線)
  6. 按1鍵切換为白色
  7. 按2鍵切換为黄色
  8. 按3鍵切換为红色
  9. 按4鍵每兩個頂點組成的直線
  10. 按5鍵由多個頂點組成的相連直線
  11. 按6鍵由多個頂點組成相連的閉合直線

繪畫直線

  1. glLineWidth(width);設置直線寬度
  2. glBegin(GL_LINE_STRIP);準備繪畫連續直線
  3. glVertex3f(x1,y1,z1);繪畫直線頂點1
  4. glVertex3f(x2,y2,z2);繪畫直線頂點2
  5. glEnd();結束繪畫
glBegin()繪畫直線參數 簡介
GL_LINES 由兩個頂點組成的直線
GL_LINE_STRIP 由多個頂點組成的相連直線
GL_LINE_LOOP 由多個頂點組成相連的閉合直線,第一個與最後一個頂點自動相連

因屏幕由像素組成,直線邊緣會產生鋸齒,OpenGL有抗鋸齒算法,啟用後直線會變得平滑,並修改邊緣像素的顏色:

  1. glEnable(GL_LINE_SMOOTH);啟用直線的平滑模式(抗鋸齒功能)
  2. glEnable(GL_BLEND);啟用混合

點畫模式通常用繪畫虛線

void glLineStipple(GLint factor,GLushort pattern);

factor:模板每BIT對應像素量

pattern:由2個Btye組成點畫模板

  1. glEnable(GL_LINE_STIPPLE);設置點畫模式(虛線)
  2. glLineStipple(5,0xfafa);設置模板

開啟直線抗鋸齒算法後,直線寬度範圍受到限制,若輸入不受支持直線寬度,會改為最接近的支持數值:

  1. GLfloat widths[2];浮點數數組
  2. glGetFloatv(GL_LINE_WIDTH_RANGE, widths);提取直線寬度的範圍
  3. GLfloat min = widths[0];最小
  4. GLfloat max = widths[1];最大
  5. GLfloat granularity;
  6. glGetFloatv(GL_LINE_WIDTH_GRANULARITY,&granularity);提取直線寬度的粒度
  7. GLfloat width;
  8. glGetFloatv(GL_LINE_WIDTH,&width);獲取當前直線寬度
  9. width = width + granularity;加大
  10. width = width – granularity;減小
  11. glPointSize(width);設置當前直線寬度,但不能在glBegin()與glEnd()之間調用

OpenGL之繪畫頂點

OpenGL之繪畫頂點

OpenGL支持基本幾何頂點繪畫,使用glVertex()生成畫點的演示程式如上圖:下載

  1. 按鼠標左鍵繪畫頂點
  2. 按+鍵加大頂點尺寸
  3. 按-鍵減小頂點尺寸
  4. 按S鍵切換抗鋸齒功能
  5. 按1鍵切換為白色
  6. 按2鍵切換為黃色
  7. 按3鍵切換為紅色

繪畫單個頂點

  1. glPointSize(size);設置頂點的大小
  2. glBegin(GL_POINTS); 準備繪畫
  3. glVertex3f(x,y,z); 繪畫頂點(浮點數版)
  4. glVertex3i(x,y,z); 繪畫頂點(整數版)
  5. glEnd(); 結束繪畫

因屏幕由像素組成,縮放頂點時邊緣會產生鋸齒,OpenGL有其抗鋸齒算法,啟用後頂定會由方變圓,並修改邊緣像素的顏色:

if (glIsEnabled(GL_POINT_SMOOTH) == false)// 判斷抗鋸齒是否已啟用

{

glEnable(GL_POINT_SMOOTH); // 啟用頂點的平滑模式(抗鋸齒功能)

glEnable(GL_BLEND);// 需啟用混合

}

開啟抗鋸齒算法後,頂點尺寸範圍受到限制,若輸入不受支持頂點的尺寸,會改為最接近的支持數值:

  1. GLfloat sizes[2];浮點數數組
  2. glGetFloatv(GL_POINT_SIZE_RANGE,sizes);提取頂點尺寸的範圍
  3. GLfloat min = sizes[0];最小
  4. GLfloat max = sizes[1];最大
  5. GLfloat granularity;
  6. glGetFloatv(GL_POINT_SIZE_GRANULARITY,&granularity);提取頂點尺寸的粒度
  7. GLfloat size;
  8. glGetFloatv(GL_POINT_SIZE,&size);獲取當前頂點尺寸
  9. size = size + granularity;加大
  • size = size – granularity;減小
  • glPointSize(size);設置當前頂點的大小,但不能在glBegin()與glEnd()之間調用

OpenGL之速度與質量

OpenGL之速度與質量

因顯卡性能各異,所以OpenGL可給用戶在速度與質量之間作出選擇,參數在下表給出.並給出示例代碼:

Void glHint(GLenum target, GLenum hint);

HINT 簡介
GL_FASTEST 使用最快速度和效率,但畫面質量有所下降.
GL_NICEST 使用最高畫面質量,但運行速度有所下降
GL_DONT_CARE 由顯卡的OpenGL驅動在速度和質量之間作出選擇

 

TARGET 簡介
GL_POINT_SMOOTH_HINT 指定在進行反鋸齒的操作中,點、線、多邊形的抽樣質量
GL_LINE_SMOOTH_HINT
GL_POLYGON_SMOOTH_HINT
GL_FOG_HINT 若hint設為GL_NICEST,煙霧的計算將以每像素的形式執行

若hint設為GL_FASTEST,煙霧的計算將以每頂點的形式執行

GL_PERSPECTIVE_CORRECTION_HINT 指定顏色和紋理坐標的插值品質

設置OpenGL性能

hint:建議性能

GL_FASTEST:速度優先

GL_NICEST:最高畫面質量

GL_DONT_CARE:由顯卡驅動決定

void Set_Hint_OpenGL(GLenum hint)

{

glHint(GL_POINT_SMOOTH_HINT,          hint);// 點

glHint(GL_LINE_SMOOTH_HINT,           hint);// 線

glHint(GL_POLYGON_SMOOTH_HINT,        hint);// 多邊形

glHint(GL_FOG_HINT,                   hint);// 煙霧

glHint(GL_PERSPECTIVE_CORRECTION_HINT,hint);//紋理坐標

}

OpenGL之錯誤碼

OpenGL之錯誤碼

OpenGL內部有ERROR錯誤標記,若向OpenGL的函式傳遞不正確的參數,函式會設置錯誤碼並返回.錯誤代碼一但產生就不會修改,直到調用

GLenum error = glGetError();

它將返回下表的錯誤代碼,並把標記重設為GL_NO_ERROR:

錯誤碼 簡介
GL_NO_ERROR 無錯誤
GL_INVALID_ENUM 傳遞不被支持枚舉型(enum)數值時產生此錯誤
GL_INVALID_VALUE 傳遞超出可接受範圍的數值時產生此錯誤
GL_INVALID_OPERATION 傳遞參數未能運行或當前設置未能運行,這錯誤碼較上兩者更難以追查錯誤
GL_STACK_OVERFLOW 堆盞溢出
GL_STACK_UNDERFLOW 堆盞不平衡
GL_OUT_OF_MEMORY 內存耗盡或內存洩漏
GL_TABLE_TOO_LARCE 過多使用TABLE而產生

 

OpenGL版本

OpenGL之查詢版本

調用glGetString()可以很方便提取顯卡的OpenGL信息,但需在wglMakeCurrent()之後調用,否則返回NULL.我使用此函式製作讀取OpenGL版本程式:下載

函式原型:

const GLubyte * glGetString(GLenum name);

name參數 簡介
GL_VENDOR 顯卡的製造商名稱
GL_RENDERER 顯卡型號和CPU的信息
GL_VERSION 顯卡驅動主輔版本號
GL_EXTENSIONS OpenGL擴展支持列表,以空格進行分割

 

OpenGL之全屏

OpenGL之全屏

從DOS,街機到手機遊戲都是以全屏出現,全屏顯示只需加入小量代碼

  1. 填充DEVMODE數據結構
  2. 設定屏幕寬度dmPelsWidth
  3. 設定屏幕高度dmPelsHeight
  4. 設定屏幕像素BIT數dmBitsPerPel
  5. 設定有效字dmFields
  6. 調用ChangeDisplaySettings(&devmode,CDS_FULLSCREEN)進入全屏模式,成功設定返回DISP_CHANGE_SUCCESSFUL
  7. 創建窗口CreateWindowEx()
  8. 擴展樣式設為全屏窗口WS_EX_APPWINDOW
  9. 窗口樣式樣式設為無邊框窗口WS_POPUP
  10. 窗口寬高需等於屏幕寬高
  11. 隱藏鼠標ShowCursor(false);

設定為全屏需在CreateWindow之前調用,下面是完整的代碼

bool Set_FullScreen_OpenGL(int screenWidth,int screenHeight,int screenBpp )

{

DEVMODE devmode;

memset(&devmode,0,sizeof(devmode));// 清零

devmode.dmSize = sizeof(DEVMODE);// 填充DEVMODE

devmode.dmPelsWidth  = screenWidth;// 屏幕寬度

devmode.dmPelsHeight = screenHeight;// 屏幕高度

devmode.dmBitsPerPel = screenBpp;// 屏幕像素BIT數

devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;// 設定有效字段

// 設為全屏

if(ChangeDisplaySettings(&devmode,CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)

OpenGL_FullScreen = true;

else

OpenGL_FullScreen = false;

return OpenGL_FullScreen;

}

退出程序時恢復為窗口模式

bool Set_Window_OpenGL()

{ // 設為窗口模式

if(ChangeDisplaySettings(NULL,0) == DISP_CHANGE_SUCCESSFUL)

{

OpenGL_FullScreen = false;

ShowCursor(true);// 顯示鼠標

}

return OpenGL_FullScreen;

}

OpenGL之重設窗口大小

OpenGL之重設窗口大小

當OpenGL窗口的大小發生改變時,OpenGL窗口會變形需要重新設定以適應新的窗口大小.

  1. 收到WM_SIZE消息後獲取窗口大小,高度為HIWORD(lParam),寬度為LOWORD(lparam)
  2. 重置視區尺寸glViewport(0,0,width,height);
  3. 設定投影矩陣glMatrixMode(GL_PROJECTION);
  4. 載入單位矩陣glLoadIdentity();
  5. 計算窗口尺寸比例gluPerspective();
  6. 設定模型視圖矩陣glMatrixMode(GL_MODELVIEW);
  7. 載入單位矩陣glLoadIdentity();

給出重設窗口大小完整代碼

void Set_WindowSize_OpenGL(int width,int height)

{

if(height == 0)

height = 1;// 确保分母不为0

// 重置视区尺寸

::glViewport(0,0,width,height);

// 设定投影矩阵

::glMatrixMode(GL_PROJECTION);

// 载入单位矩阵

::glLoadIdentity();

// 计算窗口尺寸比例

gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);

// 设定模型视图矩阵

::glMatrixMode(GL_MODELVIEW);

// 载入单位矩阵

::glLoadIdentity();

}

OpenGL之繪製環境

OpenGL之繪製環境

繪製環境Context用於記錄OpenGL的設置和命令,但繪製環境必需在像素格式設置完成後調用.下麵是簡介和源碼

繪製環境 簡介
HGLRC 繪製環境的句柄
HGLRC wglCreateContext(HDC hDC); 創建繪製環境,並返回繪製環境句柄, 在WM_CREATE消息下調用
BOOL wglDeleteContext(HDC hDC,HGLRC hRC); 刪除繪製環境, 在WM_CLOSE消息下調用
BOOL wglMakeCurrent(HDC hDC,HGLRC hRC); 設置當前繪製環境,若HGLRC設為NULL則取消當前設定的繪製環境

創建繪製環境

void Create_Context_OpenGL(HDC hDC)

{ //創建繪製環境

hGLRC = ::wglCreateContext(hDC);

// 設置為繪製環境

::wglMakeCurrent(hDC,hGLRC);

}

刪除繪製環境

void Delete_Context_OpenGL(HDC hDC)

{ // 取消設定的為繪製環境

::wglMakeCurrent(hDC,NULL);

// 刪除繪製環境

::wglDeleteContext(hGLRC);

}

OpenGL之像素格式

OpenGL之像素格式

在OpenGL工作之前需要設定當前環境設備(顯卡)像素格式,只需三步:

設定像素格式 簡介
PIXELFORMATDESCRIPTOR 填充像素格式
ChoosePixelFormat() 獲取顯卡支持的像素格式,返回索引
SetPixelFormat() 設置當前環境設備(顯卡)的像素格式

PIXELFORMATDESCRIPTOR需要填補的數值較多

字段 填充數值 像素格式簡介
iPixelType sizeof(PIXELFORMATDESCRIPTOR) 結構的大小
nVersion 1 版本號填1
dwFlags PFD_DRAW_TO_WINDOW 支持在窗口繪畫
PFD_DRAW_TO_BITMAP 支持在位圖繪畫
PFD_SUPPORT_GDI 緩存支持GUI繪畫
PFD_SUPPORT_OPENGL 緩存支持OPENGL繪畫
PFD_GENERIC_ACCELERATED
PFD_GENERIC_FORMAT
PFD_NEED_PALETTE
PFD_NEED_SYSTEM_PALETTE
PFD_DOUBLEBUFFER 支持雙緩存
PFD_STEREO
PFD_SWAP_LAYER_BUFFERS 支持交換Layer緩存
PFD_DEPTH_DONTCARE 支持Z緩存
PFD_DOUBLEBUFFER_DONTCARE
PFD_STEREO_DONTCARE
iPixelType PFD_TYPE_RGBA RGBA像素
PFD_TYPE_COLORINDEX 256色使用調色板索引
cColorBits 32、24、16、8 每像素所占字節數
cRedBits 0 紅色所占Bit數
cRedShift 0 紅色偏移Bit量
cGreenBits 0 綠色所占Bit數
cGreenShift 0 綠色偏移Bit量
cBlueBits 0 藍色所占Bit數
cBlueShift 0 藍色偏移Bit量
cAlphaBits 0 Alpha所占Bit數
cAlphaShift 0 Alpha偏移Bit量
cAccumBits 0 累加緩存Bit數
cAccumRedBits 0 紅色累加緩存Bit數
cAccumGreenBits 0 綠色累加緩存Bit數
cAccumBlueBits 0 藍色累加緩存Bit數
cAccumAlphaBits 0 Alpha累加緩存Bit數
cDepthBits 16 z-buffer(Z緩存)大小
cStencilBits 0 模板緩存Bit數
cAuxBuffers 0 輔助緩存Bit數
iLayerType 0 繪製平面
bReserved 0 保留字段
dwLayerMask 0 不在使用
dwVisibleMask 0 透明色掩碼索引
dwDamageMask 0 不在使用

 

最後給出完整代碼

void Setup_PixelFormat_OpenGL(HDC hDC)

{

PIXELFORMATDESCRIPTOR pfd;

int index;

pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);// 結構的大小

pfd.nVersion = 1;//版本號填1

pfd.dwFlags  = PFD_DRAW_TO_WINDOW |//  支持窗口

PFD_SUPPORT_OPENGL |// 支持OPENGL

PFD_DOUBLEBUFFER   ;// 支持雙緩存

pfd.iPixelType = PFD_TYPE_RGBA;// 像素數據類型RGBA

pfd.cColorBits = 16;// 16bit每像素所占字節數

pfd.cRedBits   = 0;// 紅色所占Bit數

pfd.cRedShift  = 0;// 紅色偏移Bit量

pfd.cGreenBits   = 0;// 綠色所占Bit數

pfd.cGreenShift  = 0;// 綠色偏移Bit量

pfd.cBlueBits   = 0;// 藍色所占Bit數

pfd.cBlueShift  = 0;// 藍色偏移Bit量

pfd.cAlphaBits  = 0;// Alpha所占Bit數

pfd.cAlphaShift  = 0;// Alpha偏移Bit量

pfd.cAccumBits      = 0;// 累加緩存Bit數

pfd.cAccumRedBits   = 0;// 紅色累加緩存Bit數

pfd.cAccumGreenBits = 0;// 綠色累加緩存Bit數

pfd.cAccumBlueBits  = 0;// 藍色累加緩存Bit數

pfd.cAccumAlphaBits = 0;// Alpha累加緩存Bit數

pfd.cDepthBits      = 16;// 16bit z-buffer(Z緩存)大小

pfd.cStencilBits    = 0;// 模板緩存Bit數

pfd.cAuxBuffers     = 0;// 輔助緩存Bit數

pfd.iLayerType      = 0;// 無繪製平面

pfd.bReserved       = 0;// 保留字段

pfd.dwLayerMask     = 0;// 不在使用

pfd.dwVisibleMask   = 0;// 透明色掩碼索引

pfd.dwDamageMask    = 0;// 不再使用了

// 獲取當前環境設備(顯卡)支持的像素格式,返回索引

index = ::ChoosePixelFormat(hDC,&pfd);

// 設置當前環境設備(顯卡)的像素格式

::SetPixelFormat(hDC,index,&pfd);

}