GLKit 框架是為了簡化iOS上OpenGL ES的開發(fā),提供的基于OpenGL ES的iOS框架。
實現(xiàn)思路:
1. 新建OpenGLES 上下文 并且配置環(huán)境
2. 設(shè)置頂點數(shù)據(jù)數(shù)據(jù)和設(shè)置緩存
3. 創(chuàng)建著色器效果,并啟動著色器
注意:
1. ViewController要繼承GLKViewController
2. 繼承GLKViewController后要實現(xiàn) - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect 方法
一些方法的解析:
GLKBaseEffect
Effect效果類提供標(biāo)準(zhǔn)的公共著色效果的實現(xiàn)。能夠配置效果和相關(guān)的頂點數(shù)據(jù),然后創(chuàng)建和加載適當(dāng)?shù)闹?。GLKit 包括三個可配置著色效果類:GLKBaseEffect實現(xiàn)OpenGL ES 1.1規(guī)范中的關(guān)鍵的燈光和材料模式, GLKSkyboxEffect提供一個skybox效果的實現(xiàn), GLKReflectionMapEffect 在GLKBaseEffect基礎(chǔ)上包括反射映射支持。
為什么OpenGL中要用GLfloat而不用float,兩者有什么區(qū)別呢?
不同的機(jī)器上 float的占用的字節(jié)大小不同,
比如有的機(jī)器上 float 是4個字節(jié)
有的機(jī)器 float 是8個字節(jié)
而GLfloat 則是在不同的環(huán)境下對應(yīng)不同的處理
以確保字節(jié)數(shù)相等
GLuint
GLuint 就是正整形, 和C里面的unsigned int 一樣。
Vertex Buffer Object (VBO)
創(chuàng)建VBO需要3個步驟:
使用glGenBuffers() 請求OpenGL ES 為圖形處理器控制的緩存書城一個獨(dú)一無二的標(biāo)識符。
使用glBindBuffer() 告訴OpenGL ES為接下來的運(yùn)算使用一個緩存。
使用glBufferData() 讓OpenGL ES 為當(dāng)前捆綁的緩存分配并初始化足夠的連續(xù)內(nèi)存。
void glGenBuffersARB(GLsizei n, GLuint* ids)
glGenBuffersARB() 創(chuàng)建(一個或多個)緩沖區(qū)對象并返回這些對象的標(biāo)示符。該函數(shù)包括兩個參數(shù):第一個是欲創(chuàng)建緩沖區(qū)對象的個數(shù),第二個是用于存儲(一個或多個)緩沖區(qū)標(biāo)示符的數(shù)組地址(標(biāo)示符為GLuint類型)
void glBindBufferARB(GLenum target, GLuint id)
一旦緩沖區(qū)對象被建立,在使用它之前我們需要使用該函數(shù)將其與一個真實的緩沖區(qū)空間綁定。glBindBufferARB()有兩個參數(shù):target和ID。
Target作為一個標(biāo)示符,告訴VBO該緩沖區(qū)對象是存儲頂點數(shù)組數(shù)據(jù)(GL_ARRAY_BUFFER_ARB)還是索引數(shù)據(jù)(GL_ELEMENT_ARRAY_BUFFER_ARB)。
任何頂點的屬性,包括頂點坐標(biāo)、紋理坐標(biāo)、法向量和顏色分量數(shù)組都需要使用GL_ARRAY_BUFFER_ARB。在glDrawElements()或glRangeElements()里會用到的索引數(shù)組此處必須使用GL_ELEMENT_ARRAY_BUFFER_ARB。注意到這里的target實際上協(xié)助VBO決定了存儲相應(yīng)緩沖區(qū)對象的最高效區(qū)域,比如某些系統(tǒng)會將索引存儲在AGP或者系統(tǒng)內(nèi)存中,而頂點會存儲在顯存中。
一旦glBindBufferARB()被首次調(diào)用,VBO會首先在內(nèi)存中賦予一個大小為0的緩沖區(qū)空間,并隨后初始化VBO狀態(tài),比如用途和可操作性。
void glBufferDataARB(GLenum target, GLsizei size, const void* data, GLenum usage)
當(dāng)緩沖區(qū)對象被初始化后,你可以使用glBufferDataARB將數(shù)據(jù)拷貝進(jìn)緩沖區(qū)對象。該函數(shù)有四個參量。與前一個函數(shù)相同,第一個參量只能從GL_ARRAY_BUFFER_ARB或者GL_ELEMENT_ARRAY_BUFFER_ARB中選擇。Size代表欲復(fù)制數(shù)據(jù)的總字節(jié)數(shù)。第三個參量是指向該源數(shù)據(jù)數(shù)組的指針;如果該指針為NULL,則VBO會在內(nèi)存中開辟出一塊size大小的空間。最后一個參量usage是另一個傳遞給VBO的標(biāo)示符,用來決定該緩沖區(qū)對象如何使用:static, dynamic 還是 stream,和read, copy 和 draw。
VBO允許usage標(biāo)示符取以下9種值:
GL_STATIC_DRAW_ARB
GL_STATIC_READ_ARB
GL_STATIC_COPY_ARB
GL_DYNAMIC_DRAW_ARB
GL_DYNAMIC_READ_ARB
GL_DYNAMIC_COPY_ARB
GL_STREAM_DRAW_ARB
GL_STREAM_READ_ARB
GL_STREAM_COPY_ARB
"Static”意味著VBO中的數(shù)據(jù)不會被改變(一次修改,多次使用),"dynamic”意味著數(shù)據(jù)可以被頻繁修改(多次修改,多次使用),"stream”意味著數(shù)據(jù)每幀都不同(一次修改,一次使用)。"Draw”意味著數(shù)據(jù)將會被送往GPU進(jìn)行繪制,"read”意味著數(shù)據(jù)會被用戶的應(yīng)用讀取,"copy”意味著數(shù)據(jù)會被用于繪制和讀取。注意在使用VBO時,只有draw是有效的,而copy和read主要將會在像素緩沖區(qū)(PBO)和幀緩沖區(qū)(FBO)中發(fā)揮作用。
系統(tǒng)會根據(jù)usage標(biāo)示符為緩沖區(qū)對象分配最佳的存儲位置,比如系統(tǒng)會為GL_STATIC_DRAW_ARB和GL_STREAM_DRAW_ARB分配顯存,GL_DYNAMIC_DRAW_ARB分配AGP,以及任何_READ_相關(guān)的緩沖區(qū)對象都會被存儲到系統(tǒng)或者AGP中因為這樣數(shù)據(jù)更容易讀寫。
sizeof()
在 Pascal 語言中,sizeof() 是一種內(nèi)存容量度量函數(shù),功能是返回一個變量或者類型的大小(以字節(jié)為單位);在 C 語言中,sizeof() 是一個判斷數(shù)據(jù)類型或者表達(dá)式長度的運(yùn)算符。
在Pascal 語言與C語言中,對 sizeof() 的處理都是在編譯階段進(jìn)行。
glVertexAttribPointer()
glVertexAttribPointer(<#GLuint indx#>, <#GLint size#>, <#GLenum type#>, <#GLboolean normalized#>, <#GLsizei stride#>, <#const GLvoid *ptr#>)
//傳遞數(shù)據(jù)
//1:傳遞是什么數(shù)據(jù)?這里是頂點位置數(shù)據(jù)GLKVertexAttribPosition
//2:數(shù)據(jù)的大小(每個點的數(shù)據(jù)個數(shù),我們每個點只有xy2個值所以是2,如果做三維的話還有z坐標(biāo),那么就是3)
//3:頂點的數(shù)據(jù)類型,我們定義的是GLfloat數(shù)組所以是GL_FLOAT,如果用int定義頂點那么就是GL_INT.。。
//4:這個。。一般都是GL_FALSE
//5:跨度值,簡單來講,就是隔多少個值取一個點。假如設(shè)為1(這個1不是真正的1,因為跨度是按內(nèi)存空間來算的),
//就是1個單位,那么我們就只能取到1,3,5.。。24被跨過去了。這個在使用頂點結(jié)構(gòu)體的時候會有用,現(xiàn)在設(shè)為0
//6:數(shù)據(jù)的地址,就是數(shù)組的名字 (這個解析是錯的)
glDrawArrays
該方法原型:
glDrawArrays(int mode, int first,int count)
參數(shù)1:有三種取值
1.GL_TRIANGLES:每三個頂之間繪制三角形,之間不連接
2.GL_TRIANGLE_FAN:以V0V1V2,V0V2V3,V0V3V4,……的形式繪制三角形
3.GL_TRIANGLE_STRIP:順序在每三個頂點之間均繪制三角形。這個方法可以保證從相同的方向上所有三角形均被繪制。以V0V1V2,V1V2V3,V2V3V4……的形式繪制三角形
參數(shù)2:從數(shù)組緩存中的哪一位開始繪制,一般都定義為0
參數(shù)3:頂點的數(shù)量
主要代碼如下:
- (void)viewDidLoad {
[super viewDidLoad];
[self initContext];
[self initImageVertexAndBuffer];
[self initTexture];
}
- (void)initContext {
//新建OpenGLES 上下文 并且配置環(huán)境
self.mContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
GLKView * view = (GLKView *)self.view;
view.context = self.mContext;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888; //顏色緩沖區(qū)格式
[EAGLContext setCurrentContext:self.mContext];
}
- (void)initImageVertexAndBuffer {
//頂點數(shù)組,前三個是頂點坐標(biāo),后面兩個是紋理坐標(biāo)
GLfloat imageVertexArray[] = {
0.5, -0.5, 0.0f, 1.0f, 0.0f, //右下
0.5, 0.5, -0.0f, 1.0f, 1.0f, //右上
-0.5, 0.5, 0.0f, 0.0f, 1.0f, //左上
0.5, -0.5, 0.0f, 1.0f, 0.0f, //右下
-0.5, 0.5, 0.0f, 0.0f, 1.0f, //左上
-0.5, -0.5, 0.0f, 0.0f, 0.0f, //左下
};
//頂點數(shù)據(jù)緩存
GLuint buffer;
//創(chuàng)建一個緩沖區(qū)
glGenBuffers(1, &buffer);
//綁定
glBindBuffer(GL_ARRAY_BUFFER, buffer);
//初始化并為緩存分配內(nèi)存
glBufferData(GL_ARRAY_BUFFER, sizeof(imageVertexArray), imageVertexArray, GL_STATIC_DRAW);
//頂點緩存
//glEnableVertexAttribArray() 告訴OpenGL ES 接下來的渲染中是否使用緩存中的數(shù)據(jù);
glEnableVertexAttribArray(GLKVertexAttribPosition);
//glVertexAttribPointer() 告訴OpenGL ES 在緩存中的數(shù)據(jù)類型和所有需要訪問的數(shù)據(jù)內(nèi)存偏移值
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 0);
//紋理緩存
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 3);
}
- (void)initTexture {
NSString * filePath = [[NSBundle mainBundle] pathForResource:@"for_test" ofType:@"jpg"];
//GLKTextureLoaderOriginBottomLeft 紋理坐標(biāo)系是相反的
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
//GLKTextureLoader讀取圖片,創(chuàng)建紋理GLKTextureInfo
GLKTextureInfo * tureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
self.mEffect = [[GLKBaseEffect alloc]init];
self.mEffect.texture2d0.enabled = GL_TRUE;
self.mEffect.texture2d0.name = tureInfo.name;
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
//定義清除屏幕的顏色(即屏幕的背景色,因為屏幕可能殘留其他數(shù)據(jù),不清屏的話說不定看到花瓶哦)
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
//上面只是定義了要用什么顏色清理屏幕,這里才是真正的掃地工人!
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//啟動著色器
[self.mEffect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 6);
}
一下函數(shù)的解析:

image.png
此demo對落影大神的基礎(chǔ)上加上更多的注釋和體會。