OpenGL之二次曲面

OpenGL之二次曲面

如果要繪製『球體』,『圓柱』,『圓錐』,『圓盤』除了可以自已編寫圖形庫.還可以時用OpenGL Utility Library(OpenGL實用庫)提供的高級圖形支持.簡稱為GLUT.要下載可到官網下載: https://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip 但windows版只支持x86.演示程式:下載

1.創建二次曲面對象,成功返回指向二次曲面的指針,否則返回NULL

GLUquadric*gluNewQuadric(void);

2.設置繪製風格

void gluQuadricDrawStyle(GLUquadric *quadObject,GLenum drawStyle);

drawStyle(繪畫樣式) 簡介
GLU_FILL 實體填充渲染
GLU_LINE 以線框模式渲染
GLU_SILHOUETTE 以輪框模式渲染,排除多邊形的共線.
GLU_POINT 以頂點模式渲染

3.設置法線生成

法線狀態用於設置二次曲面的表面法線的生成方式.

void WINAPI gluQuadricNormals(GLUquadric *quadObject,GLenum normals);

Normals(法線狀態) 簡介
GLU_NONE 不生成法線
GLU_FLAT 每個多邊形生成一個法線(單調明暗處理)
GLU_SMOOTH 每個頂點生成一個法線(平滑明暗處理) (默認值)

3.設置法線方向

設置生成法線的方向,內部還是外部.

Void gluQuadricOrientation(GLUquadric *quadObject,GLenum orientation);

Orientation(方向) 簡介
GLU_OUTSIDE 法線指向外側(默認值)
GLU_INSIDE 法線指向內側

4.設置紋理座標

紋理狀態是否為圖形生成紋理座標

void gluQuadricTexture(GLUquadric *quadObject,GLboolean textureCoords);

textureCoords 簡介
GL_TRUE 生成紋理座標
GL_FALSE 不生成紋理座標(默認值)

5.當不使用二次曲面後需要釋放資源

void gluDeleteQuadric(GLUquadricObj *state);

 

二次曲面繪畫

1.繪畫偏平的圓盤,中間可以有個圓孔

void gluDisk(GLUquadric *qobj,GLdouble innerRadius,GLdouble outerRadius,GLint slices,GLint loops);

繪畫偏平的扇形圓盤

void gluPartialDisk(GLUquadric *qobj,GLdouble innerRadius,GLdouble outerRadius,GLint slices,GLint loops,GLdouble startAngle,GLdouble sweepAngle);

參數 簡介
qobj 二次曲面對象
innerRadius 內圓直徑,若為0則是閉孔,大於零則中心有個孔
outerRadius 外圓直徑
Slices 繞z軸的細分數.此值越大圓盤越圓
Loops 同軸圓盤的邊形細分數
startAngle 扇形起此角度
sweepAngle 扇形圓弧角度

2.繪畫圓錐和圓柱

void gluCylinder(GLUquadric *qobj,GLdouble baseRadius,GLdouble topRadius,GLdouble height,GLint slices,GLint stacks);

分別有底座半徑與柱頂半徑若其一為0為圓錐,若兩值不相等則為錐形圓柱,若兩值相等則為圓柱. 底座圓面與柱頂圓面是繪畫的,你需要使用gluDisk()另外繪畫

圓柱沿Z軸繪畫,底座為於Z=0, 柱頂位於Z=height(高度)

參數 簡介
qobj 二次曲面對象
baseRadius 底座半徑 z=0
topRadius 柱頂半徑z=height
height 圓柱的高度
slices 繞Z軸的細分數.此值越大圓柱越圓
stacks 延Z軸的細分數.此值越高返射光的效果越好.

3.繪畫球體,按給定半徑以原點為中心進行繪製

void gluSphere(GLUquadric *qobj,GLdouble radius,Glint slices,GLint stacks);

參數 簡介
qobj 二次曲面對象
radius 球體的半徑
slices 繞z軸的細分數(相當於經線)
stacks 沿z軸的細分數(相當於緯線)

 

