OpenGL案例-繪制一個正方形并用鍵盤控制移動

一、案例及相關(guān)函數(shù)說明

使用OpenGL繪制一個正方形,并且利用鍵盤的上下左右鍵控制正方形的上下左右移動。效果如下:


效果.gif

本次案例需要的幾個函數(shù):

  • int main(int argc,char *argv[]) main函數(shù)
    類似于我們開發(fā)中的main函數(shù),是APP程序的入口,在OPenGL中是程序??。
    OpenGL 是?向過程編程.所以你會發(fā)現(xiàn)利用OpenGL處理圖形/圖像都是鏈?zhǔn)叫问?
    以及基于OpenGL封裝的圖像處理理框架也是鏈?zhǔn)骄幊獭?/li>
  • void changeSize(int w ,int h):changeSize 函數(shù):
    自定義函數(shù),通過glutReshaperFunc(函數(shù)名)注冊為重塑函數(shù).當(dāng)屏幕大小發(fā)生變化/或者第?次創(chuàng)建窗口時,會調(diào)用該函數(shù)調(diào)整窗口?小/視?口?小。
  • void RenderScene(void) RenderScene函數(shù)
    ?定義函數(shù),通過glutDisplayFunc(函數(shù)名)注冊為顯示渲染函數(shù).當(dāng)屏幕發(fā)生變化/或者開發(fā)者主動渲染會調(diào)?此函數(shù),用來實現(xiàn)數(shù)據(jù)->渲染過程。
  • void setupRC(void) setupRC函數(shù)
    自定義函數(shù),設(shè)置你需要渲染的圖形的相關(guān)頂點數(shù)據(jù)/顏?色數(shù)據(jù)等數(shù)據(jù)準(zhǔn)備工作,可以理解為初始化配置函數(shù)。
  • void SpecialKeys(int key, int x, int y) SpecialKey函數(shù)
    自定義函數(shù),接收到鍵盤上下左右按鍵的響應(yīng),根據(jù)按鍵進行計算并且觸發(fā)重繪API。

接下來看下整個案例的流程圖:


流程圖.png

二、上代碼

main()函數(shù):

程序啟動的入口,在這里主要是做程序的準(zhǔn)備工作:

  1. 初始化OpenGL,設(shè)置當(dāng)前工作目錄,初始化GLUT庫等;
  2. 設(shè)置窗口大小和標(biāo)題顯示相關(guān)的內(nèi)容
  3. 注冊各種監(jiān)聽回調(diào)函數(shù)(本案例中主要是以下幾種:changeSize窗口大小發(fā)生改變的回調(diào);RenderScene繪制/重繪回調(diào);SpecialKeys鍵盤特殊鍵位點擊后的的回調(diào))
  4. 調(diào)用setupRC(),開啟glutMainLoop(類似iOS中的RunLoop)。
int main(int argc,char *argv[])
{
    //設(shè)置當(dāng)前工作目錄,針對MAC OS X
    gltSetWorkingDirectory(argv[0]);
    //初始化GLUT庫,這個函數(shù)只是傳說命令參數(shù)并且初始化glut庫
    glutInit(&argc, argv);  glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    
    //GLUT窗口大小、窗口標(biāo)題
    glutInitWindowSize(800, 600);
    glutCreateWindow("Triangle");
    //注冊重塑函數(shù),當(dāng)窗口大小發(fā)生改變時,會觸發(fā)changeSize()回調(diào)
    glutReshapeFunc(changeSize);
    //注冊顯示函數(shù);當(dāng)changeSize觸發(fā)時,或者glutPostRedisplay()會觸發(fā)
    //RenderScene()回調(diào)
    glutDisplayFunc(RenderScene);
    //注冊特殊函數(shù)(鍵盤按鍵點擊監(jiān)聽),當(dāng)點擊鍵盤時觸發(fā);
    glutSpecialFunc(SpecialKeys);
    GLenum status = glewInit();
    if (GLEW_OK != status) {
        printf("GLEW Error:%s\n",glewGetErrorString(status));
        return 1;
    }
    //設(shè)置我們的渲染環(huán)境
    setupRC();
    glutMainLoop();
    return  0;
}

