OpenGL入門之 正方形鍵位控制

目標(biāo)

這篇文章要實現(xiàn)的效果主要是朴上,先畫出一個正方形,然后通過監(jiān)聽特殊鍵位函數(shù)懂鸵,并實現(xiàn)相應(yīng)代碼的方式來做到移動這個正方形偏螺。

首先附上本篇文章的思維導(dǎo)圖。

正方形思維導(dǎo)圖.png

一匆光、準(zhǔn)備工作

1套像、環(huán)境搭建
1.1 創(chuàng)建項目

首先創(chuàng)建一個Mac App,如圖(創(chuàng)建.png)所示


創(chuàng)建.png

并將AppDelegate.h终息、AppDelegate.m夺巩、ViewController.h、ViewController.m周崭、main.m等文件刪除柳譬,如圖(刪除.png)所示。

刪除.png

再創(chuàng)建一個空文件续镇,并改名為main.cpp或者main.mm美澳。如圖(改名.png)


改名.png
1.2 資源庫集成

如需下載資源庫,可在此百度網(wǎng)盤鏈接下載磨取,鏈接永久有效
鏈接: https://pan.baidu.com/s/1ZtkJyAAkhI2iCC9EDKJHfQ 密碼: kgfa

1)添加依賴庫OpenGl.framework 和 GLUT.framework人柿,如下圖


image.png
1.3 main函數(shù)

可以先將如下代碼粘貼進(jìn)main.cpp中。


#include "GLShaderManager.h"
/*
 `#include<GLShaderManager.h>` 移入了GLTool 著色器管理器(shader Mananger)類忙厌。沒有著色器凫岖,我們就不能在OpenGL(核心框架)進(jìn)行著色。著色器管理器不僅允許我們創(chuàng)建并管理著色器逢净,還提供一組“存儲著色器”哥放,他們能夠進(jìn)行一些初步?基本的渲染操作歼指。
 */

#include "GLTools.h"
/*
 `#include<GLTools.h>`  GLTool.h頭文件包含了大部分GLTool中類似C語言的獨立函數(shù)
*/

 
#include <GLUT/GLUT.h>
/*
 在Mac 系統(tǒng)下,`#include<glut/glut.h>`
 在Windows 和 Linux上甥雕,我們使用freeglut的靜態(tài)庫版本并且需要添加一個宏
*/

//定義一個踩身,著色管理器
GLShaderManager shaderManager;

//簡單的批次容器,是GLTools的一個簡單的容器類社露。
GLBatch triangleBatch;


//blockSize 邊長
GLfloat blockSize = 0.1f;

//正方形的4個點坐標(biāo)
GLfloat vVerts[] = {
        -blockSize,-blockSize,0.0f,
        blockSize,-blockSize,0.0f,
        blockSize,blockSize,0.0f,
        -blockSize,blockSize,0.0f
};



/*
 在窗口大小改變時挟阻,接收新的寬度&高度。
 */
void changeSize(int w,int h)
{
    /*
      x,y 參數(shù)代表窗口中視圖的左下角坐標(biāo)峭弟,而寬度附鸽、高度是像素為表示,通常x,y 都是為0
     */
    glViewport(0, 0, w, h);
    
}