OpenGL之模板緩存

OpenGL之模板緩存

使用『模板緩存』可以將屏幕中的某些部分從視野中屏蔽.其中的特效是『鏡像』效果.鏡像(倒影)演示程式:下載

1.設置像素格式時對PIXELFORMATDESCRIPTOR對cStencilBits設置為 16bit『模板緩存』.

PIXELFORMATDESCRIPTOR pdf;

pfd.cStencilBits = 16;

2.要啟用『模板緩存』

glEnable(GL_STENCIL_TEST);

3.設置模板操作

void glStencilOp(GLenum fail,GLenum zfail,GLenum zpass);

fail:模板測試失敗

zfail:模板測試通過,但深度測試失敗

zpass:模板測試與深度測試均通過

操作 簡介
GL_KEEP 保持當前值
GL_ZERO 將模板緩存的值設定為0
GL_REPLACE 將模板緩存的值設定為glStencilFunc()的參考值ref.
GL_INCR 增加當前模板的緩存值
GL_DECR 減小當前模板的緩存值
GL_INVERT 將模板緩存的值反轉

4.設置模板比較程序

void glStencilFunc(GLenum func,GLint ref,GLuint mask);

func:比較程式

ref:參考值

mask:模板掩碼

比較程式 簡介
GL_NEVER 總是失敗
GL_LESS 條件比較:if (ref & mask) < (stencil & mask).
GL_LEQUAL 條件比較:if (ref & mask) ≤ (stencil & mask).
GL_GREATER 條件比較:if (ref & mask) > (stencil & mask).
GL_GEQUAL 條件比較: if (ref & mask) ≥ (stencil & mask).
GL_EQUAL 條件比較: if (ref & mask) = (stencil & mask).
GL_NOTEQUAL 條件比較: if (ref & mask) ≠ (stencil & mask).
GL_ALWAYS 總是允許

繪畫鏡像函式代碼演示:

1.禁用深度測試

glDisable(GL_DEPTH_TEST);

2.禁用對所有的然色分量的修改

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

3.啟用模板測試

glEnable(GL_STENCIL_TEST);

4.將地板繪製到模板緩存中,引用參考值ref

glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

glStencilFunc(GL_ALWAYS, 1, 1);

5.繪畫地板後雖然還未睇到地板,但已在模板緩存中生成孔,在孔中的多邊形將不被繪製

Draw_Floor();

6.啟用所有顏色分量的修改

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

7.啟用深度測試

glEnable(GL_DEPTH_TEST);

8.設置模板比較程序,只能在模板緩存中值為1的相應去區域繪製

glStencilFunc(GL_EQUAL, 1, 1);

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

9.壓入模型矩陣.準備繪製”鏡像”

glPushMatrix();

10.返轉境像

glScalef(1.0f, -1.0f, 1.0f);

11.繪畫鏡像(倒影)

Draw_Mirror();

11.彈出模型矩陣結束鏡像繪製

PopMatrix();

12.禁用模板測試

glDisable(GL_STENCIL_TEST);

13.以50%繪製透明地板, 啟用混合

glEnable(GL_BLEND);

glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

glColor4f(1.0f,1.0f,1.0f,0.5f);

14.繪畫地板

Draw_Floor();

15.禁用混合

glDisable(GL_BLEND);

 

OpenGL之紋理映射字體

OpenGL之紋理映射字體

因為『3D輪廓字體』只是填充純色,但可以對『3D輪廓字體』應用紋理映射,以增強其外觀效果.紋理座標可以讓OpenGL自動生成.演示程式下載:

1.讓OpenGL為文本生成紋理座標,並固定於3D模型

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

glEnable(GL_TEXTURE_GEN_S);

glEnable(GL_TEXTURE_GEN_T);

2.載入紋理

Load_File_Texture(&font3D->texture, hInstance, filename);

3.綁定紋理

glBindTexture(GL_TEXTURE_2D, texture->texID);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

OpenGL之3D輪廓字體