setupRC()函數(shù):

setupRC主要做了一些初始化操作,可以理解為iOS中在初始化UIView時進行的UI開發(fā)配置

  1. 設(shè)置窗口背景顏?色
  2. 初始化存儲著?色器shaderManager
  3. 設(shè)置圖形頂點數(shù)據(jù)
  4. 利用GLBatch三?形批次類,將數(shù)據(jù)傳遞到著色器器
    setupRC只能在main函數(shù)中調(diào)用手動觸發(fā)。
void setupRC()
{
    //設(shè)置清屏顏色(背景顏色)
    glClearColor(0.98f, 0.40f, 0.7f, 1);
    //初始化著色管理器
    shaderManager.InitializeStockShaders();
    //修改為GL_TRIANGLE_FAN ,4個頂點
    //其實就是在以某種方式構(gòu)造數(shù)據(jù),后面的渲染會用到這些數(shù)據(jù)
    //這里用到了GLBatch批次類,是一個容器類
    //裝什么樣的數(shù)據(jù)
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
    //數(shù)據(jù)是什么
    triangleBatch.CopyVertexData3f(vVerts);
    //裝完了
    triangleBatch.End();
}

changeSize()函數(shù):

changeSize中主要做兩件事:

  1. 設(shè)置OpenGL 視?
  2. 設(shè)置OpenGL 投影?式等.
    changeSize觸發(fā)方式主要有兩種:手動觸發(fā)(新建窗?)和回調(diào)觸發(fā)(改變視口位置大小后)。
void changeSize(int w ,int h) {
/*
     x,y 參數(shù)代表窗口中視圖的左下角坐標(biāo),而寬度、高度是像素為表示,通常x,y 都是為0
    */
   glViewport(0, 0, w, h);
}

RenderScene()函數(shù):

RenderScene主要處理的就是屏幕上具體呈現(xiàn)的內(nèi)容:

  1. 清理理緩存區(qū)(顏?色,深度,模板緩存區(qū)等)
  2. 使?用存儲著?色器器
  3. 繪制圖形.

可以理解為UIView下的drawInRect:
RenderScene觸發(fā)方式主要有兩種:系統(tǒng)自動觸發(fā)(changeSize調(diào)用后)和回調(diào)觸發(fā)(調(diào)用glutPostRedisplay重繪)。

void RenderScene(void)
{
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    //設(shè)置一個顏色{R,G,B,A}
    GLfloat vRed[] = {1.0f,0.0f,0.0f,0.0f};
    //4x4矩陣
    M3DMatrix44f mTransfromMatrix;
    //平移
    m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0f);
    //將矩陣結(jié)果 提交給固定著色器(平面著色器)中繪制
 shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransfromMatrix,vRed);
    triangleBatch.Draw();

    //執(zhí)行交換緩存區(qū) (因為是雙緩存區(qū))
    glutSwapBuffers();
}

值得注意的是,這里我們移動視圖的時候是通過矩陣來實現(xiàn)的,除此之外我們還有分點單獨計算,但是那樣在頂點數(shù)據(jù)很多的情況下效率是極其低的。所以合理運用矩陣對我們使用OpenGL起到非常重要的作用。

SpecialKeys()函數(shù):

SpecialKeys是我們在main()中添加的對鍵盤按鈕點擊后的監(jiān)聽回調(diào),該回調(diào)會返回一個int類型的key,我們根據(jù)曾這個key可以判斷我們點擊了鍵盤上的哪個鍵,進而實現(xiàn)后面的計算。這個方法是按鍵控制屏幕上視圖移動的效果的核心方法,所以這里主要捕獲上,下,左,右鍵,并做一些數(shù)據(jù)處理。

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;
    }
    //碰撞檢測
    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;
    }
    //這是觸發(fā)重繪的一個API,類似于調(diào)用setNeedsDisplay()
    glutPostRedisplay();
}

代碼中的碰撞檢測實際是顯示邊界問題,防止我們在移動過程中正方形視圖移出了我們的顯示視圖區(qū)域。

覺得不錯記得點贊哦!聽說看完點贊的人逢考必過,逢獎必中。?( ′???` )比心

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容