3计维、OpenGL初探之OpenGL初探之繪制可用鍵盤移動(dòng)的三角形實(shí)戰(zhàn)解析

前言:前一部分了解了OpenGL環(huán)境搭建和基本API之后袜香,我們先來做一個(gè)小小的練習(xí),使用固定管線來繪制一個(gè)可移動(dòng)的三角形鲫惶,同時(shí)詳細(xì)解釋一下一些常用方法的含義

一蜈首、搭建OpenGL在Mac下的環(huán)境


搭建Xcode環(huán)境,這里不再做過多贅述了

傳送門:http://www.reibang.com/p/05555148d567

二欠母、實(shí)戰(zhàn)開始


(注:完整代碼在文章的最后面)
1欢策、首先來到main函數(shù)中進(jìn)行環(huán)境初始化和一些函數(shù)的注冊(cè)

int main(int argc,char* argv[])

{
    
    gltSetWorkingDirectory(argv[0]);
    
    glutInit(&argc, argv);
    
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    
    glutInitWindowSize(800,600);
    
    glutCreateWindow("Triangle");
        
    glutReshapeFunc(ChangeSize);
    
    glutDisplayFunc(RenderScene);
    
    glutSpecialFunc(SpecialKeys);
    
    GLenum err = glewInit();
    
    if(GLEW_OK != err) {
        
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
        
        return 1;
        
    }
    
    SetupRC();
    
    glutMainLoop();
    
    return 0;
}

下面來一一分析對(duì)應(yīng)函數(shù)和方法的意思,

gltSetWorkingDirectory(argv[0]) : 是”GLTools“用來設(shè)置當(dāng)前工作目錄的函數(shù)赏淌,實(shí)際上在windows中是不必要的踩寇,因?yàn)楣ぷ髂夸浤J(rèn)就是與程序的可執(zhí)行程序的目錄相同。但是在Mac OSX環(huán)境中六水,這個(gè)程序?qū)?dāng)前工作文件夾改為應(yīng)用程序捆綁包中的"/Resource"文件夾.'GLUT'的優(yōu)先設(shè)定會(huì)自動(dòng)設(shè)定為這個(gè)俺孙,這樣寫也是為了更加安全。

glutInit(&argc, argv): 初始化GLUT庫掷贾,這個(gè)函數(shù)只是傳入命令參數(shù)并且初始化glut庫

glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL): 設(shè)置顯示模式睛榄。其中GLUT_DOUBLE 指的是初始化雙緩沖窗口顯示模式,GLUT_RGBA RGBA顏色顯示模式想帅,GLUT_DEPTH 初始化深度測試顯示模式场靴,可以用于開啟深度測試,GLUT_STENCIL 初始化模板緩沖區(qū)

glutInitWindowSize(800,600) 初始化一個(gè)GLUT窗口并設(shè)置窗口大小
glutCreateWindow("Triangle") 設(shè)置窗口的標(biāo)題

glutReshapeFunc(ChangeSize) 注冊(cè)綁定重塑函數(shù)港准,當(dāng)窗口第一次創(chuàng)建或者窗口大小發(fā)生變化憎乙,需要界面重繪時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用這個(gè)已經(jīng)注冊(cè)過的自定義函數(shù)ChangeSize
glutDisplayFunc(RenderScene) 注冊(cè)綁定顯示函數(shù)叉趣,當(dāng)屏幕發(fā)生渲染或者你使用代碼強(qiáng)制渲染泞边,需要界面重繪的時(shí)候,系統(tǒng)會(huì)自動(dòng)調(diào)用這個(gè)已經(jīng)注冊(cè)綁定過的自定義函數(shù)RenderSize

glutSpecialFunc(SpecialKeys); 當(dāng)你使用特殊鍵位的時(shí)候比如鍵盤的上下左右鍵的時(shí)候疗杉,就會(huì)走到這個(gè)方法里阵谚,在這個(gè)函數(shù)中做特殊鍵位區(qū)分的時(shí)候,這些特殊鍵位都有對(duì)應(yīng)的枚舉值比如上(GLUT_KEY_UP) 下(GLUT_KEY_DOWN)左(GLUT_KEY_LEFT)右(GLUT_KEY_RIGHT)烟具,我找了一些梢什,這個(gè)簡單了解一下就行了

#define GLUT_KEY_F1         1
#define GLUT_KEY_F2         2
#define GLUT_KEY_F3         3
#define GLUT_KEY_F4         4
#define GLUT_KEY_F5         5
#define GLUT_KEY_F6         6
#define GLUT_KEY_F7         7
#define GLUT_KEY_F8         8
#define GLUT_KEY_F9         9
#define GLUT_KEY_F10            10
#define GLUT_KEY_F11            11
#define GLUT_KEY_F12            12
/* directional keys */
#define GLUT_KEY_LEFT           100
#define GLUT_KEY_UP         101
#define GLUT_KEY_RIGHT          102
#define GLUT_KEY_DOWN           103
#define GLUT_KEY_PAGE_UP        104
#define GLUT_KEY_PAGE_DOWN      105
#define GLUT_KEY_HOME           106
#define GLUT_KEY_END            107
#define GLUT_KEY_INSERT         108