OpenGL之3D輪廓字體

之前一直使用Windows自帶字體輸出文本,但只限2D的『位圖字體』.在Windows下有獨有輪廓字體函式.讓文本具有一定的厚度.讓所有的Windows字體轉換成3D字體.演示程式可輸入英文字符,下載程式:

1.存儲輪廓字體位置和方向,生成256個GLYPHMETRICSFLOAT變量

GLYPHMETRICSFLOAT gmf[256];

2.創建大小為256個字符的顯示列表,對所有256個ASCII碼支持.

UINT base;// 顯示列表的BASE ID

base = glGenLists(256);

3.創建字體句柄

HFONT font;

font=CreateFont(1,0,0,0,FW_BOLD,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,NTIALIASED_QUALITY,FF_DONTCARE|DEFAULT_PITCH,”Arial”);

4.為字體選擇設備環境

SelectObject(hDC,font);

5.創建3D輪廓字體,每個ASCII對應一個輪廓字體

wglUseFontOutlines(hDC,0,256,base,0.0f,FONT3D_DEPTH,WGL_FONT_POLYGONS,gmf);

6.複製當前矩陣並壓棧

glPushMatrix();

7.將文本定位於場景空間的中央.計算文本的長度

length = (int)strlen(text);

for(int i=0;i<length; ++i)

{

char  c = text[i];

width = width + gmf[c].gmfCellIncX;

if(gmf[c].gmfCellIncX > height )

height = gmf[c].gmfCellIncX;

}

8.設定文本座標

glTranslatef(posX – (width0.1f)/2.0f,posY – (height0.1f)/2.0f ,posZ + (FONT3D_DEPTH*0.1f)/2.0f);

9.顯示列表屬性壓棧

glPushAttrib(GL_LIST_BIT);

10.載入顯示列表ID

glListBase(base);

11.渲染文本

glCallLists((int)strlen(text),GL_UNSIGNED_BYTE,text);

12.顯示列表屬性出棧

glPopAttrib();

OpenGL之位圖字體

OpenGL之位圖字體

要在屏幕上顯示文本可以使用Windows自帶字體進行渲染.比起之前使用『點陣字體』方便簡潔很多,但此方法只式用於Windows.演示程式可輸入英文字符,下載程式:

1.創建96個顯示列表IDs,存儲生成的字符位圖

UINT base;// 顯示列表的BASE ID

base = glGenLists(96);//創建大小為96BYTE的顯示列表

2.創建顯示列表後,使用CreateFont()創建字體

HFONT font;// 字體句柄

font=CreateFont(12,0,0,0,FW_BOLD,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,FF_DONTCARE | DEFAULT_PITCH,”Courier”);

3.為字體選擇一個設備環境

SelectObject(hDC,font);

4.從系統載入字體文檔並生成位圖.

wglUseFontBitmaps(hDC,32,96,base);

5.設定屏幕位置

glRasterPos2i(xPos,yPos);

7.顯示列表屬性壓棧

glPushAttrib(GL_LIST_BIT);

6.載入顯示列表ID

glListBase(base-32);

7.渲染文本

glCallLists((int)strlen(text),GL_UNSIGNED_BYTE,text);

8.顯示列表屬性出棧

glPopAttrib();

OpenGL之視錐體裁剪

OpenGL之視錐體裁剪

圖形引擎繪製任何睇不見(視錐截體之外)的任何物體,都會浪費保貴GPU資源.相機的視錐體定義你所能夠梯到的3D世界空間.視錐體由相機的位置和視野組成.視錐體由六個平面組成.只要進入視錐體內的3D模型都應被渲染.(被其它3D模型遮檔除外).位於視錐體之外則不必渲染.

OpenGL會自動丟棄在視錐體之外的三角形.但OpenGL是逐個三角形進行視錐體裁剪.當你有大量(幾萬個)的三角形進入OpenGL裁剪隊列時.會大大地降低程式性能.

