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

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

效果圖如下所示:


02、正方形鍵位控制.gif

整體的流程圖如下


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

主要需要實現(xiàn)以下兩部分:

  • 繪制正方形
  • 特殊鍵位移動函數(shù)

繪制正方形

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

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

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

鍵位控制效果

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

該效果的實現(xiàn)有兩種方式

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

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

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

坐標更新方式

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

三個自定義函數(shù)的流程圖如下:


坐標更新-自定義函數(shù)實現(xiàn)流程

ChangeSize和RenderScene就不做解釋了,在繪制時,這部分已經(jīng)完成了,主要說說SpecialKeys函數(shù)

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


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


    坐標更新-邊緣碰撞計算

具體的代碼實現(xiàn)如下:

//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);
    
    //根據(jù)移動方向,更新相對坐標
    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);
    
    //重新計算正方形的位置
    //一個頂點有三個數(shù) 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]);
    
    //更新頂點數(shù)據(jù)
    triangleBatch.CopyVertexData3f(vVerts);
    
    //重新渲染提交 --> RenderScene
    glutPostRedisplay();
    
}

矩陣方式

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

涉及兩個函數(shù):RenderScene、SpecialKeys

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


矩陣-自定義函數(shù)

SpecialKeys 函數(shù)

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

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


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

具體實現(xiàn)如下:

//使用矩陣方式(一起搞定),不需要修改每個頂點,只需要記錄移動步長,碰撞檢測
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 函數(shù)
主要步驟如下:

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

具體的代碼實現(xiàn)如下

//開始渲染
void RenderScene(void)

{
    //1.清除一個或者一組特定的緩存區(qū)
    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);
    
    //當單元著色器不夠用時,使用平面著色器
    //參數(shù)1:存儲著色器類型
    //參數(shù)2:使用什么矩陣變換
    //參數(shù)3:顏色
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransformMatrix, vRed);
    
    //提交著色器
    triangleBatch.Draw();
    glutSwapBuffers();
}

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

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

友情鏈接更多精彩內容