遊戲建模之碰撞反應

遊戲建模之碰撞反應

若3D模型發生碰撞後需要計算碰撞反應,不通物體運動有不同碰撞反應.但物體多數以直線運動.物體彈回角度和碰撞角度相等.

入射角度:桌球運動方向與邊沿平面法線向量之間夾角.

反射角度:垂直於運動方向矢量

例:當桌球撞向邊沿.它將按撞擊角度與之對等『入射角度』彈開

方程並沒有考慮球體旋轉作用力與磨擦力.最終得到計算反射方向方程式

給定運動方向矢量I與垂直法線N求碰撞反射方向F

F = (I – N2 (I % N)) * | I |;

計算反射方向代碼,dir為射線方向,normal為碰撞面法線

VECTOR3D Reflection_VECTOR3D(VECTOR3D_PTR dir,VECTOR3D_PTR normal){

VECTOR3D vec ;

Normalize_VECTOR3D(dir, &vec); // 單為化方向向量

*dir = (vec – *normal * 2.0f * (vec % *normal)) * Length_VECTOR3D(dir);

return *dir;

}

遊戲建模-平面碰撞

遊戲建模-平面碰撞

平面是3D圖形學重要部分.平面有兩個重要概念.

1.3D平面都無窮遠延伸

2.所有平面都將整個空間分成兩個半空間.正半空間為法線指向空間,負半空間則是令一則空間.這個特性對於碰撞算法重要

平面描敘如下:

平面法線向量:n=(a,b,c)

平面任意點:p0=(x0,y0,z0)

平面任意點:p=(x,y,z)

平面與原點距離:d平面位移常量(plane-shift constant)

因為法線n與向量(p0->p)垂直. 因兩垂直向量點積為零:

n * (p0->p) = 0

轉為分量表示

(a,b,c)*(x-x0,y-y0,z-z0)=0

轉為『頂點』與『法線』表示

a(x-x0)+b(y-y0)+c*(z-z0)=0

ax+by+cz+(-ax0-by0-cz0)=0

令d=-ax0-by0-c*z0

『平面方程』如下:

ax+by+c*z+d=0

 

這足以定義平面結構

typedef struct PLANE3D_TYP{

VECTOR3D n;//平面法線向量(不必是單位向量)

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

POINT3D p0;//平面上最近原點的點

}PLANE3D,*PLANE3D_PTR;

 

判斷『點』位於『平面』那個半空

3D世界中『視點』、『角色』並不能穿越牆壁.要做到這步需判斷點位於平正空間(法線指向)還是負空間.

要判斷這點需要下面的平面方程

hs=a(x-x0)+b(y-y0)+c*(z-z0)

只需將點(x,y,z)帶入方程中並計算結果

如果hs=0則該點位於平面之上

如果hs>0則該點位於平面正半空間(法線指向)中

如果hs<0則該點位於平面負半空間中

float Compute_Point_In_Plane3D(PLANE3D_PTR plane,VECTOR3D_PTR pt){

float hs = plane->A * pt->x + plane->B * pt->y + plane->C * pt->z + plane->D;

return(hs); // 返回半空間值

}

 

計算平面與直線之相交點(3D空間)

平面『頂點』與『法線』方程如下:

a(x-x0)+b(y-y0)+c*(z-z0)=0

3D直線方程如下:

(x-x0)/a = (y-y0)/b = (z-z0)/c

計算多邊形法線與直線方向點積

double a = plane->n % (line->v);

若為零則直線與平面平行

VECTOR3D Intersect;

if (a == 0)

Intersect = line->p0;

計算相交點

Intersect = line->p0 – (line->v) * ((plane->n % line->p0 + plane->D) / a);

3D線段與3D平面交點函式:

bool Intersect_Line3D_Plane3D(PLANE3D_PTR plane, PARMLINE3D_PTR line,POINT3D_PTR pt){

// 計算直線方向與多邊形法線點積

double a = plane->n % (line->v);

if (a == 0)

return false;

// 計算相交點

*pt = line->p0 – (line->v) * ((plane->n % line->p0 + plane->D) / a);

return true;

}

 

計算頂點是否為於多邊形之上,

首先計算頂點與多邊形所有頂點之間角度總和.如果該頂點位於多邊形之上.那麼此頂點與多邊形所有頂點之間角度總和將等於或接近2PI