最簡單的優化方式是定義3D球形容器,用於包裹你的3D模型.然後使用視錐體與3D球形進行測試.如果3D球形完全在視錐體之外.即可放棄渲染3D模型.如果3D模型部分或全部進入視錐體內,則交由OpenGL繼序進行三角形裁剪

演示程式中有幾百個隨機移動球體,按空格鍵啟用或禁用『視錐體裁剪』.未啟用之前不到200幀.一但啟動『視錐體裁剪』則超過1000幀.性能大幅提高五倍(視渲染球體的個數而定).程式下載:

 

定義3D球體

typedef struct SPHERE3D{

float    x, y, z;// 中心點

float    radius;// 球體半徑

}SPHERE3D,* SPHERE3D_PTR;

 

定義3D平面

typedef struct PLANE3D_TYP{

float A, B, C;// 平面法線向量

float D;//平面到原點最近距離

}PLANE3D,*PLANE3D_PTR;

 

定義視錐體

typedef struct FRUSTUM_TYP {

PLANE3D planes[6];//6個平面

}FRUSTUM, *FRUSTUM_PTR;

 

1.平面方程式定義:

Ax + By + Cz + D = 0

A,B,C:平面的法線向量

D:從平面到原點的距離

x,y,z:平面上的任意點

結果為零:該點落在平面上

結果為正:該點為于平面的前方

結果為負:該點為於平面的後方

 

2.確定視錐體尺寸,獲取投影矩陣和模型視口矩陣

glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat*)&projection);

glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&modelview);

 

3.投影矩陣乘以模型視口矩陣

glPushMatrix();

glLoadMatrixf((GLfloat*)&projection);

glMultMatrixf((GLfloat*)&modelview);

glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&modelview);

glPopMatrix();

 

4.提取視錐體的六個平面

int scale = (row < 0) ? -1 : 1;

row = abs(row) – 1;

plane->A = mat->M[0][3] + scale * mat->M[0][row];

plane->B = mat->M[1][3] + scale * mat->M[1][row];

plane->C = mat->M[2][3] + scale * mat->M[2][row];

plane->D = mat->M[3][3] + scale * mat->M[3][row];

平面(plane) 行(row)
左則 1
右則 -1
底部 2
頂部 -2
近端 3
遠端 -3

 

5.平面歸一化

float length = sqrtf(plane->A * plane->A + plane->B * plane->B + plane->C * plane->C);

plane->A /= length;

plane->B /= length;

plane->C /= length;

plane->D /= length;

 

6.檢查3D球體是否為於視錐體內

frustum:視錐體

sphere:球體

返回值:若在視錐體內返回TRUE,否則反回FALSE

bool Compute_Sphere_In_Frustum(FRUSTUM_PTR frustum, SPHERE3D_PTR sphere)

{

float dist;

for (int i=0;i<6;++i)

{// 判斷球體是否為與六個平面之前

PLANE3D_PTR plane = &frustum->planes[i];

// 計算點與平面的距離,若為正在視錐體內,若為負在視錐體外

dist = plane->A * sphere->x + plane->B * sphere->y + plane->C * sphere->z + plane->D;

if (dist <= -sphere->radius)

return false;// 在視錐體外

}

return true; // 在視錐體內

}

 

OpenGL之數組鎖定

OpenGL之數組鎖定

OpenGL允許鎖定(lock)與解鎖(unlock)數組.當鎖定(lock)數組後,數據便不能更改.當存在大量共用的頂點,並且進行多次操作.能大大地提高運行速度

 

數據初此化後鎖定數組

void glLockArraysEXT(GLint first, GLsizei count);

first:頂點索引

count:頂點個數

 

程序退出時對數組解鎖

void glUnlockArraysEXT(void);

 

演示程式中,因為地形數據不會改變,對其進行鎖定.按空格鍵可切換鎖定(lock)與解鎖(unlock).幀數大約提升10%.只是兩行代碼就有不小的性能改進.下載:

OpenGL之頂點數組與多紋理映射

