案例 02、OpenGL入門--正方形鍵位控制

OpenGL + OpenGL ES +Metal 系列文章匯總

效果圖如下所示:


02、正方形鍵位控制.gif

整體的流程圖如下


正方形鍵位控制整體流程圖

主要需要實現以下兩部分:

  • 繪制正方形
  • 特殊鍵位移動函數

繪制正方形

在之前的三角形繪制中,我們已經了解了圖形繪制的一個基本流程,那么正方形的繪制就是水到渠成的,只需要在三角形代碼的基礎上做以下修改:

  • 定義頂點到原心距離,即 正方形邊長 = blockSize * 2
GLfloat blockSize = 0.1f;
  • 修改頂點數組
//正方形四個點的坐標
GLfloat vVerts[] = {
    -blockSize, -blockSize, 0.0f,
    blockSize, -blockSize, 0.0f,
    blockSize, blockSize, 0.0f,
    -blockSize, blockSize, 0.0f,
};
  • 修改setupRC函數中圖元的連接方式
//將 GL_TRIANGLES 修改為 GL_TRIANGLE_FAN ,4個頂點
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);

到此,正方形就繪制完成了,接下來我們需要完成正方形鍵位控制效果

鍵位控制效果

主要是指正方形根據選擇鍵盤的上下左右鍵移動。

該效果的實現有兩種方式

  • 坐標更新方式
  • 矩陣方式

打個比方,有100件需要染同一種顏色的衣服,你可以選擇一件一件的染色,也可以選擇同時將100件放入染缸,一起染色,

  • 其中一件一件染色指代的就是坐標更新方式,適用于頂點較少的圖形,
  • 同時放入染色指代的就是矩陣方式,當圖形頂點非常多的,再用坐標更新就不合適了,需要使用矩陣來同時更新。

坐標更新方式

頂點根據相對頂點逐個更新頂點坐標,在SpecialKeys函數中完成鍵位移動時坐標的更新,并手動調用渲染。

三個自定義函數的流程圖如下:


坐標更新-自定義函數實現流程

ChangeSize和RenderScene就不做解釋了,在繪制時,這部分已經完成了,主要說說SpecialKeys函數

  • 首先需要定義一個步長
  • 定義一個相對頂點的x和y值
    假設正方形如下圖所示,以D為相對頂點


    正方形.png
  • 根據鍵位方向,分別更新x 和 y
  • 邊緣碰撞處理
    如果沒有這個步驟,圖形移動到邊緣時,就會移動到屏幕不可見的區域,下圖可以說明4個方向對邊緣碰撞處理是如何計算的,這里就不做詳細說明了


    坐標更新-邊緣碰撞計算

具體的代碼實現如下:

//key 枚舉值,x、y是位置
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個邊界)的處理
    
    //當正方形移動超過最左邊的時候
    if (blockX < -1.0f) {
        blockX = -1.0f;
    }
    //當正方形移動到最右邊時
    //1.0 - blockSize * 2 = 總邊長 - 正方形的邊長 = 最左邊點的位置
    if (blockX > (1.0f - blockSize * 2)) {
        blockX = 1.0f - blockSize * 2;
    }
    //當正方形移動到最下面時
    //-1.0 - blockSize * 2 = Y(負軸邊界) - 正方形邊長 = 最下面點的位置
    if (blockY < -1.0f + blockSize * 2) {
        blockY = -1.0f + blockSize * 2;
    }
    //當正方形移動到最上面時
    if (blockY > 1.0f) {
        blockY = 1.0f;
    }
    
    printf("blockX = %f\n",blockX);
    printf("blockY = %f\n",blockY);
    
    //重新計算正方形的位置
    //一個頂點有三個數 x、y、z
    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);
    
    //重新渲染提交 --> RenderScene
    glutPostRedisplay();
    
}

矩陣方式

主要是根據x軸、y軸移動的距離,生成一個平移矩陣,通過圖形*平移矩陣 = 移動后的圖形,得到最終效果

涉及兩個函數:RenderScene、SpecialKeys

矩陣方式中自定義函數的流程如下:


矩陣-自定義函數

SpecialKeys 函數

  • 定義步長及兩個全局變量(相對于x軸和y軸的平移距離)
//記錄移動圖形時,在x軸上平移的距離
GLfloat xPos = 0.0f;
//記錄移動圖形時,在y軸上平移的距離
GLfloat yPos = 0.0f;

GLfloat stepSize = 0.025f;
  • 根據移動方向,計算移動距離
  • 邊緣碰撞處理
    其移動距離計算的理解如圖所示
    ==> 可以將初始化的平移距離理解為正方形的中心,即原點,在圖形移動時,其中心點也發生了移動,所以我們要計算的邊緣的移動距離就是兩個中心店之間的平移距離


    矩陣-邊緣碰撞處理邏輯
  • 手動觸發重新渲染

具體實現如下:

//使用矩陣方式(一起搞定),不需要修改每個頂點,只需要記錄移動步長,碰撞檢測
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;
    }
    
    //碰撞檢測 xPos是平移距離,即移動量
    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();
    
}

RenderScene 函數
主要步驟如下:

  • 清理特定緩存區
  • 根據平移距離計算平移矩陣
  • 將矩陣結果交給存儲著色器(平面著色器)中繪制
    在位置更新方式中,使用的是單元著色器,而矩陣方式中,涉及的矩陣是4*4的,單元著色器不夠用,所以使用平面著色器

具體的代碼實現如下

//開始渲染
void RenderScene(void)

{
    //1.清除一個或者一組特定的緩存區
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    //1.設置顏色RGBA
    GLfloat vRed[] = {1.0f, 0.5f, 0.0f, 1.0f};
    
    
    //定義矩陣
    M3DMatrix44f mTransformMatrix;
    
    //平移矩陣
    m3dTranslationMatrix44(mTransformMatrix, xPos, yPos, 0.0f);
    
    //當單元著色器不夠用時,使用平面著色器
    //參數1:存儲著色器類型
    //參數2:使用什么矩陣變換
    //參數3:顏色
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransformMatrix, vRed);
    
    //提交著色器
    triangleBatch.Draw();
    glutSwapBuffers();
}

完整代碼見Github -02_正方形鍵位控制

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372