繪制各個(gè)方法的執(zhí)行順序和各自的業(yè)務(wù)掂器。
main函數(shù)
int main(int argc,char *argv[])
{
//設(shè)置當(dāng)前工作目錄摊欠,針對(duì)MAC OS X
/*
`GLTools`函數(shù)`glSetWorkingDrectory`用來(lái)設(shè)置當(dāng)前工作目錄丢烘。實(shí)際上在Windows中是不必要的,因?yàn)楣ぷ髂夸浤J(rèn)就是與程序可執(zhí)行執(zhí)行程序相同的目錄些椒。但是在Mac OS X中播瞳,這個(gè)程序?qū)?dāng)前工作文件夾改為應(yīng)用程序捆綁包中的`/Resource`文件夾。`GLUT`的優(yōu)先設(shè)定自動(dòng)進(jìn)行了這個(gè)中設(shè)置免糕,但是這樣中方法更加安全赢乓。
*/
gltSetWorkingDirectory(argv[0]);
//初始化GLUT庫(kù),這個(gè)函數(shù)只是傳說(shuō)命令參數(shù)并且初始化glut庫(kù)
glutInit(&argc, argv);
/*
初始化雙緩沖窗口,其中標(biāo)志GLUT_DOUBLE石窑、GLUT_RGBA牌芋、GLUT_DEPTH、GLUT_STENCIL分別指
雙緩沖窗口松逊、RGBA顏色模式躺屁、深度測(cè)試、模板緩沖區(qū)
--GLUT_DOUBLE`:雙緩存窗口经宏,是指繪圖命令實(shí)際上是離屏緩存區(qū)執(zhí)行的犀暑,然后迅速轉(zhuǎn)換成窗口視圖驯击,這種方式,經(jīng)常用來(lái)生成動(dòng)畫(huà)效果耐亏;
--GLUT_DEPTH`:標(biāo)志將一個(gè)深度緩存區(qū)分配為顯示的一部分徊都,因此我們能夠執(zhí)行深度測(cè)試;
--GLUT_STENCIL`:確保我們也會(huì)有一個(gè)可用的模板緩存區(qū)苹熏。
深度碟贾、模板測(cè)試后面會(huì)細(xì)致講到
*/
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//GLUT窗口大小、窗口標(biāo)題
glutInitWindowSize(800, 600);
glutCreateWindow("Triangle");
/*
GLUT 內(nèi)部運(yùn)行一個(gè)本地消息循環(huán)轨域,攔截適當(dāng)?shù)南⒏さⅰH缓笳{(diào)用我們不同時(shí)間注冊(cè)的回調(diào)函數(shù)。我們一共注冊(cè)2個(gè)回調(diào)函數(shù):
1)為窗口改變大小而設(shè)置的一個(gè)回調(diào)函數(shù)
2)包含OpenGL 渲染的回調(diào)函數(shù)
*/
//注冊(cè)重塑函數(shù)
glutReshapeFunc(changeSize);
//注冊(cè)顯示函數(shù)
glutDisplayFunc(RenderScene);
//注冊(cè)特殊函數(shù)
glutSpecialFunc(SpecialKeys);
/*
初始化一個(gè)GLEW庫(kù),確保OpenGL API對(duì)程序完全可用干发。
在試圖做任何渲染之前朱巨,要檢查確定驅(qū)動(dòng)程序的初始化過(guò)程中沒(méi)有任何問(wèn)題
*/
GLenum status = glewInit();
if (GLEW_OK != status) {
printf("GLEW Error:%s\n",glewGetErrorString(status));
return 1;
}
//設(shè)置我們的渲染環(huán)境
setupRC();
glutMainLoop();
return 0;
}
main函數(shù)做了一系列初始化的工作
初始化GLUT庫(kù)
初始化雙緩沖窗口、RGBA顏色模式枉长、深度測(cè)試冀续、模版緩沖區(qū)
設(shè)置窗口大小,窗口標(biāo)題
注冊(cè)回調(diào)函數(shù)
1.glutReshapeFunc()
2.glutDisplayFunc()
手動(dòng)調(diào)用SetupRC()
setRC()函數(shù)
//為程序作一次性的設(shè)置
void SetupRC()
{
//設(shè)置背影顏色
glClearColor(0.3f,0.4f,0.5f,1.0f);
//初始化著色管理器
shaderManager.InitializeStockShaders();
//批次處理
triangleBatch.Begin(GL_TRIANGLES,3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
這個(gè)函數(shù)只執(zhí)行一次必峰,在main函數(shù)中手動(dòng)觸發(fā)
設(shè)置窗口背景顏色
初始化著色管理器
利用GLBatch 三角形批次類(lèi)將數(shù)據(jù)傳遞到著色器
ChangeSize函數(shù)
/*
在窗口大小改變時(shí)洪唐,接收新的寬度&高度。
*/
void changeSize(int w,int h)
{
/*
x,y 參數(shù)代表窗口中視圖的左下角坐標(biāo)吼蚁,而寬度凭需、高度是像素為表示,通常x,y 都是為0
*/
glViewport(0, 0, w, h);
}
ChangeSize在main函數(shù)中注冊(cè)肝匆,自動(dòng)觸發(fā)粒蜈,觸發(fā)條件是
第一次創(chuàng)建窗口
窗口尺寸發(fā)生改變
處理的業(yè)務(wù)
設(shè)置OpenGL視口
設(shè)置OpenGL投影方式等
RenderScene函數(shù)
void RenderScene(void)
{
//1.清除一個(gè)或者一組特定的緩存區(qū)
/*
緩沖區(qū)是一塊存在圖像信息的儲(chǔ)存空間,紅色旗国、綠色枯怖、藍(lán)色和alpha分量通常一起分量通常一起作為顏色緩存區(qū)或像素緩存區(qū)引用。
OpenGL 中不止一種緩沖區(qū)(顏色緩存區(qū)能曾、深度緩存區(qū)和模板緩存區(qū))
清除緩存區(qū)對(duì)數(shù)值進(jìn)行預(yù)置
參數(shù):指定將要清除的緩存的
GL_COLOR_BUFFER_BIT :指示當(dāng)前激活的用來(lái)進(jìn)行顏色寫(xiě)入緩沖區(qū)
GL_DEPTH_BUFFER_BIT :指示深度緩存區(qū)
GL_STENCIL_BUFFER_BIT:指示模板緩沖區(qū)
*/
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//2.設(shè)置一組浮點(diǎn)數(shù)來(lái)表示紅色
GLfloat vRed[] = {1.0,0.0,0.0,1.0f};
//傳遞到存儲(chǔ)著色器度硝,即GLT_SHADER_IDENTITY著色器,這個(gè)著色器只是使用指定顏色以默認(rèn)笛卡爾坐標(biāo)第在屏幕上渲染幾何圖形
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
//提交著色器
triangleBatch.Draw();
//在開(kāi)始的設(shè)置openGL 窗口的時(shí)候寿冕,我們指定要一個(gè)雙緩沖區(qū)的渲染環(huán)境蕊程。這就意味著將在后臺(tái)緩沖區(qū)進(jìn)行渲染,渲染結(jié)束后交換給前臺(tái)蚂斤。這種方式可以防止觀(guān)察者看到可能伴隨著動(dòng)畫(huà)幀與動(dòng)畫(huà)幀之間的閃爍的渲染過(guò)程存捺。緩沖區(qū)交換平臺(tái)將以平臺(tái)特定的方式進(jìn)行槐沼。
//將后臺(tái)緩沖區(qū)進(jìn)行渲染曙蒸,然后結(jié)束后交換給前臺(tái)
glutSwapBuffers();
}
RenderScene在main函數(shù)中注冊(cè)
自動(dòng)觸發(fā)
開(kāi)發(fā)者手動(dòng)調(diào)用 glutPostRedisplay();
處理的業(yè)務(wù)
清理緩存區(qū)(顏色捌治,深度,模板緩存區(qū)等)
使用存儲(chǔ)著色器繪制圖形
因此繪制正方形只要改變頂點(diǎn)數(shù)組和傳遞數(shù)據(jù)的GLBatch即可纽窟。
定義圖形頂點(diǎn)到坐標(biāo)軸的距離為blockSize,則四個(gè)頂點(diǎn)的坐標(biāo)為
GLfloat blockSize = 0.1f;
GLfloat vVerts[] = {
-blockSize,blockSize,0.0f,
blockSize,blockSize,0.0f,
blockSize,-blockSize,0.0f,
-blockSize,-blockSize,0.0f,
};
將GLBatch的設(shè)置函數(shù)修改為
triangleBatch.Begin(GL_TRIANGLE_FAN,4);
如果我們想要通過(guò)鍵盤(pán)方向鍵控制方塊的移動(dòng)肖油,我們就需要注冊(cè)監(jiān)聽(tīng)特殊按鍵點(diǎn)擊的方法
glutSpecialFunc(SpecialKeys);
然后在該方法中實(shí)現(xiàn)計(jì)算移動(dòng)后的各點(diǎn)位的坐標(biāo)值;
void SpecialKeys(int key, int x, int y){
GLfloat stepSize = 0.025f;
GLfloat blockX = vVerts[0];
GLfloat blockY = vVerts[10];
printf("v[0] = %f\n",blockX);
printf("v[10] = %f\n",blockY);
if (key == GLUT_KEY_UP) {
blockY += stepSize;
}
if (key == GLUT_KEY_DOWN) {
blockY -= stepSize;
}
if (key == GLUT_KEY_LEFT) {
blockX -= stepSize;
}
if (key == GLUT_KEY_RIGHT) {
blockX += stepSize;
}
//觸碰到邊界(4個(gè)邊界)的處理
//當(dāng)正方形移動(dòng)超過(guò)最左邊的時(shí)候
if (blockX < -1.0f) {
blockX = -1.0f;
}
//當(dāng)正方形移動(dòng)到最右邊時(shí)
//1.0 - blockSize * 2 = 總邊長(zhǎng) - 正方形的邊長(zhǎng) = 最左邊點(diǎn)的位置
if (blockX > (1.0 - blockSize * 2)) {
blockX = 1.0f - blockSize * 2;
}
//當(dāng)正方形移動(dòng)到最下面時(shí)
//-1.0 - blockSize * 2 = Y(負(fù)軸邊界) - 正方形邊長(zhǎng) = 最下面點(diǎn)的位置
if (blockY < -1.0f + blockSize * 2 ) {
blockY = -1.0f + blockSize * 2;
}
//當(dāng)正方形移動(dòng)到最上面時(shí)
if (blockY > 1.0f) {
blockY = 1.0f;
}
printf("blockX = %f\n",blockX);
printf("blockY = %f\n",blockY);
// Recalculate vertex positions
vVerts[0] = blockX;
vVerts[1] = blockY - blockSize*2;
printf("(%f,%f)\n",vVerts[0],vVerts[1]);
vVerts[3] = blockX + blockSize*2;
vVerts[4] = blockY - blockSize*2;
printf("(%f,%f)\n",vVerts[3],vVerts[4]);
vVerts[6] = blockX + blockSize*2;
vVerts[7] = blockY;
printf("(%f,%f)\n",vVerts[6],vVerts[7]);
vVerts[9] = blockX;
vVerts[10] = blockY;
printf("(%f,%f)\n",vVerts[9],vVerts[10]);
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
在代碼中我們加入了移動(dòng)到邊界的判斷臂港,最后我們調(diào)用批次類(lèi)將數(shù)據(jù)傳遞給著色器triangleBatch.CopyVertexData3f(vVerts);并調(diào)用函數(shù)重新渲染 glutPostRedisplay()森枪。
每一次移動(dòng)過(guò)程中,都需要手動(dòng)計(jì)算每個(gè)頂點(diǎn)的坐標(biāo)很是繁瑣审孽,可以直接通過(guò)平移矩陣來(lái)實(shí)現(xiàn)县袱。只需要在RenderScene添加以下代碼
M3DMatrix44f mFinalTransform,mTransfromMatrix,mRotationMartix;
//平移
m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0f);
//每次平移時(shí),旋轉(zhuǎn)5度
static float yRot = 0.0f;
yRot += 5.0f;
m3dRotationMatrix44(mRotationMartix, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);
//將旋轉(zhuǎn)和移動(dòng)的矩陣結(jié)果 合并到mFinalTransform (矩陣相乘)
m3dMatrixMultiply44(mFinalTransform, mTransfromMatrix, mRotationMartix);
//將矩陣結(jié)果 提交給固定著色器(平面著色器)中繪制
shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinalTransform,vRed);
在這里我們聲明了三個(gè)矩陣佑力,平移矩陣式散、旋轉(zhuǎn)矩陣和最終的矩陣,我們只需把相應(yīng)的參數(shù)傳進(jìn)去打颤,最后合并到最終矩陣暴拄,然后提交給固定著色器,最后void SpecialKeys(int key, int x, int y)方法就可以寫(xiě)成
void SpecialKeys(int key, int x, int y){
GLfloat stepSize = 0.025f;
if (key == GLUT_KEY_UP) {
yPos += stepSize;
}
if (key == GLUT_KEY_DOWN) {
yPos -= stepSize;
}
if (key == GLUT_KEY_LEFT) {
xPos -= stepSize;
}
if (key == GLUT_KEY_RIGHT) {
xPos += stepSize;
}
//碰撞檢測(cè)
if (xPos < (-1.0f + blockSize)) {
xPos = -1.0f + blockSize;
}
if (xPos > (1.0f - blockSize)) {
xPos = 1.0f - blockSize;
}
if (yPos < (-1.0f + blockSize)) {
yPos = -1.0f + blockSize;
}
if (yPos > (1.0f - blockSize)) {
yPos = 1.0f - blockSize;
}
glutPostRedisplay();
}
由此可以看出使用矩陣運(yùn)算编饺,可以簡(jiǎn)化方便好多流程乖篷。