OpenGL之頂點數組與多紋理映射
將頂點數組『VertexArray』應用於多紋理『Multitexture』映射,由於每個紋理單元都有其自已的狀態.要將每個紋理單元都單度地啟用頂點數組,並且為其每個紋理單元設定紋理座標的頂點數組.通過常試可以將多個2D紋理(GL_TEXTURE_2D)進行映射,但2D紋理與1D紋理(GL_TEXTURE_1D)多次償試都無法將『頂點數組』應用『紋理數組』映射暈.演示程式按空格鍵切換『多紋理映射』草地紋理與高度紋理.兩者幀數相約.下載:

 

要讓紋理單元使用頂點數組,必須先激活它.

void glClientActiveTexture(GLenum texture);

texture:紋理單元索引GL_TEXTURE0_ARB~GL_TEXTURE31_ARB

 

啟用紋理單元頂點座標數組

void glEnableClientState(GLenum array);

禁用紋理單元頂點座標數組

void glDisableClientState(GLenum array);

array:GL_TEXTURE_COORD_ARRAY 紋理座標數組

 

為紋理單元設定指定數組

void WINAPI glTexCoordPointer(Glint size,GLenum type,GLsizei stride,const GLvoid  *pointer);

 

設置兩個紋理單元設置頂點數組

glClientActiveTexture(GL_TEXTURE0_ARB);// 激活紋理0 

glEnableClientState(GL_VERTEX_ARRAY); // 啟用頂點數組

glEnableClientState(GL_TEXTURE_COORD_ARRAY); // 啟用紋理座標數組

glVertexPointer(3, GL_FLOAT, 0, terrain->vertex_array);// 頂點數組

glTexCoordPointer(3, GL_FLOAT, 0, terrain->grass_texcoord);// 紋理數組

glClientActiveTexture(GL_TEXTURE1_ARB);// 激活紋理1

glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glTexCoordPointer(3, GL_FLOAT,0, terrain->height_texcoord);// 紋理數組

glDrawArrays(GL_TRIANGLES, 0, polygon_num);// 繪畫所有當前以啟用的頂點數組

glDisable(GL_TEXTURE_1D);// 禁用紋理單元1

glClientActiveTexture(GL_TEXTURE0_ARB);// 重新激活紋理0,這個很重要否則會影響其它紋理貼圖

glDisableClientState(GL_VERTEX_ARRAY); // 禁用頂點數組

glDisableClientState(GL_TEXTURE_COORD_ARRAY); // 禁用紋理座標數組

glDisableClientState(GL_NORMAL_ARRAY);// 禁用法線數組

OpenGL頂點數組

OpenGL頂點數組

遊戲的實際的開發中將會大量頻繁地處理頂點,在簡單多邊形可以使用代碼直接生成模型頂點.而真正的遊戲隨便一個模型就可能有幾百或幾千個多邊形.不可能使用代碼直接生成.解決的方法是使用『頂點數組』(Vertex Array).通過建模軟件進形3D建模,然後輸出特定的文本文檔或二進制文檔.可分為以下幾個部驟.

  1. 從磁盤上的模型文檔中載入模型的頂點數據.
  2. 將頂點數據儲存在數組(array),如將頂點座標存入獨立數組,法線數組,顏色數組.
  3. 當OpenGL需要頂點數據時,載入相應的數據.

 

啟用『頂點數組』

void glEnableClientState(GLenum array);

禁用『頂點數組』

void glDisableClientState(GLenum array);

參數 簡介
GL_COLOR_ARRAY 啟用頂點顏色數組
GL_EDGE_FLAG_ARRAY 啟用頂點的邊EdgeFlag數組
GL_INDEX_ARRAY 啟用頂點的調色板索引數組
GL_NORMAL_ARRAY 啟用法線數組
GL_TEXTURE_COORD_ARRAY 啟用紋理座標數組
GL_VERTEX_ARRAY 啟用定點座標數組

 

載入頂點的顏色數組:

void glVertexPointer(GLint size,GLenum type,GLsizei stride,const GLvoid  *pointer);