bool Intersect_Vector3D_Polygon3D(VECTOR3D_PTR polygon, int num,VECTOR3D_PTR v){

VECTOR3D segment1, segment2;// 頂點 到 多邊形頂點 矢量

double length1, length2;// 矢量長度

double sumAngle = 0;// 矢量之間角度總和

double cosAngle = 0;// 兩矢量余弦角

// 編曆多邊形所有頂點

for (int index = 0; index < num; ++index)     {

segment1 = polygon[index] – *v;

segment2 = polygon[(index+1) % num] – *v; // % num 確保數值環形加一

length1 = Length_VECTOR3D(&segment1);

length2 = Length_VECTOR3D(&segment2);// 矢量長度

//檢查頂點是否落在多邊形邊界上

if ( length1 * length2 <= 0.0000001f){

// 多邊形邊界被認為是多邊形內部

sumAngle = PI2; // pai * 2

break;

}

// 計算上述兩個矢量之間余弦角

cosAngle = (segment1 % segment2) / (length1 * length2);

// 將計算結果累加入角度總和

sumAngle = sumAngle + acosf(cosAngle);

}

if ((sumAngle <= PI2 + 0.0000001f) && (sumAngle >= PI2 – 0.0000001f))

return true;// 頂點與多邊形發生碰撞

else

return false;

return true;

}

 

使用三個頂點初始化(定義)3D平面!

void Init_PLANE3D(PLANE3D_PTR plane,VECTOR3D_PTR va,VECTOR3D_PTR vb,VECTOR3D_PTR vc){

VECTOR3D normalA = *vc – *va;// 計算頂點C->A向量

VECTOR3D normalB = *vc – *vb;// 計算頂點C->B向量

plane->n = Cross_VECTOR3D(&normalA, &normalB);// 計算兩個3D向量叉積

plane->D = Dot_VECTOR3D(&(-(*va)), &plane->n); //距離等於va求返後與n求點積

}

遊戲建模-矢量運算

遊戲建模-矢量運算

矢量(VECTOR)也稱『向量』其實是抽象『量』它在遊戲世界被頂義為『位置』『速度』『磨擦』『方向』『點』等等. 矢量通常有3種

矢量 分量 簡序
2D矢量 x,y 2D空間
3D矢量 x,y,z 3D空間
4D矢量 x,y,z,w 3D空間w總是為1.用於方陣運算

首先定義3D矢量結構:

typedef struct VECTOR3D_TYP{

float x,y,z;

}VECTOR3D,*VECTOR3D_PTR;

下面是3D矢量(VECTOR)運算函式庫.

 

計算3D矢量長度,矢量長度也稱為範數(norm).將其理解為原點(0,0,0)到矢量(x,y,z)之距離

float Length_VECTOR3D(VECTOR3D_PTR va){

return( (float)sqrtf(va->xva->x + va->yva->y + va->z*va->z) );

}

 

3D矢量進行歸一化(normalize),也就使其長度縮放為1,但同時方向保持不變.它通常被用於無需理會長度之運算如『方向』

void Normalize_VECTOR3D(VECTOR3D_PTR va){

// 1.首先計算長度

float length = sqrtf(va->xva->x + va->yva->y + va->z*va->z);

//2.矢量除以長度得到歸一化矢量

va->x= va->x/length;

va->y= va->y/length;

va->z= va->z/length;

}

 

3D矢量點積運算可以理解為矢量乘法.先將各分量相乘後再相加得到一個標量

float operator%(VECTOR3D va, VECTOR3D vb){

return((va.x * vb.x) + (va.y * vb.y) + (va.z * vb.z));

}

float Dot_VECTOR3D(VECTOR3D_PTR va, VECTOR3D_PTR vb){

return( (va->x * vb->x) + (va->y * vb->y) + (va->z * vb->z) );

}

叉積是另一種矢量乘法,叉積運算最小要有3個分量才有效.

VECTOR3D operator^(VECTOR3D va, VECTOR3D vb){

VECTOR3D vn;

vn.x = ((va.y * vb.z) – (va.z * vb.y));

vn.y = -((va.x * vb.z) – (va.z * vb.x));

vn.z = ((va.x * vb.y) – (va.y * vb.x));

return(vn);

}

VECTOR3D Cross_VECTOR3D(VECTOR3D_PTR va, VECTOR3D_PTR vb){

VECTOR3D vn;

vn.x =  ( (va->y * vb->z) – (va->z * vb->y) );

vn.y = -( (va->x * vb->z) – (va->z * vb->x) );

vn.z =  ( (va->x * vb->y) – (va->y * vb->x) );

return(vn);

}

 

計算兩個3D矢量va和vb之間夾角余弦值

float CosTh_VECTOR3D(VECTOR3D_PTR va, VECTOR3D_PTR vb){

return(Dot_VECTOR3D(va,vb)/(Length_VECTOR3D(va)*Length_VECTOR3D(vb)));

}

 

 

計算三角形法線

void Normal_VECTOR3D(VECTOR3D_PTR normal,VECTOR3D_PTR va, VECTOR3D_PTR vb, VECTOR3D_PTR vc){

VECTOR3D u, v, n;

float length;

u = *vb – *va;

v = *vc – *va;

n = u^v;//Cross_VECTOR3D(&u, &v, &n);// 計算叉積

length = sqrtf(n.xn.x + n.yn.y + n.z*n.z);

normal->x = n.x/length;

normal->y = n.y/length;

normal->z = n.z/length;

}

 

將兩個3D矢量相加(va + vb),如用於位置移動

VECTOR3D operator+(VECTOR3D va, VECTOR3D vb){

VECTOR3D vsum;

vsum.x = va.x + vb.x;

vsum.y = va.y + vb.y;

vsum.z = va.z + vb.z;

return (vsum);//返回相加結果!

}

 

將兩個3D矢量相減(va – vb),如用於位置移動

VECTOR3D operator-(VECTOR3D va, VECTOR3D vb){

VECTOR3D vdiff;

vdiff.x = va.x – vb.x;

vdiff.y = va.y – vb.y;

vdiff.z = va.z – vb.z;

return(vdiff);     //返回相減向量!

}

 

3D矢量反數,如返轉方向

VECTOR3D operator-(VECTOR3D v){

VECTOR3D negation;

negation.x = -v.x ;

negation.y = -v.y ;

negation.z = -v.z ;

return(negation);     //返回反數向量!

}

 

使用縮放因子k對3D矢量進行縮放如:位置=位置+速度*時間

VECTOR3D operator*(VECTOR3D va, float k){

VECTOR3D vscaled;

vscaled.x = k * va.x;

vscaled.y = k * va.y;

vscaled.z = k * va.z;

return vscaled;// 返回縮放後向量

}

 

3D矢量賦值

void Init_VECTOR3D(VECTOR3D_PTR v, float x,float y,float z) {

v->x = x;  v->y = y; v->z = z;

}

 

3D矢量拷貝

Copy_VECTOR3D(VECTOR3D_PTR vdst, VECTOR3D_PTR vsrc){

vdst->x = vsrc->x;  vdst->y = vsrc->y; vdst->z = vsrc->z;

}

 

3D矢量比較

bool operator==(VECTOR3D vdst, VECTOR3D vsrc){

if (vdst.x == vsrc.x && vdst.y == vsrc.y && vdst.z == vsrc.z)

return true;

else

return false;

}

 

3D向量不等比較

bool operator!=(VECTOR3D vdst, VECTOR3D vsrc)

{

if (vdst.x != vsrc.x ||         vdst.y != vsrc.y ||vdst.z != vsrc.z)

return true;

else

return false;

}

 

向量歸零(3D向量)無方向,無距離,代表位於原點

void Zero_VECTOR3D(VECTOR3D_PTR v) {

v->x = v->y = v->z = 0.0f;

}

計算兩矢量之間夾角

float Angle_VECTOR3D(VECTOR3D_PTR va, VECTOR3D_PTR vb){

return acosf(*va % *vb);

}

角度轉弧度

#define DEG_TO_RAD(ang) ((ang)*PI/180.0)

弧度轉角度

#define RAD_TO_DEG(rads) ((rads)*180.0/PI)

隨機數 x:下限,  y:上限.

#define RAND_RANGE(x,y) ( (x) + (rand()%((y)-(x)+1)))

隨機數: -1.0 ~ 1.0

#define FRAND_RANGE1()   (((float)rand()-(float)rand())/RAND_MAX)

隨機數 0~1

#define FRAND_RANGE() ((float)rand() / (float)RAND_MAX)

遊戲建模之邊界盒

遊戲建模之邊界盒

