第一個OpenGL程序
一、OpenGL簡介
- OpenGL基本函數庫用來描述圖元、屬性、幾何變換、觀察變換和進行多種其它操作。
- OpenGL是一個開放式的、與硬件無關的軟件包。因此輸入和輸出函數等操作均不包含在其基本庫中。但在OpenGL開發的輔助庫中有輸入和輸出函數以及眾多附加函數。
- OpenGL是一個專業的、功能強大的、調用方便的底層三維圖形函數庫。
- OpenGL是一個圖形與硬件的接口。
二、OpenGl語法
OpenGl基本庫(核心庫)中的函數都要以gl為前綴。並把組成函數的每個單詞首字母用大寫形式表示。例如
glClear,glPolygonMode
OpenGL中的常量均以大寫字母GL開頭,命名中每一個組成單詞均大寫,中間用_隔開。例如
GL_RGB,GL_POLYGON
不同機器上整數描述範圍可能不同,OpenGL有專門的數據類型。如下
後綴 | 數據類型 | 典型的對應C語言類型 | OpenGL類型定義 |
---|---|---|---|
b | 8位整數 | signed char | GLbyte |
s | 16位整數 | short | GLshort |
i | 32位整數 | int or long | GLint,GLsizei |
f | 32位浮點數 | float | GLfloat,GLclampf |
d | 64位浮點數 | double | GLdouble,GLclampd |
ub | 8位無符號整數 | unsigned char | GLubyte,GLboolean |
us | 16位無符號整數 | unsigned short | GLushort |
ui | 32位無符號整數 | unsigned int or unsigned long | GLuint,GLenum,GLbitfield |
OpenGL的庫函數采用C語言風格,他們分別屬於以下不同的庫。
- OpenGL核心庫,函數名前綴gl。
- OpenGL實用庫,函數名前綴glu。
- OpenGL輔助庫,函數名前綴aux。
- OpenGL工具庫,函數名前綴glut。
- Windows專用庫,函數名前綴wgl。
- Win32 API 函數庫。
三、第一個OpenGL程序
首先一步步來創建我們的第一個OpenGL程序:在窗口中畫一條線段。我們使用GLUT
glutInit(&argc, argv);
接著創建一個窗口並給出標題。
gultCreateWindow("LearnOpenGL example");
盡管窗口有默認位置和大小,但是還可以使用glut函數來設置這些參數。例如
glutInitWindowPosition(50,100);
上面代碼指定顯示窗口左上角應在屏幕左邊界向右50個像素、屏幕上邊界向下100個像素。
glutInitWindonSize(800,600);
上面代碼指定寬度為800像素,高度為600像素的顯示窗口。還可以使用gultInitDisplayMode
函數來顯示窗口和緩存和顏色模型。如下面使用單個緩存和RGB三原色組成的模型。
glutInitDisplayMode(GULT_SINGLE|GLUT_RGB);
可以使用RGB顏色設置顯示窗口的背景顏色。使用函數
glClearColor(1.0,1.0,1.0,0.0);
上面代碼將背景顏色設置為白色,四個參數是\(RGBA\),分別表示紅、綠、藍、以及調和參數,\(A=0.0\)表示完全透明,\(A=1.0\)表示完全不透明。這裏先不仔細討論這個參數。實驗中我們將背景顏色設置為類似於黑板的顏色。
盡管上述命令將顏色參數賦給了窗口,但是不能讓顯示窗口在屏幕上出現。還必須引入下面函數
glClear(GL_COLOR_BUFFER_BIT);
變量GL_COLOR_BUFFER_BIT
是OpenGL常量,用它來指定顏色緩存的位值。除了顯示背景色,還可以為要顯示的場景中的數據顯示各種顏色。
glColor3f(0.0,0.4,0.2);
上面指定的三個分量就是RGB值。我們的第一個程序是顯示一條二維的線段,但是OpenGL是默認處理3維的,二維線段是三維的特例,但是OpenGL還是采用三維觀察來處理這個圖形。用函數
glMatrixMode(GL_PROJECTTION);
gluOrtho2D(0.0,200.0,0.0,150.0);
表示用正投影觀察將世界坐標系2維矩形區域映射到屏幕上,矩形區域上\(x\)範圍從\(0-200.0\),\(y\)範圍為\(0-150.0\)。完整程序
在OpenGL中,我們利用頂點來定義圖形系統可以識別的基本幾何圖元。OpenGL中許多函數都有多重形式,頂點函數的形式為glVertex*()
,*號表示諸如nt、ntv
之類的,\(n\)代表維數,\(t\)表示數據類型,\(v\)表示變量由指向一個數組的指針來給出。例如在2維坐標中畫一個點:glVertex2f(50.0f,100.0f);
表示在二維坐標系中位置為\((50,100)\)處化一個點,點的數據類型是GLfloat,而下面形式用整數類型確定了三維空間的一個位置
glVertex3i(GLint x, GLint y,GLint z);
如果利用數組來表示三維點的信息GLint vertex[3];
, 那麽可以使用
glVertex3iv(vertex);
頂點可以定義很多位置的幾何圖元。下面是在窗口中畫一條線段的完整程序。
#include <GL/glut.h>
#include <iostream>
using namespace std;
void lineSegment()
{
// clear display-window
glClear(GL_COLOR_BUFFER_BIT);
// set linesegment color to red
glColor3f(1.0, 0.0, 0.0);
// Create linesigment
glBegin(GL_LINES);
glVertex2i(0, 0);
glVertex2i(50, 500);
glEnd();
glFlush();
}
int main(int argc, char **argv)
{
// Initialize GLUT
glutInit(&argc, argv);
// Set display model
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
// Set window position
glutInitWindowPosition(100, 100);
// Set Display window size
glutInitWindowSize(800, 600);
//create aw window
glutCreateWindow("LearnOpenGL example");
// ====================================================================
// Set display-window color
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
// set projection parameters
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 200.0, 0.0, 200);
// display line
glutDisplayFunc(lineSegment);
glutMainLoop();
return 0;
}
OpenGL利用下面形式來定義幾何對象
glBegin(type);
glVertex*();
...
...
glVertex*();
glEnd();
參數type指定OpenGL把頂點組合起來定義幾何對象的方式。OpenGL提供了多種類型的點和線段圖元
- 點(GL_POINTS) 每個頂點被顯示的大小至少是一個像素。
- 線段(GL_LINES) 圖元把相繼的頂點配對後解釋為線段的兩個端點。註意頂點時兩兩配對處理的,所以如果有奇數個點,最後一個點由於無法配對,將會被舍棄。
- 折線(GL_LINE_STRIP,GL_LINE_LOOP) 使用這兩個參數表示用線段將相鄰兩個點相連,而後者還將最後一個點與第一個點相連從而形成閉環。可以看經典教材《計算機圖形學(第四版)》的\(P_{39}\)頁更形象。
在繪制圖元時,在應用程序結束後,可能我們還沒來得及看到輸出窗口就消失了。目前可以使用GLUT函數
void glutMainLoop();
這個函數執行會讓程序進入一個事件處理循環。如果沒有事件需要處理,程序會處於等待狀態,直到通過某種外部方式來終止程序的執行,比如按下Ctrl+C。
圖形是通過一個稱為顯示回調(display callback)的函數發送到屏幕上的。這個函數通過下面的GLUT函數指定並註冊(register)到窗口系統:
void glutDisplayFunc(void (*func)(void));
只要窗口系統確定OpenGL窗口需要重新繪制,上面指定的func函數就會被調用。
四、動手實現二維Sierpinski鏤墊程序
Sierpinski鏤墊是一個有趣的圖形。我們先來嘗試繪制二維的Sierpinski鏤墊圖形,初始給出一個三角形ABC,步驟如下:
- 在三角形中隨機選擇一個初始點\(p(x,y)\).
- 隨機選擇三個頂點之一。
- 求點\(p\)與第二步中選擇的三角形頂點的中點並將該點畫出來。
- 更新該點為點\(p\)
- 轉步驟2
我們假定循環5000次,然後看看最終的效果是什麽。將主程序寫成函數display()
,先給出代碼和效果,然後再對程序進行分析。
#include <GL/glut.h>
#include <iostream>
#include <cmath>
using namespace std;
void Init()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glColor3f(1.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 100.0, 0.0, 100.0);
glMatrixMode(GL_MODELVIEW);
}
void Display()
{
GLfloat vertices[3][2] = { {10.0,10.0},{90.0,10.0},{50.0, 70.0} };
int i, j, k;
GLfloat p[2] = { 75.0,75.0 };
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
for (int i = 0; i < 5000; i++)
{
int j = rand() % 3;
p[0] = (vertices[j][0] + p[0]) / 2;
p[1] = (vertices[j][1] + p[1]) / 2;
glVertex2fv(p);
}
glEnd();
glFlush();
}
int main(int argc, char **argv)
{
// Initialize GLUT
glutInit(&argc, argv);
// Set display model
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
// Set window position
glutInitWindowPosition(100, 100);
// Set Display window size
glutInitWindowSize(800, 600);
//create aw window
glutCreateWindow("LearnOpenGL example");
// ====================================================================
// Set display-window color
// display Cycle
glutDisplayFunc(Display);
Init();
glutMainLoop();
return 0;
}
Init()
函數包括了必要的初始化步驟。主要看display()
函數,我們首先定義了三角形的三個頂點存放在vertices[]
數組中,然後在三角形內部隨機選取了一個點p,接著就開始畫點了,循環5000次,這個過程中,我們使用了rand()
函數來隨機選擇一個三角形的頂點。而最終顯示,這些點收斂的很有規律。
第一個OpenGL程序