參數 簡介
size 頂點顏色分量其值只能為3(rgb)或4(rgba)
type 數組的數據類型

GL_BYTE

GL_UNSIGNED_BYTE

GL_SHORT

GL_UNSIGNED_SHORT

GL_INT

GL_UNSIGNED_INT

GL_FLOAT

GL_DOUBLE

stride 跨度,兩個顏色之間的字節數,如果顏色數據是緊湊則填為0
pointer 頂點的顏色數組

 

載入邊(Edge)數組:

void glEdgeFlagPointer(GLsizei stride,const GLvoid *pointer);

參數 簡介
stride 跨度
pointer 多邊形邊(Edge)數組bool類型數值

 

載入調色板顏色索引數組

void glIndexPointer(GLenum type,GLsizei stride,const GLvoid *pointer);

參數 簡介
type 數組的數據類型

GL_SHORT

GL_INT

GL_FLOAT

GL_DOUBLE

stride 跨度相鄰索引之間的字節數
pointer 調色板顏色索引數組

 

載入頂點的法線向量,每三個元素組成一個法線向量

void glNormalPointer(GLenum type,GLsizei stride,const GLvoid *pointer);

參數 簡介
type 數組的數據類型

GL_BYTE

GL_SHORT

GL_INT

GL_FLOAT

GL_DOUBLE

stride 跨度相鄰法線之間的字節數
pointer 頂點的法線向量數組

載入頂點的紋理座標數組void glTexCoordPointer(Glint size,GLenum type,GLsizei stride,const GLvoid  *pointer);

參數 簡介
size 頂點的座標數,其值只能為1,2,3,4

1為1維紋理(s)

2為2維紋理(s,t)

3與4較小使用

type 數組的數據類型

GL_SHORT

GL_INT

GL_FLOAT

GL_DOUBLE

stride 跨度,兩個紋理之間的字節數
pointer 頂點紋理座標數組

 

載入頂點座標數組:

void glVertexPointer(Glint size,GLenum type,GLsizei stride,const GLvoid *pointer);

參數 簡介
size 頂點的座標分量:2,3,4
type 數組的數據類型

GL_SHORT

GL_INT

GL_FLOAT

GL_DOUBLE

stride 跨度,兩個頂點座標之間的字節數,如果是緊湊方置其值為0
pointer 頂點座標數組

繪畫所有當前以啟用的頂點數組void glDrawArrays(GLenum mode,GLint first,GLsizei count);

參數 簡介
mode GL_POINTS:點

GL_LINE_STRIP:相連的直線

GL_LINE_LOOP:閉合的相連直線

GL_LINES:非相連的直線

GL_TRIANGLE_STRIP:相連的三角形 GL_TRIANGLE_FAN:共用頂點三角形

GL_TRIANGLES:度立的三角形

GL_QUAD_STRIP:相連的四邊形

GL_QUADS:四邊形

GL_POLYGON:任意頂點多邊形

first 數組起此索引
count 繪畫的頂點量

 

以任意順序繪畫以啟用的頂點數組void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid *indices);

參數 簡介
mode 與glDrawArrays()的一致
count 索引數組的長度
type 索引的數據類型,只能是無符號整數GL_UNSIGNED_BYTE GL_UNSIGNED_SHORT GL_UNSIGNED_INT
indices: 索引數組

按值定的範圍繪畫以啟用的頂點數組

void glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);

參數 簡介
mode 與glDrawArrays()的一致
start 索引數組開此索引
end 索引數組結束索引
count 索引數組的長度
type 索引的數據類型,只能是無符號整數與glDrawElements()的一致
indices: 索引數組

按數組索引繪畫單一個頂點void glArrayElement(GLint index);

參數 簡介
index 頂點的索引

演示程式中繪畫幾百個球體不斷移動,若不使用頂點數組每秒只有約66幀,而若使用頂點數組性能大幅度提升到每秒有200幀.性能有驚人的提升(不同的計算機性能有所差別).按空格鍵啟用或禁用頂點數組.演示程式下載: