OpenGL案例繪制正方形并移動(dòng)

繪制各個(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)化方便好多流程乖篷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市透且,隨后出現(xiàn)的幾起案子撕蔼,更是在濱河造成了極大的恐慌,老刑警劉巖石蔗,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罕邀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡养距,警方通過(guò)查閱死者的電腦和手機(jī)诉探,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)棍厌,“玉大人肾胯,你說(shuō)我怎么就攤上這事≡派矗” “怎么了敬肚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)束析。 經(jīng)常有香客問(wèn)我艳馒,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任弄慰,我火速辦了婚禮第美,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘陆爽。我一直安慰自己什往,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布慌闭。 她就那樣靜靜地躺著别威,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驴剔。 梳的紋絲不亂的頭發(fā)上省古,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音丧失,去河邊找鬼衫樊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛利花,可吹牛的內(nèi)容都是我干的科侈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼炒事,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼臀栈!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起挠乳,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤权薯,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后睡扬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體盟蚣,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年卖怜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屎开。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡马靠,死狀恐怖奄抽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情甩鳄,我是刑警寧澤逞度,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站妙啃,受9級(jí)特大地震影響档泽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一馆匿、第九天 我趴在偏房一處隱蔽的房頂上張望品抽。 院中可真熱鬧,春花似錦甜熔、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至羽历,卻和暖如春焊虏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背秕磷。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工诵闭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人澎嚣。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓疏尿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親易桃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子褥琐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356