GLenum err = glewInit(); 初始化一個(gè)GLEW庫,確保OpenGL API對(duì)程序完全可用朝聋,在試圖做任何渲染之前嗡午,要檢查確定驅(qū)動(dòng)程序的初始化過程中沒有任何問題

SetupRC() 自定方法,設(shè)置我們的渲染環(huán)境

glutMainLoop() 運(yùn)行循環(huán)冀痕,類似OC的Runloop荔睹,函數(shù)在調(diào)用之后狸演,在主窗口被關(guān)閉之前都不會(huì)返回,一個(gè)應(yīng)用程序只需要調(diào)用一次僻他,這個(gè)函數(shù)負(fù)責(zé)處理我們所有的消息宵距,直到我們關(guān)閉程序?yàn)橹埂?/p>

2、接著引入固定管線著色器和OpenGL一些基本庫文件

#include "GLShaderManager.h"

#include "GLTools.h"

#include <glut/glut.h>


GLShaderManager.h 這個(gè)移入了GLTool著色器管理器類shader manager吨拗,沒有著色器满哪,我們就不能再OpenGL核心框架進(jìn)行著色,著色器管理器不僅允許我們創(chuàng)建并管理著色器劝篷,還提供了一組”存儲(chǔ)著色器“哨鸭,他們能夠進(jìn)行一些基本的渲染操作。

GLTools.h GLTool.h頭文件包含了大部分GLTool中類似C語言的獨(dú)立函數(shù)

GLUT/GLUT.h 在Mac 系統(tǒng)下娇妓,需要#include <glut/glut.h> 兔跌; 在windows和Linux上板熊,我們使用freeglut的靜態(tài)庫版本并需要添加一個(gè)宏

3它呀、重塑函數(shù)的實(shí)現(xiàn),在窗口大小改變的時(shí)候项钮,接受新的寬度和高度

void changeSize(int w,int h)
{
    glViewport(0, 0, w, h);
    
}

glViewPort這個(gè)函數(shù)就是設(shè)置視口,x,y 參數(shù)代表窗口中視圖的左下角坐標(biāo)蕊蝗,而寬度、高度是像素為表示赖舟,通常x,y 都是為0蓬戚,調(diào)用glViewPort會(huì)調(diào)用重新渲染RenderScene

4、接著定義一個(gè)著色器管理變量和一個(gè)批次類宾抓,GLBatch是GLTools的一個(gè)簡單的容器類

GLBatch triangleBatch;

GLShaderManager shaderManager;

5子漩、接下來,我們需要設(shè)置渲染環(huán)境和頂點(diǎn)數(shù)據(jù)

void SetupRC()

{

    glClearColor(0.0f,0.0f,1.0f,1.0f);
    
    shaderManager.InitializeStockShaders();
        
    GLfloat vVerts[] = {
        
        -0.5f,0.0f,0.0f,
        
        0.5f,0.0f,0.0f,
        
        0.0f,1.0f,0.0f,
        
    };
    
    
    triangleBatch.Begin(GL_TRIANGLES,3);
    
    triangleBatch.CopyVertexData3f(vVerts);
    
    triangleBatch.End();
}

glClearColor 設(shè)置清屏顏色石洗,設(shè)置到顏色緩沖區(qū)里面幢泼,是一個(gè)狀態(tài)基,可以理解為窗口的背景色

shaderManager.InitializeStockShaders() 初始化一個(gè)著色器管理器

GLfloat vVerts[] = {
        
        -0.5f,0.0f,0.0f,
        
        0.5f,0.0f,0.0f,
        
        0.0f,1.0f,0.0f,
        
    };
    定義一個(gè)一維數(shù)組讲衫,里面存儲(chǔ)三角形的三個(gè)頂點(diǎn)的坐標(biāo)缕棵,每個(gè)頂點(diǎn)有三個(gè)數(shù)(x,y涉兽,z)

其中
triangleBatch.Begin(GL_TRIANGLES,3); 第一個(gè)參數(shù)GL_TRIANGLES指的是選擇三角形的連接方式招驴,第二個(gè)參數(shù)3代表3個(gè)頂點(diǎn)

triangleBatch.CopyVertexData3f(vVerts);把頂點(diǎn)數(shù)據(jù)copy進(jìn)去,然后triangleBatch.End();表示設(shè)置完成