void RenderScene(void)
{

    //1.清除一個或者一組特定的緩存區(qū)
    /*
     緩沖區(qū)是一塊存在圖像信息的儲存空間瞒瘸,紅色坷备、綠色、藍(lán)色和alpha分量通常一起分量通常一起作為顏色緩存區(qū)或像素緩存區(qū)引用情臭。
     OpenGL 中不止一種緩沖區(qū)(顏色緩存區(qū)省撑、深度緩存區(qū)和模板緩存區(qū))
      清除緩存區(qū)對數(shù)值進(jìn)行預(yù)置
     參數(shù):指定將要清除的緩存的
     GL_COLOR_BUFFER_BIT :指示當(dāng)前激活的用來進(jìn)行顏色寫入緩沖區(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è)置一組浮點數(shù)來表示紅色
    GLfloat vRed[] = {1.0,0.0,0.0,1.0f};
    
    //傳遞到存儲著色器,即GLT_SHADER_IDENTITY著色器俯在,這個著色器只是使用指定顏色以默認(rèn)笛卡爾坐標(biāo)第在屏幕上渲染幾何圖形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
    
    //提交著色器
    triangleBatch.Draw();
    
    //在開始的設(shè)置openGL 窗口的時候竟秫,我們指定要一個雙緩沖區(qū)的渲染環(huán)境。這就意味著將在后臺緩沖區(qū)進(jìn)行渲染跷乐,渲染結(jié)束后交換給前臺鸿摇。這種方式可以防止觀察者看到可能伴隨著動畫幀與動畫幀之間的閃爍的渲染過程。緩沖區(qū)交換平臺將以平臺特定的方式進(jìn)行劈猿。
    //將后臺緩沖區(qū)進(jìn)行渲染拙吉,然后結(jié)束后交換給前臺
    glutSwapBuffers();
    
}

void setupRC()
{
    //設(shè)置清屏顏色(背景顏色)
    glClearColor(0.98f, 0.40f, 0.7f, 1);
    
    
    //沒有著色器,在OpenGL 核心框架中是無法進(jìn)行任何渲染的揪荣。初始化一個渲染管理器筷黔。
    //在前面的課程,我們會采用固管線渲染仗颈,后面會學(xué)著用OpenGL著色語言來寫著色器
    shaderManager.InitializeStockShaders();
    
    
//    //指定頂點
//    //在OpenGL中佛舱,三角形是一種基本的3D圖元繪圖原素。
//    GLfloat vVerts[] = {
//        -0.5f,0.0f,0.0f,
//        0.5f,0.0f,0.0f,
//        0.0f,0.5f,0.0f
//    };
    
    //圖元的連接方式修改為GL_TRIANGLE_FAN 挨决,4個頂點
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
    
}


int main(int argc,char *argv[])
{
    //設(shè)置當(dāng)前工作目錄请祖,針對MAC OS X
    /*
     `GLTools`函數(shù)`glSetWorkingDrectory`用來設(shè)置當(dāng)前工作目錄。實際上在Windows中是不必要的脖祈,因為工作目錄默認(rèn)就是與程序可執(zhí)行執(zhí)行程序相同的目錄肆捕。但是在Mac OS X中,這個程序?qū)?dāng)前工作文件夾改為應(yīng)用程序捆綁包中的`/Resource`文件夾盖高。`GLUT`的優(yōu)先設(shè)定自動進(jìn)行了這個中設(shè)置慎陵,但是這樣中方法更加安全眼虱。
     */
    gltSetWorkingDirectory(argv[0]);
    
    
    //初始化GLUT庫,這個函數(shù)只是傳說命令參數(shù)并且初始化glut庫
    glutInit(&argc, argv);
    
    /*
     初始化雙緩沖窗口,其中標(biāo)志GLUT_DOUBLE席纽、GLUT_RGBA捏悬、GLUT_DEPTH、GLUT_STENCIL分別指
     雙緩沖窗口润梯、RGBA顏色模式过牙、深度測試、模板緩沖區(qū)
     
     --GLUT_DOUBLE`:雙緩存窗口纺铭,是指繪圖命令實際上是離屏緩存區(qū)執(zhí)行的抒和,然后迅速轉(zhuǎn)換成窗口視圖,這種方式彤蔽,經(jīng)常用來生成動畫效果;
     --GLUT_DEPTH`:標(biāo)志將一個深度緩存區(qū)分配為顯示的一部分庙洼,因此我們能夠執(zhí)行深度測試顿痪;
     --GLUT_STENCIL`:確保我們也會有一個可用的模板緩存區(qū)。
     深度油够、模板測試后面會細(xì)致講到
     */
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    
    //GLUT窗口大小蚁袭、窗口標(biāo)題
    //glutInitWindowSize(600, 800);
    glutInitWindowSize(500, 500);
    glutCreateWindow("Triangle");
    
    /*
     GLUT 內(nèi)部運行一個本地消息循環(huán),攔截適當(dāng)?shù)南⑹АH缓笳{(diào)用我們不同時間注冊的回調(diào)函數(shù)揩悄。我們一共注冊2個回調(diào)函數(shù):
     1)為窗口改變大小而設(shè)置的一個回調(diào)函數(shù)
     2)包含OpenGL 渲染的回調(diào)函數(shù)
     */
    //注冊重塑函數(shù)
    glutReshapeFunc(changeSize);
    //注冊顯示函數(shù)
    glutDisplayFunc(RenderScene);
    
    
    
    /*
     初始化一個GLEW庫,確保OpenGL API對程序完全可用。
     在試圖做任何渲染之前鬼悠,要檢查確定驅(qū)動程序的初始化過程中沒有任何問題
     */
    GLenum status = glewInit();
    if (GLEW_OK != status) {
        
        printf("GLEW Error:%s\n",glewGetErrorString(status));
        return 1;
        
    }
    
    //設(shè)置我們的渲染環(huán)境
    setupRC();
    
    glutMainLoop();
    


    
    return  0;
    
}

PS:int main(int argc,char *argv[]) 函數(shù)必須實現(xiàn)删性,否則會抱無入口函數(shù)的錯誤:xcode implicit entry/start for main executable。

