一、案例及相關(guān)函數(shù)說明
使用OpenGL繪制一個正方形,并且利用鍵盤的上下左右鍵控制正方形的上下左右移動。效果如下:

效果.gif
本次案例需要的幾個函數(shù):
-
int main(int argc,char *argv[])main函數(shù):
類似于我們開發(fā)中的main函數(shù),是APP程序的入口,在OPenGL中是程序??。
OpenGL 是?向過程編程.所以你會發(fā)現(xiàn)利用OpenGL處理圖形/圖像都是鏈?zhǔn)叫问?
以及基于OpenGL封裝的圖像處理理框架也是鏈?zhǔn)骄幊獭?/li> -
void changeSize(int w ,int h):changeSize 函數(shù):
自定義函數(shù),通過glutReshaperFunc(函數(shù)名)注冊為重塑函數(shù).當(dāng)屏幕大小發(fā)生變化/或者第?次創(chuàng)建窗口時,會調(diào)用該函數(shù)調(diào)整窗口?小/視?口?小。 -
void RenderScene(void)RenderScene函數(shù):
?定義函數(shù),通過glutDisplayFunc(函數(shù)名)注冊為顯示渲染函數(shù).當(dāng)屏幕發(fā)生變化/或者開發(fā)者主動渲染會調(diào)?此函數(shù),用來實現(xiàn)數(shù)據(jù)->渲染過程。 -
void setupRC(void)setupRC函數(shù):
自定義函數(shù),設(shè)置你需要渲染的圖形的相關(guān)頂點數(shù)據(jù)/顏?色數(shù)據(jù)等數(shù)據(jù)準(zhǔn)備工作,可以理解為初始化配置函數(shù)。 -
void SpecialKeys(int key, int x, int y)SpecialKey函數(shù):
自定義函數(shù),接收到鍵盤上下左右按鍵的響應(yīng),根據(jù)按鍵進行計算并且觸發(fā)重繪API。
接下來看下整個案例的流程圖:

