<h5>1蔗包、先上效果圖</h5>
<h5>2、背景知識</h5>
- OpenGL ES(OpenGL for Embedded Systems)是OpenGL三維圖形API的子集剔蹋,針對手機(jī)催烘、PDA和游戲主機(jī)等嵌入式設(shè)備而設(shè)計的。
- OpenGL ES只能繪制點浪感、線段和三角形
- GLKit 框架是為了簡化iOS上OpenGL ES的開發(fā),提供的基于OpenGL ES的iOS框架。
- GLKit 中重要的類:GLKViewController & GLKView & GLKBaseEffect矫付、GLKReflectionMapEffect舰始、GLKSkyboxEffect Class等。
- 紋理:姑且認(rèn)為是個小圖片
- 紋理坐標(biāo): 在x和y軸上峻堰,范圍為0到1之間(注意我們使用的是2D紋理圖像)讹开。紋理坐標(biāo)起始于(0, 0),也就是紋理圖片的左下角捐名,終始于(1, 1)旦万,即紋理圖片的右上角。
<h5>3镶蹋、代碼實現(xiàn)主要思路(以繪制圖片為例成艘,繪制三角形代碼比較簡單,見項目源碼)</h5>
1)創(chuàng)建OpenGL ES上下文
2)設(shè)置頂點數(shù)據(jù)信息
3)創(chuàng)建著色器效果贺归,并啟動著色器
- 實現(xiàn)GLKViewDelegate代理方法淆两,繪制圖片到屏幕
<h5>4、重要代碼說明<h5>
- 需要引用框架#import <GLKit/GLKit.h>
- 使用GLKit展示所在的ViewController需要繼承GLKViewController
- 設(shè)置好頂點信息數(shù)組 和 頂點索引數(shù)組
//設(shè)置頂點信息數(shù)組
const GLfloat Vertices[] = {
0.5, -0.5, 0.0f, 1.0f, 0.0f, //右下(x,y,z坐標(biāo) + s,t紋理)
-0.5, 0.5, 0.0f, 0.0f, 1.0f, //左上
-0.5, -0.5, 0.0f, 0.0f, 0.0f, //左下
0.5, 0.5, 0.0f, 1.0f, 1.0f, //右上
};
//設(shè)置頂點索引數(shù)組
const GLuint indices[] = {
0,1,2,
1,3,0
};
<h6>4.1拂酣、重要代碼說明 之 創(chuàng)建OpenGL ES上下文<h6>
/**
設(shè)置OpenGL ES上下文
*/
- (void)setupContext{
self.context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(@"Failed to initialize OpenGLES 2.0 context");
exit(1);
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
//顏色緩沖區(qū)格式
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
//self.context為OpenGL的"當(dāng)前激活的Context"秋冰。之后所有"GL"指令均作用在這個Context上。
if (![EAGLContext setCurrentContext:self.context]) {
NSLog(@"Failed to set current OpenGL context");
exit(1);
}
}
說明
- 只要使用OpenGL婶熬,總需要這個 EAGLContext對象丹莲,EAGLContext對象管理所有通過OpenGL進(jìn)行draw的信息
- 這里使用OpenGL ES 2.0的API
- 簡單的容錯處理
<h6>4.2、重要代碼說明 之 設(shè)置頂點數(shù)據(jù)信息</h6>
- (void)setupVBOs{
/** VBO : 頂點緩存區(qū)對象
兩種頂點緩存類型:一種是用于跟蹤每個頂點信息的(Vertices)尸诽,另一種是用于跟蹤組成每個三角形的索引信息(我們的Indices)
*/
GLuint verticesBuffer;
glGenBuffers(1, &verticesBuffer);
glBindBuffer(GL_ARRAY_BUFFER, verticesBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
GLuint indicesBuffer;
glGenBuffers(1, &indicesBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//啟動
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
//為vertex shader的兩個輸入?yún)?shù)(Position 和 TexCoord)配置兩個合適的值
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
}
重要函數(shù)說明
*1甥材、 glGenBuffers (GLsizei n, GLuint buffers) **
創(chuàng)建一個緩存對象
2、glBindBuffer (GLenum target, GLuint buffer)
激活緩沖對象性含,buffer指向target洲赵,target可以是GL_ARRAY_BUFFER(坐標(biāo),顏色 等)、GL_ELEMENT_ARRAY_BUFFER (索引坐標(biāo))或者GL_TEXTURE_BUFFER(紋理緩沖)
*3叠萍、glBufferData (GLenum target, GLsizeiptr size, const GLvoid data, GLenum usage) **
用數(shù)據(jù)分配和初始化緩沖區(qū)對象 ,demo中usage使用GL_STATIC_DRAW (預(yù)先指定辅鲸,只寫1次,可讀n次)
DRAW: 客戶機(jī)指定了用于渲染的數(shù)據(jù)
READ:從OPENGL緩沖區(qū)讀取數(shù)據(jù)值,并且在應(yīng)用程序中用于各種魚渲染不直接相關(guān)的計算過程
COPY:從OPENGL緩沖區(qū)讀取數(shù)據(jù)值,作為用于渲染的數(shù)據(jù)
STREAM:緩沖區(qū)對象中數(shù)據(jù)需要經(jīng)常更新,但是作為繪圖或其他操作使用較少
STATIC:緩沖區(qū)數(shù)據(jù)只指定1次,但是這些數(shù)據(jù)使用頻率非常高
DYNAMIC:緩沖區(qū)數(shù)據(jù)常常更新管行,并且使用頻率也很高
4、glEnableVertexAttribArray (GLuint index)
開啟對應(yīng)的頂點屬性(坐標(biāo),紋理坐標(biāo),顏色等)
5、glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid ptr)*
為頂點屬性(坐標(biāo),紋理坐標(biāo)狂秘,顏色等)配置合適的值
//參數(shù)1:GLuint indx 聲明這個屬性的名稱
//參數(shù)2:GLint size定義這個屬性由多少個值組成清女。譬如說position是由3個GLfloat組成
//參數(shù)3: GLenum type聲明每一個值是什么類型。我們都用了GL_FLOAT
//參數(shù)4:GLboolean normalized , GL_FALSE就好了
//參數(shù)5:GLsizei stride stride的大小卦方,描述每個vertex數(shù)據(jù)的大小
//參數(shù)6:const GLvoid* ptr , 數(shù)據(jù)結(jié)構(gòu)的偏移量。從這個結(jié)構(gòu)中哪里開始獲取值。
//Position的值在前面擒贸,所以傳(GLfloat *)NULL + 0進(jìn)去就可以了案淋。
//而TexCoord是緊接著位置的數(shù)據(jù)誉碴,而position的大小是3個float的大小,所以是從(GLfloat *)NULL + 3開始的
<h6>4.3瓣距、重要代碼說明 之 創(chuàng)建著色器效果</h6>
//創(chuàng)建著色器效果
- (void)setupBaseEffect{
//GLKTextureLoader讀取圖片黔帕,創(chuàng)建紋理GLKTextureInfo
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"ic_dog" ofType:@"jpeg"];
//GLKTextureLoaderOriginBottomLeft 參數(shù)是避免紋理上下顛倒,原因是紋理坐標(biāo)系和世界坐標(biāo)系的原點不同蹈丸。
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], GLKTextureLoaderOriginBottomLeft, nil];
//加載圖片
GLKTextureInfo* textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
// 創(chuàng)建著色器GLKBaseEffect蹬屹,把紋理賦值給著色器
self.mEffect = [[GLKBaseEffect alloc] init];
self.mEffect.texture2d0.enabled = GL_TRUE;
self.mEffect.texture2d0.name = textureInfo.name;
//啟動著色器
[self.mEffect prepareToDraw];
}
<h6>4.4侣背、重要代碼說明 之 繪制圖片到屏幕</h6>
#pragma mark - GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
// 清屏
glClearColor(0.3f, 0.6f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 繪制
// self.mCount = sizeof(indices) / sizeof(indices[0]);
glDrawElements(GL_TRIANGLES, self.mCount, GL_UNSIGNED_INT, 0);
}
函數(shù)
glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid indices)*
//繪制,在每個vertex上調(diào)用我們的vertex shader慨默,每個像素調(diào)用fragment shader贩耐。
//參數(shù)1:聲明用哪種特性來渲染圖形。有GL_LINE_STRIP厦取、GL_TRIANGLE_FAN和GL_TRIANGLE等潮太。然而GL_TRIANGLE(三角形)最常用。
//參數(shù)2: 告訴渲染器有多少個圖形要渲染虾攻。
//參數(shù)3: 指每個indices中的index類型,GL_UNSIGNED_INT
//參數(shù)4:它是一個指向indices的指針铡买。已經(jīng)存入緩存,這里不需要了.
<h5>5霎箍、思考</h5>
1奇钞、為什么繪制出來的三角形,矩形(圖片的幾何位置)的高比寬長漂坏。
答: 雖然本例中景埃,三角形、矩形在純數(shù)學(xué)的OpenGL ES坐標(biāo)系中顶别,長和寬是相等的谷徙。但是在本例中,幀緩存是按像素來匹配屏幕尺寸的驯绎。在渲染時候完慧,GPU會轉(zhuǎn)換 純數(shù)學(xué)的OpenGL ES坐標(biāo)系的X、Y剩失、Z坐標(biāo)為幀緩存中所對應(yīng)的真實像素位置屈尼。幀緩存中的像素位置叫做視口(viewport)坐標(biāo)。轉(zhuǎn)換為視口坐標(biāo)的后果就是:所繪制的集合圖形被拉伸以適應(yīng)屏幕大小拴孤,也就是高比寬大了脾歧。
代碼直通車:QSOpenGLES001