至此焕窝,一個完整的OpenGL的項目就搭建完成了蹬挺,跑起來的效果如下圖。


image.png

二它掂、正方形繪制與鍵位控制流程

2.1 初始化

在代碼編寫之前巴帮,首先需要創(chuàng)建一些全局變量。

//批次容器類對象虐秋,其中存放了頂點數(shù)據(jù)榕茧,并通過相關(guān)方法,承載了頂點數(shù)據(jù)以及片元著色器的相關(guān)操作
GLBatch triangleBatch;
//渲染管理器
GLShaderManager shaderManager;

//頂點到坐標(biāo)軸的距離
GLfloat blockSize = 0.1f;
//頂點數(shù)據(jù)
GLfloat vVerts[] = {
    -blockSize,-blockSize,0.f,
    blockSize,-blockSize,0.f,
    blockSize,blockSize,0.f,
    -blockSize,blockSize,0.f
};

//移動圖形時客给,x軸偏移量
GLfloat xPos = 0.f;
//移動圖形時用押,y軸偏移量
GLfloat yPos = 0.f;
2.1.1 main函數(shù)

在main.app中,有一個main函數(shù)靶剑,它是整個程序的入口函數(shù)只恨,在該函數(shù)中译仗,需要做一些OpenGL的初始化工作。

  1. 設(shè)置當(dāng)前目錄官觅,該方法針對MAC OS X纵菌;
  2. 初始化glut庫;
  3. 初始化雙緩沖窗口休涤;
  4. 設(shè)置glut窗口的大小以及標(biāo)題咱圆;
  5. 注冊重塑函數(shù),changeSize為重塑函數(shù)功氨;
  6. 注冊渲染函數(shù)序苏,RenderScene為渲染函數(shù);
  7. 注冊特殊函數(shù)捷凄,SpecialKeys為特殊函數(shù)忱详;
  8. 調(diào)用setupRC() 函數(shù),做準(zhǔn)備&設(shè)置頂點數(shù)據(jù)等操作跺涤;
  9. 開啟glutMainLoop匈睁。

具體代碼如下:

int main(int argc,char *argv[])
{
    //設(shè)置當(dāng)前工作目錄,針對MAC OS X
    gltSetWorkingDirectory(argv[0]);
    
    //初始化GLUT庫,這個函數(shù)只是傳說命令參數(shù)并且初始化glut庫
    glutInit(&argc, argv);
    
    /*
     初始化雙緩沖窗口桶错,其中標(biāo)志GLUT_DOUBLE航唆、GLUT_RGBA、GLUT_DEPTH院刁、GLUT_STENCIL分別指
     雙緩沖窗口糯钙、RGBA顏色模式、深度測試退腥、模板緩沖區(qū)
     
     --GLUT_DOUBLE`:雙緩存窗口任岸,是指繪圖命令實際上是離屏緩存區(qū)執(zhí)行的,然后迅速轉(zhuǎn)換成窗口視圖狡刘,這種方式演闭,經(jīng)常用來生成動畫效果;
     --GLUT_DEPTH`:標(biāo)志將一個深度緩存區(qū)分配為顯示的一部分颓帝,因此我們能夠執(zhí)行深度測試米碰;
     --GLUT_STENCIL`:確保我們也會有一個可用的模板緩存區(qū)。
     深度购城、模板測試后面會細(xì)致講到
     */
 glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    //GLUT窗口大小吕座、窗口標(biāo)題
    glutInitWindowSize(500, 500);
    glutCreateWindow("Triangle");
    //注冊重塑函數(shù)
    glutReshapeFunc(changeSize);
    //注冊顯示函數(shù)
    glutDisplayFunc(RenderScene);
    //注冊特殊函數(shù)
   glutSpecialFunc(SpecialKeys);
    /*
     初始化一個GLEW庫,確保OpenGL API對程序完全可用。
     在試圖做任何渲染之前瘪板,要檢查確定驅(qū)動程序的初始化過程中沒有任何問題
     */
    GLenum status = glewInit();
    if (GLEW_OK != status) {
        printf("GLEW Error:%s\n",glewGetErrorString(status));
        return 1;
    }
    
    //設(shè)置我們的渲染環(huán)境
    setupRC();
    glutMainLoop();
    return  0;
}
2.1.2 setupRC
  1. 初始化渲染管理器
    如果沒有著色器吴趴,OpenGL是無法進(jìn)行工作的,因此侮攀,首先初始化一個渲染管理器锣枝,目前是使用固定管線做渲染厢拭。因此,需要通過思維導(dǎo)圖中提到的 著色器manager(shaderManager) 初始化渲染管理器撇叁。

  2. 設(shè)置清屏顏色 glClearColor(0.98f, 0.40f, 0.7f, 1);

  3. 設(shè)置頂點數(shù)據(jù)

