目標(biāo)
這篇文章要實現(xiàn)的效果主要是朴上,先畫出一個正方形,然后通過監(jiān)聽特殊鍵位函數(shù)懂鸵,并實現(xiàn)相應(yīng)代碼的方式來做到移動這個正方形偏螺。
首先附上本篇文章的思維導(dǎo)圖。
一匆光、準(zhǔn)備工作
1套像、環(huán)境搭建
1.1 創(chuàng)建項目
首先創(chuàng)建一個Mac App,如圖(創(chuàng)建.png)所示
并將AppDelegate.h终息、AppDelegate.m夺巩、ViewController.h、ViewController.m周崭、main.m等文件刪除柳譬,如圖(刪除.png)所示。
再創(chuàng)建一個空文件续镇,并改名為main.cpp或者main.mm美澳。如圖(改名.png)
1.2 資源庫集成
如需下載資源庫,可在此百度網(wǎng)盤鏈接下載磨取,鏈接永久有效
鏈接: https://pan.baidu.com/s/1ZtkJyAAkhI2iCC9EDKJHfQ 密碼: kgfa
1)添加依賴庫OpenGl.framework 和 GLUT.framework人柿,如下圖
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的項目就搭建完成了蹬挺,跑起來的效果如下圖。
二它掂、正方形繪制與鍵位控制流程
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的初始化工作。
- 設(shè)置當(dāng)前目錄官觅,該方法針對MAC OS X纵菌;
- 初始化glut庫;
- 初始化雙緩沖窗口休涤;
- 設(shè)置glut窗口的大小以及標(biāo)題咱圆;
- 注冊重塑函數(shù),changeSize為重塑函數(shù)功氨;
- 注冊渲染函數(shù)序苏,RenderScene為渲染函數(shù);
- 注冊特殊函數(shù)捷凄,SpecialKeys為特殊函數(shù)忱详;
- 調(diào)用setupRC() 函數(shù),做準(zhǔn)備&設(shè)置頂點數(shù)據(jù)等操作跺涤;
- 開啟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
初始化渲染管理器
如果沒有著色器吴趴,OpenGL是無法進(jìn)行工作的,因此侮攀,首先初始化一個渲染管理器锣枝,目前是使用固定管線做渲染厢拭。因此,需要通過思維導(dǎo)圖中提到的 著色器manager(shaderManager) 初始化渲染管理器撇叁。設(shè)置清屏顏色 glClearColor(0.98f, 0.40f, 0.7f, 1);
設(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)流程圖。