這里拓展一下便于理解枷畏,如果是畫四邊形SetUpRC中的頂點(diǎn)坐標(biāo)需要修改成

如果是要繪制四邊形别厘,需要修改頂點(diǎn)數(shù)組,然后修改連接方式如下

void SetupRC()

{    
    glClearColor(0.0f,0.0f,1.0f,1.0f);
    
    shaderManager.InitializeStockShaders();
    
    GLfloat vVerts[] = {
        
        -0.5f,-0.5f,0.0f,
        
        -0.5f,0.5f,0.0f,
        
        0.5f,0.5f,0.0f,
        
        0.5f,-0.5f,0.0f,
        
    };
    
    triangleBatch.Begin(GL_TRIANGLE_FAN,4);
    
    triangleBatch.CopyVertexData3f(vVerts);
    
    triangleBatch.End();
    
}

對(duì)比一下拥诡,頂點(diǎn)數(shù)組變了触趴,然后連接方式由GL_TRIANGLES變?yōu)镚L_TRIANGLE_FAN氮发,頂點(diǎn)個(gè)數(shù)由3個(gè)變?yōu)?個(gè)

 頂點(diǎn)數(shù)組的變化很明顯,就不細(xì)說了
 連接方式和頂點(diǎn)個(gè)數(shù)變了
 //三角形的
 triangleBatch.Begin(GL_TRIANGLES,3);
 //四邊形的
 triangleBatch.Begin(GL_TRIANGLE_FAN,4);

這里再拓展一下雕蔽,OpenGL圖元只有點(diǎn)折柠、線、三角形批狐,現(xiàn)在畫點(diǎn)扇售,線以及多邊形都沒問題了,圓形就需要通過這三個(gè)做處理一下了

6嚣艇、接下來我們需要設(shè)置渲染

void RenderScene(void)

{   
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
        
    GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
        
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
        
    triangleBatch.Draw();
        
    glutSwapBuffers();
    
}

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT) 每次渲染前需要清除特定緩沖區(qū)比如深度緩沖區(qū)承冰,顏色緩沖區(qū)

shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed) 不同的著色器,參數(shù)都是不一樣的食零,但是函數(shù)名都是這個(gè)困乒,繪制簡單的三角形,用單元著色器就行了贰谣,所以選GLT_SHADER_IDENTITY娜搂,并設(shè)置繪制顏色

triangleBatch.Draw() 開始顏色渲染

glutSwapBuffers() 交換緩沖區(qū),把渲染的內(nèi)容提交上去

執(zhí)行一下吱抚,就能看到藍(lán)色背景的windows下百宇,有一個(gè)紅色的三角形

1.png

7、開始設(shè)置移動(dòng)秘豹,設(shè)置移動(dòng)之前需要把頂點(diǎn)坐標(biāo)設(shè)置為全局變量携御,這樣好處理,把下面頂點(diǎn)數(shù)組放到全局

GLfloat vVerts[] = {
        
        -0.5f,0.0f,0.0f,
        
        0.5f,0.0f,0.0f,
        
        0.0f,1.0f,0.0f,
        
    };

把這段坐標(biāo)換成下面這段既绕,然后把邊長減小點(diǎn)啄刹,便于查看效果

//blockSize 邊長
GLfloat blockSize = 0.1f;

//三角形的3個(gè)點(diǎn)坐標(biāo)
GLfloat vVerts[] = {
        -blockSize,0.0f,0.0f,
        blockSize,0.0f,0.0f,
        0.0f,blockSize,0.0f,
};

然后開始實(shí)現(xiàn)SpecialKeys函數(shù),這里拓展一下凄贩,頂點(diǎn)較少可以使用更新頂點(diǎn)坐標(biāo)這種移動(dòng)方式誓军,頂點(diǎn)較多的復(fù)雜圖形,可以使用矩陣進(jìn)行移動(dòng)

void SpecialKeys (int key , int x, int y){
    
    GLfloat stepSize = 0.1f;
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[1];
    
    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;
    
    //更新點(diǎn)的坐標(biāo) ABC
    vVerts[0] = blockX;
    vVerts[1] = blockY;
    
    vVerts[3] = blockX + 2 * stepSize;
    vVerts[4] = blockY;
    
    vVerts[6] = blockX + stepSize;
    vVerts[7] = blockY + stepSize;
    
    triangleBatch.CopyVertexData3f(vVerts);
    
    glutPostRedisplay();
}