邊界球』雖然可解卻大部3D模型『碰撞測試』問題.單若3D模型是長條形則不適合如『牆體』『長劍』.『軸對齊坐標邊界盒』axis-aligned bounding box(AABB)引入則可解決這類問題.每個『邊界盒』均由3D模型『中心點』與『最遠點』、『最近點』所組成.通過遍歷每個3D模型頂點找出XYZ三軸上最遠頂點.定義3D邊界盒:

typedef struct AABB_TYP {

VECTOR3D center;// 中心點

VECTOR3D far;// 最遠

VECTOR3D near;// 最近

}AABB, *AABB_PTR;

 

『3D模型』最遠點與最近點可遍歷所有3D模型頂點獲得:

1.最遠點與最近點清零

VECTOR3D far = {0,0,0};// 最遠點

VECTOR3D near = {0,0,0};// 最近點

2.遍歷所有3D頂點

for (int index = 0; index < vertex_num; ++index){

3.XYZ三軸最遠點

if (far.x > vertex_array[index].x)

vertex_array[index].x = far.x;

if (far.y > vertex_array[index].y)

vertex_array[index].y = far.y;

if (far.z > vertex_array[index].z)

vertex_array[index].z = far.z;

4.XYZ三軸最近點

if (near.x > vertex_array[index].x)

vertex_array[index].x = near.x;

if (near.y > vertex_array[index].y)

vertex_array[index].y = near.y;

if (near.z > vertex_array[index].z)

vertex_array[index].z = near.z;

}

 

判斷頂點是否為於邊界盒

bool Compute_Point_In_AABB(AABB_PTR aabb, VECTOR3D_PTR point)

{

if ((point->x >= aabb->center.x + aabb->near.x && point->x <= aabb->center.x + aabb->far.x) &&

(point->y >= aabb->center.y + aabb->near.y && point->y <= aabb->center.y + aabb->far.y) &&

(point->z >= aabb->center.z + aabb->near.z && point->z <= aabb->center.z + aabb->far.z) )

return true;

return false;

}

遊戲建模之邊界球

遊戲建模之邊界球

在3D遊戲中常對『3D模型』進行多邊形『碰撞檢測』.例如武器擊中『牆體』或『怪物』.最容易最常用是『邊界球』進『碰撞檢測』.每個『邊界球』均由3D模型『中心點』與『半徑』. 這『半徑』並不一定是最長半徑,通常這個值只包裹核心部分.定義3D球體:

typedef struct SPHERE3D_TYP{

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

float    radius;// 球體半徑

}SPHERE3D,* SPHERE3D_PTR;

 

『3D模型』最大半徑與平均平徑可遍歷所有頂點而取得:

1.模型半徑前設為零

radius_avg = 0;// 平均半徑

radius_max = 0;// 最大半徑

2.遍歷3D模型所有頂點

for (int index = 0; index < vertex_num; ++index)

{

3.計算3D頂點與中心距離

float dist = (float)sqrt(vertex_array[index].x*vertex_array[index].x +

vertex_array[index].y*vertex_array[index].y +

vertex_array[index].z *vertex_array[index].z);

4.累加半徑

radius_avg = radius_avg + dist;

5.求得最大半徑

if (dist > radius_max)

radius_max = dist;

}

6.計算平均半徑

radius_avg = radius_avg / vertex_num;

 

要對兩『邊界球』進行『碰撞檢測』只需求得兩『邊界球』之距,然後與兩『邊界球』半徑之和進行比較:

bool Compute_Sphere3D_In_Sphere3D(SPHERE3D_PTR sphereA, SPHERE3D_PTR sphereB)

{1.計算兩頂點XYZ分量距離

float x = sphereA->x – sphereB->x;

float y = sphereA->y – sphereB->y;

float z = sphereA->z – sphereB->z;

2.球體距離

float dist = sqrtf(x*x + y * y + z * z);

3.半徑之和進行比較

if (dist < (sphereA->radius + sphereB->radius))

return true;// 球體重疊/碰撞

else

return false;//

}

WAV音檔分釋與讀取

WAV音檔分釋與讀取

WAV音頻格式由Electronic Arts(電子協會)創建.它基於.IFF(Interchange File Format)對等交換文件格式.允許不同音檔格式通過鑲套技術進行編碼.

上兩編文章『DirectSound』與『DirectSound3D』均從WAV音檔中讀音頻數據.WAV音檔好再於結構簡單無需解壓. 我建議先把所有WAV音檔數據格式統一. 改為『單聲道Mono』(因為你只有一個咪頭)、採樣頻率11025Hz、採樣精度8bit.後再由遊戲引擎載入.