代碼如下

void SetupRC()
{
    glClearColor(0.98, 0.34, 0.14, 1);
    
     //初始化shader供鸠,固定著色器
    shaderManager.InitializeStockShaders();
    //將頂點數(shù)據(jù)復(fù)制到頂點著色器
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
}
2.2 RunLoop
2.2.1 重塑方法

該方法在窗口大小改變或者第一次創(chuàng)建窗口的時候會調(diào)用,傳入窗口的寬度和高度陨闹。

//窗口大小改變時接受新的寬度和高度楞捂,其中0,0代表窗口中視口的左下角坐標(biāo),w趋厉,h代表像素
void ChangeSize(int w,int h)
{
    //設(shè)置視口
    glViewport(0, 0, w, h);
}
2.2.2 渲染方法

該方法在屏幕發(fā)生變化或者用戶手動調(diào)用的時候寨闹,會調(diào)用,用來實現(xiàn)數(shù)據(jù)->渲染的過程君账。

//開始渲染
void RenderScene(void)
{
    //清空顏色緩沖區(qū)繁堡、深度緩沖區(qū)、模板緩沖區(qū)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    //設(shè)置顏色
    GLfloat vRed[] = {1,0,0,1};
    
    M3DMatrix44f mTransformMatrix;
    //xPos和yPos是頂點的偏移量乡数,mTransformMatrix為結(jié)果矩陣椭蹄,
   //通過 m3dTranslationMatrix44方法及xPos和yPos得出偏移矩陣mTransformMatrix
    m3dTranslationMatrix44(mTransformMatrix, xPos, yPos, 0);
    shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransformMatrix,vRed);
    triangleBatch.Draw();
    //從緩沖區(qū)顯示到屏幕
    glutSwapBuffers();
    
}
2.2.3 特殊鍵位方法

該方法在用戶使用特殊鍵位的時候調(diào)用。

void SpecialFunc(int key,  int x, int y) {
    
    
    //復(fù)雜的圖形  100個頂點之類的   用矩陣
    GLfloat  stepSize = 0.025;
    
    if (key == GLUT_KEY_LEFT) {
        xPos -= stepSize;
    } else if (key == GLUT_KEY_RIGHT) {
        xPos += stepSize;
    } else if (key == GLUT_KEY_UP) {
        yPos += stepSize;
    } else if (key == GLUT_KEY_DOWN) {
        yPos -= stepSize;
    }
    
    if (xPos < -1.f + blockSize) {
        xPos = -1.f + blockSize;
    } else if (xPos > 1.f - blockSize) {
        xPos = 1.f - blockSize;
    }
    
    if (yPos < -1.f + blockSize) {
        yPos = -1.f + blockSize;
    } else if (yPos > 1.f - blockSize) {
        yPos = 1.f - blockSize;
    }
    glutPostRedisplay();
}

最后瞳脓,附上一張gluMainLoop的監(jiān)聽響應(yīng)流程圖。


流程圖.png

完整demo鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末澈侠,一起剝皮案震驚了整個濱河市劫侧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哨啃,老刑警劉巖烧栋,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拳球,居然都是意外死亡审姓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門祝峻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來魔吐,“玉大人,你說我怎么就攤上這事莱找〕昴罚” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵奥溺,是天一觀的道長辞色。 經(jīng)常有香客問我,道長浮定,這世上最難降的妖魔是什么相满? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任层亿,我火速辦了婚禮,結(jié)果婚禮上立美,老公的妹妹穿的比我還像新娘匿又。我一直安慰自己,他們只是感情好悯辙,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布琳省。 她就那樣靜靜地躺著,像睡著了一般躲撰。 火紅的嫁衣襯著肌膚如雪针贬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天拢蛋,我揣著相機與錄音桦他,去河邊找鬼。 笑死谆棱,一個胖子當(dāng)著我的面吹牛快压,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播垃瞧,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼蔫劣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了个从?” 一聲冷哼從身側(cè)響起脉幢,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗦锐,沒想到半個月后嫌松,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡奕污,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年萎羔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碳默。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡贾陷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嘱根,到底是詐尸還是另有隱情昵宇,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布儿子,位于F島的核電站瓦哎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蒋譬,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一割岛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧犯助,春花似錦癣漆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞬哼,卻和暖如春婚肆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坐慰。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工较性, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人结胀。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓赞咙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親糟港。 傳聞我的和親對象是個殘疾皇子攀操,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348