其中設(shè)置blockX和blockY只是找了第一個(gè)點(diǎn)作為移動(dòng)坐標(biāo)參照物疲扎,然后相對(duì)第一個(gè)點(diǎn)的坐標(biāo)換算出剩余兩個(gè)點(diǎn)的坐標(biāo)谭企,比如A(-0.1,0评肆,0) B(0.1债查,0,0)瓜挽,換算成A(blockX盹廷,0,0)那此時(shí)的B就是(block + 2 * 0.1久橙,0, 0)俄占, vVerts[0]這里面的下標(biāo)0管怠,代表一維數(shù)組中的第一個(gè)點(diǎn)的x坐標(biāo),只上下左右移動(dòng)缸榄,只需要改三個(gè)點(diǎn)對(duì)應(yīng)的x渤弛,y坐標(biāo)就行了, 三個(gè)點(diǎn)想x和y的坐標(biāo)對(duì)應(yīng)的下標(biāo)分別是0甚带,1和3她肯,4和6,7鹰贵,這樣思路就很清楚了晴氨。

triangleBatch.CopyVertexData3f(vVerts); 這個(gè)將頂點(diǎn)數(shù)組通過GLBatch幫助類,將頂點(diǎn)數(shù)據(jù)傳輸?shù)酱鎯?chǔ)著色器中

glutPostRedisplay()這個(gè)是手動(dòng)觸發(fā)渲染函數(shù)碉输。

然后直接運(yùn)行籽前,就能夠得到一個(gè)可以用鍵盤控制上下左右移動(dòng)的三角形。

完整代碼如下

//
//  main.cpp
//
//  Created by battleMage on 2019/8/11.
//  Copyright ? 2019 battleMage. All rights reserved.
//

#include "GLShaderManager.h"
#include "GLTools.h"
#include <glut/glut.h>

GLBatch triangleBatch;
GLShaderManager shaderManager;

//blockSize 邊長
GLfloat blockSize = 0.1f;

//三角形的3個(gè)點(diǎn)坐標(biāo)
GLfloat vVerts[] = {
    -blockSize,0.0f,0.0f,
    blockSize,0.0f,0.0f,
    0.0f, blockSize,0.0f,
};

void ChangeSize(int w,int h){
    glViewport(0,0, w, h);
}

void SpecialKeys (int key , int x, int y){
    
    GLfloat stepSize = 0.1f;
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[1];
    
    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;
    
    //更新點(diǎn)的坐標(biāo) ABC
    vVerts[0] = blockX;
    vVerts[1] = blockY;
    
    vVerts[3] = blockX + 2 * stepSize;
    vVerts[4] = blockY;
    
    vVerts[6] = blockX + stepSize;
    vVerts[7] = blockY + stepSize;
    
    triangleBatch.CopyVertexData3f(vVerts);
    
    glutPostRedisplay();
}

void SetupRC(){
    glClearColor(0.0f,0.0f,1.0f,1.0f);
    shaderManager.InitializeStockShaders();
    triangleBatch.Begin(GL_TRIANGLES,3);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
}

void RenderScene(void) {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
    triangleBatch.Draw();
    glutSwapBuffers();
}

int main(int argc,char* argv[]){
    
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    glutInitWindowSize(800,600);
    glutCreateWindow("Triangle");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);
    
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
        return 1;
    }
    
    SetupRC();
    glutMainLoop();
    return 0;
}


效果如下:


1.png
2.png
3.png

溪浣雙鯉的技術(shù)摸爬滾打之路

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末敷钾,一起剝皮案震驚了整個(gè)濱河市枝哄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌阻荒,老刑警劉巖挠锥,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異财松,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)纱控,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門辆毡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人甜害,你說我怎么就攤上這事舶掖。” “怎么了尔店?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵眨攘,是天一觀的道長。 經(jīng)常有香客問我嚣州,道長鲫售,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任该肴,我火速辦了婚禮情竹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匀哄。我一直安慰自己秦效,他們只是感情好雏蛮,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著阱州,像睡著了一般挑秉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上苔货,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天犀概,我揣著相機(jī)與錄音,去河邊找鬼蒲赂。 笑死阱冶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的滥嘴。 我是一名探鬼主播木蹬,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼若皱!你這毒婦竟也來了镊叁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤走触,失蹤者是張志新(化名)和其女友劉穎晦譬,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體互广,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡敛腌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惫皱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片像樊。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖旅敷,靈堂內(nèi)的尸體忽然破棺而出生棍,到底是詐尸還是另有隱情,我是刑警寧澤媳谁,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布涂滴,位于F島的核電站,受9級(jí)特大地震影響晴音,放射性物質(zhì)發(fā)生泄漏柔纵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一锤躁、第九天 我趴在偏房一處隱蔽的房頂上張望首量。 院中可真熱鬧,春花似錦、人聲如沸加缘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拣宏。三九已至沈贝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間勋乾,已是汗流浹背宋下。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辑莫,地道東北人学歧。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像各吨,于是被迫代替她去往敵國和親枝笨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容