.WAV數據由以下三部份組成:

數據 簡序
RIFF .IFF標記
FORMAT 音頻格式
DATA 音頻數據

 

RIFF數據 所占空間(BYTE) 簡序
chunkID 4 塊ID,必須為’RIFF’
chunkSize 4 塊長度(不包含chunkID[4]和chunkSize所占空間)

 

FORMAT數據 所占空間(BYTE) 簡序
waveID 4 WAVE ID,必須為’WAVE’
chunkID 4 塊ID,必須為’fmt ‘
chunkSize 4 塊長度(不包含chunkID[4]和chunkSize所占空間)
wFormatTag 2 壓縮(格式)標誌默認WAVE_FORMAT_PCM脈衝編碼格式
wChannels 2 聲道:『單聲道Mono』或『雙聲道Stereo』
dwSamplesPerSec 4 採樣頻率(11025Hz,22050Hz,44100Hz)
dwAvgBytesPerSec 4 每秒播放字節數(SamplesPerSec * BlockAlign)
wBlockAlign 2 字節對齊,單聲道8bit占1byte.雙聲道16bit占4yte.
wBitsPerSample 2 每個採樣點位精度.有8bit、16bit、24bit、32bit
information 2 附加信息(未必有此數據)

 

數據塊 所占空間(BYTE) 簡序
chunkID 4 塊ID,必須為’data’
chunkSize 4 音頻數據長度
Data chunkSize 音頻數據

讀取WAV數據.wav指向文檔數據.size為文檔長度

bool Load_WAV(SOUND3D_PTR sound3D, PBYTE wav, int size){

1.數格塊

RIFF_PTR          riff;

WAVE_FORMAT_PTR   format;

WAVE_DATA_PTR     data;

2.讀取RIFF數據

riff = (RIFF_PTR)wav;

3.判斷是否RIFF

if (riff->id != WAVE_RIFF_ID)

return false;        // 返回出錯!

4.讀取WAVE_FORMAT_CHUNK

format = (WAVE_FORMAT_PTR)((PBYTE)wav + sizeof(RIFF));

if (format->waveID != WAVE_ID ||

format->chunkID != WAVE_FMT_ID ||

format->wFormatTag != WAVE_FORMAT_PCM)

return(false);   // 返回出錯!

5.讀取數據塊

data = (WAVE_DATA_PTR)((PBYTE)wav + sizeof(RIFF) + (int)format->chunkSize + sizeof(WAVE_CHUNK));

if (data->chunkID != WAVE_DATA_ID)

return(false);   // 返回出錯!

6.獲取音頻數據

PBYTE audio = (PBYTE)malloc(data->chunkSize);

memcpy(audio, &data->data, data->chunkSize);

return true;

}

FPS

FPS

FPS全稱為Frames Per Second.用於統計遊戲與影片每秒的渲染畫面(幀)次數.此值越高畫面越流暢,電影以每秒24格菲林進行播放.所以你的遊戲要流暢無停頓感.需要不低於24幀最好高於30幀.當然幀數越高越好.

FPS算法如下:

FPS = 100 * Frequency / (currentTime – startTime);

Frequency為時鐘頻率. currentTime與 startTime為前後兩次時鐘

 

Windows下你需要高精度計數器:

返回硬件級高精度時鐘頻率,若返回0代表系統不支持.

BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

返回硬件級高精度計數器,若返回0代表系統不支持.

BOOL QueryPerformanceCounter (LARGE_INTEGER *lpCount);

LARGE_INTEGER:為64BIT結構

 

此兩個函式需要winbase.h頭文檔和Kernel32.LIB庫

#include <winbase.h>

#pragma comment(lib, “Kernel32.LIB”)

 

定義如下FPS結構:

typedef struct FPS_TYP {

LARGE_INTEGER  Frequency;// 計數器的頻率

LARGE_INTEGER  startTime;// 啟動時鐘

float Frames;// 每秒渲染幀數

int n;// 臨時幀計數器

}FPS,*FPS_PTR;

 

初此化高精度定時器

bool Init_FPS(FPS_PTR fps)

{

// 返回硬件支持的高精度計數器的頻率

if (QueryPerformanceFrequency(&fps->Frequency) == false)

return false;

// 獲取啟動時鐘

QueryPerformanceCounter(&fps->startTime);//

return true;

}

 