流程圖.png
二、上代碼
main()函數(shù):
程序啟動的入口,在這里主要是做程序的準(zhǔn)備工作:
- 初始化OpenGL,設(shè)置當(dāng)前工作目錄,初始化
GLUT庫等; - 設(shè)置窗口大小和標(biāo)題顯示相關(guān)的內(nèi)容
- 注冊各種監(jiān)聽回調(diào)函數(shù)(本案例中主要是以下幾種:
changeSize窗口大小發(fā)生改變的回調(diào);RenderScene繪制/重繪回調(diào);SpecialKeys鍵盤特殊鍵位點擊后的的回調(diào)) - 調(diào)用setupRC(),開啟
glutMainLoop(類似iOS中的RunLoop)。
int main(int argc,char *argv[])
{
//設(shè)置當(dāng)前工作目錄,針對MAC OS X
gltSetWorkingDirectory(argv[0]);
//初始化GLUT庫,這個函數(shù)只是傳說命令參數(shù)并且初始化glut庫
glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//GLUT窗口大小、窗口標(biāo)題
glutInitWindowSize(800, 600);
glutCreateWindow("Triangle");
//注冊重塑函數(shù),當(dāng)窗口大小發(fā)生改變時,會觸發(fā)changeSize()回調(diào)
glutReshapeFunc(changeSize);
//注冊顯示函數(shù);當(dāng)changeSize觸發(fā)時,或者glutPostRedisplay()會觸發(fā)
//RenderScene()回調(diào)
glutDisplayFunc(RenderScene);
//注冊特殊函數(shù)(鍵盤按鍵點擊監(jiān)聽),當(dāng)點擊鍵盤時觸發(fā);
glutSpecialFunc(SpecialKeys);
GLenum status = glewInit();
if (GLEW_OK != status) {
printf("GLEW Error:%s\n",glewGetErrorString(status));
return 1;
}
//設(shè)置我們的渲染環(huán)境
setupRC();
glutMainLoop();
return 0;
}
setupRC()函數(shù):
setupRC主要做了一些初始化操作,可以理解為iOS中在初始化UIView時進行的UI開發(fā)配置
- 設(shè)置窗口背景顏?色
- 初始化存儲著?色器
shaderManager - 設(shè)置圖形頂點數(shù)據(jù)
- 利用
GLBatch三?形批次類,將數(shù)據(jù)傳遞到著色器器
setupRC只能在main函數(shù)中調(diào)用手動觸發(fā)。
void setupRC()
{
//設(shè)置清屏顏色(背景顏色)
glClearColor(0.98f, 0.40f, 0.7f, 1);
//初始化著色管理器
shaderManager.InitializeStockShaders();
//修改為GL_TRIANGLE_FAN ,4個頂點
//其實就是在以某種方式構(gòu)造數(shù)據(jù),后面的渲染會用到這些數(shù)據(jù)
//這里用到了GLBatch批次類,是一個容器類
//裝什么樣的數(shù)據(jù)
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
//數(shù)據(jù)是什么
triangleBatch.CopyVertexData3f(vVerts);
//裝完了
triangleBatch.End();
}
changeSize()函數(shù):
changeSize中主要做兩件事:
- 設(shè)置
OpenGL視? - 設(shè)置
OpenGL投影?式等.
changeSize觸發(fā)方式主要有兩種:手動觸發(fā)(新建窗?)和回調(diào)觸發(fā)(改變視口位置大小后)。
void changeSize(int w ,int h) {
/*
x,y 參數(shù)代表窗口中視圖的左下角坐標(biāo),而寬度、高度是像素為表示,通常x,y 都是為0
*/
glViewport(0, 0, w, h);
}
RenderScene()函數(shù):
RenderScene主要處理的就是屏幕上具體呈現(xiàn)的內(nèi)容:
- 清理理緩存區(qū)(顏?色,深度,模板緩存區(qū)等)
- 使?用存儲著?色器器
- 繪制圖形.
可以理解為UIView下的drawInRect:;
RenderScene觸發(fā)方式主要有兩種:系統(tǒng)自動觸發(fā)(changeSize調(diào)用后)和回調(diào)觸發(fā)(調(diào)用glutPostRedisplay重繪)。
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//設(shè)置一個顏色{R,G,B,A}
GLfloat vRed[] = {1.0f,0.0f,0.0f,0.0f};
//4x4矩陣
M3DMatrix44f mTransfromMatrix;
//平移
m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0f);
//將矩陣結(jié)果 提交給固定著色器(平面著色器)中繪制
shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransfromMatrix,vRed);
triangleBatch.Draw();
//執(zhí)行交換緩存區(qū) (因為是雙緩存區(qū))
glutSwapBuffers();
}
值得注意的是,這里我們移動視圖的時候是通過矩陣來實現(xiàn)的,除此之外我們還有分點單獨計算,但是那樣在頂點數(shù)據(jù)很多的情況下效率是極其低的。所以合理運用矩陣對我們使用OpenGL起到非常重要的作用。
SpecialKeys()函數(shù):
SpecialKeys是我們在main()中添加的對鍵盤按鈕點擊后的監(jiān)聽回調(diào),該回調(diào)會返回一個int類型的key,我們根據(jù)曾這個key可以判斷我們點擊了鍵盤上的哪個鍵,進而實現(xiàn)后面的計算。這個方法是按鍵控制屏幕上視圖移動的效果的核心方法,所以這里主要捕獲上,下,左,右鍵,并做一些數(shù)據(jù)處理。
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;
}
//碰撞檢測
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;
}
//這是觸發(fā)重繪的一個API,類似于調(diào)用setNeedsDisplay()
glutPostRedisplay();
}
代碼中的碰撞檢測實際是顯示邊界問題,防止我們在移動過程中正方形視圖移出了我們的顯示視圖區(qū)域。
覺得不錯記得點贊哦!聽說看完點贊的人逢考必過,逢獎必中。?( ′???` )比心