計算每秒渲染幀數,每100幀進行一次計算

float Get_FPS(FPS_PTR fps)

{

++fps->n;

if (fps->n > 100)

{

LARGE_INTEGER currentTime;

// 返回高精度計數器

QueryPerformanceCounter(&currentTime);

fps->Frames = (float)100 * (float)fps->Frequency.QuadPart / ((float)currentTime.QuadPart – (float)fps->startTime.QuadPart);

fps->startTime = currentTime;// 重置時間

fps->n = 0;

}

return fps->Frames;

}

 

计算两次测量所花费时间

float Get_Counter_FPS(FPS_PTR fps){

LARGE_INTEGER currentTime;//当前时钟

// 返回高精度计数器

QueryPerformanceCounter(&currentTime);

float seconds = ((float)currentTime.QuadPart – (float)fps->startTime.QuadPart) / (float)fps->Frequency.QuadPart;

fps->startTime = currentTime;

return seconds;

}

 

Windows之Microsoft屏幕放大鏡

Windows之Microsoft屏幕放大鏡

Windows其中一個最好用的工具是『Microsoft屏幕放大鏡』,通過win鍵與+鍵啟動.如果你有『Microsoft鼠標』可以通過安裝『IntelliPoint8.2』激活母指鍵啟動『Microsoft屏幕放大鏡』.安裝後要重啟電腦. 通過『檔案總管\控制台\所有控制台項目\滑鼠』設定『母指鍵』.在『全屏幕』下按『母指鍵』+『鼠標滑輪』用於梯相最好用.

快捷鍵 簡介
Win鍵與+鍵 方大/啟動放大鏡
Win鍵與-鍵 縮小
Win鍵與ESC鍵 關閉放大鏡
鼠標前母指鍵 啟動放大鏡/關閉放大鏡
鼠標前母指鍵+鼠標滑輪 方大/縮小(這個最好用)
CTRL+ALT+F 全屏幕
CTRL+ALT+L 透鏡
CTRL+ALT+D 以連接擴充座(分屏)
CTRL+ALT+SPACE 預覽全屏幕
CTRL+ALT+I 反色

 

Microsoft 無線霸雷鯊7000鼠標修復

Microsoft 無線霸雷鯊7000鼠標修復

鼠標輕觸開關是最容易損耗的,當鼠標出現連擊時,鼠標要準備退役,即使是最貴的鼠標使用壽命也相差唔多,就算鼠標有五年保養也不會幫你更換輕觸開關,唔信你可以試下拿它返廠.

如果你很喜歡你的滑鼠可以通過更換滑鼠的輕觸開關(如上圖),延長滑鼠使用壽命.因位兩層上錫要將它熔焊有D難度.因為『霸雷鯊7000』只有兩隻腳所以無分正負,貼緊上錫即可.

如果『霸雷鯊7000』出現斷幀可以償試拔掉其它USB設備.

 

Visual Studio 2017新增C專案

Visual Studio 2017新增C專案
Visual Studio 2017新增C專案

近日終於遠離最愛的VC6安裝VC2017,新增專案時居然無發現C/C++的選項,暈難道C已被拋棄?經一番鑽然才悟個中方法

  1. 運行Visual Studio 2017
  2. 『檔案/新增/專案』打開
  3. 『新增檔案/Visual C++/空白專案』
  4. 若無梯見請點按『開啟Visual Studio安裝程式』把與C++有關全部安裝
  5. 『名稱填』這裡填『OpenGL』
  6. 『位置填』這裡填『D:\C\』
  7. 取消勾選『為方案建目錄』單級目錄結構與VC6相若
  8. 按『確認』製作專案
  9. 右鍵點擊『OpenGL』打開屬性頁
  10. 打開『屬性頁/組態屬性/一般/字元集選則『使用Unicode字元集』.若選『使用多位元組字元集』則使用ANSI
  11. 打開『屬性頁/組態屬性/連接器/系統/子系統選則『Windows(/SUBSYSTEM:WINDOWS)』圖形界面。若選『主控台(/SUBSYSTEM:CONSOLE)』則為命令行界面
  12. 右鍵點擊『OpenGL』點擊『加入/新的篩選條件』填main
  13. 右鍵點擊『main』點擊『加入/新的篩選條件』
  14. 『名稱』填『main.c』副檔名為.c則使用C編譯器, 副檔名為.cpp則使用C++編譯器