在上一篇文章中, 我們學(xué)習(xí)了OpenGL ES中的一些基本概念, 從這篇文章開始, 將一起學(xué)習(xí), 如何通過OpenGL ES去渲染圖形.
一、GLKit
GLKit是iOS 5引入的一個(gè)為簡(jiǎn)化OpenGL ES的使用的框架,它對(duì)OpenGL ES的函數(shù)進(jìn)行了封裝并提供了相關(guān)的類和函數(shù),GLKit是Cocoa Touch以及多個(gè)其他的框架(包含UIKit)的一部分。而GLKView和GLKViewController類名字中的GLK前綴表明這些類是GLKit框架的一部分。
今天學(xué)習(xí)如何用GLView來渲染一張圖片:
1. 獲取頂點(diǎn)數(shù)據(jù)
首先定義一個(gè)結(jié)構(gòu)體,用來保存頂點(diǎn)數(shù)據(jù). 用一個(gè)三維向量來保存(x,y,z)坐標(biāo), 一個(gè)二維向量來保存(u,v)坐標(biāo)
/**
定義頂點(diǎn)類型
*/
typedef struct {
GLKVector3 positionCoord; // (X, Y, Z)
GLKVector2 textureCoord; // (U, V)
} CustomVertexInfo;
定義一個(gè)頂點(diǎn)數(shù)組, 來保存4個(gè)頂點(diǎn):
@property (nonatomic, assign) CustomVertexInfo *verticesArray; //!< 頂點(diǎn)數(shù)組
初始化頂點(diǎn)數(shù)據(jù):
self.verticesArray = malloc(sizeof(CustomVertexInfo) * 4);
self.verticesArray[0] = (CustomVertexInfo){{-1, 1, 0}, {0, 1}}; //!< 左上角
self.verticesArray[1] = (CustomVertexInfo){{-1, -1, 0}, {0, 0}}; //!< 左下角
self.verticesArray[2] = (CustomVertexInfo){{1, 1, 0}, {1, 1}}; //!< 右上角
self.verticesArray[3] = (CustomVertexInfo){{1, -1, 0}, {1, 0}}; //!< 右下角
2. 初始化GLKView, 設(shè)置EAGLContext上下文
//!< 初始化 GLKView
CGRect frame = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.width);
self.glkView = [[GLKView alloc] initWithFrame:frame context:context];
self.glkView.backgroundColor = [UIColor clearColor];
self.glkView.delegate = self;
[self.view addSubview:self.glkView];
//!< 設(shè)置 glkView 的上下文為當(dāng)前上下文
[EAGLContext setCurrentContext:self.glkView.context];
3. 獲取圖片, 并用GLKTextureLoader來加載紋理數(shù)據(jù)
//!< 通過 GLKTextureLoader 來加載紋理,并存放在 GLKBaseEffect 中
NSString *imagePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"example.jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft : @(YES)}; //!< 消除 UIKit 和 GLKit 的坐標(biāo)差異,否則會(huì)上下顛倒
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:[image CGImage]
options:options
error:NULL];
4. 用GLKBaseEffect保存紋理id
self.baseEffect = [[GLKBaseEffect alloc] init];
self.baseEffect.texture2d0.name = textureInfo.name;
self.baseEffect.texture2d0.target = textureInfo.target;
5. 實(shí)現(xiàn)GLKView的代理方法- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect, 并在代理方法中按照上一篇文章中的使用緩存的7個(gè)步驟, 來繪制圖片
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
[self.baseEffect prepareToDraw];
//!< 創(chuàng)建頂點(diǎn)緩存
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer); // !< 1:生成
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); // !< 2:綁定
GLsizeiptr bufferSizeBytes = sizeof(CustomVertexInfo) * 4;
glBufferData(GL_ARRAY_BUFFER, bufferSizeBytes, self. verticesArray, GL_STATIC_DRAW); // !< 3:緩存數(shù)據(jù)
//!< 設(shè)置頂點(diǎn)數(shù)據(jù)
glEnableVertexAttribArray(GLKVertexAttribPosition); // !< 4:?jiǎn)⒂没蚪? glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(CustomVertexInfo), NULL + offsetof(CustomVertexInfo, positionCoord)); // !< 5:設(shè)置指針
//!< 設(shè)置紋理數(shù)據(jù)
glEnableVertexAttribArray(GLKVertexAttribTexCoord0); // !< 4:?jiǎn)⒂没蚪? glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(CustomVertexInfo), NULL + offsetof(CustomVertexInfo, textureCoord)); // !< 5:設(shè)置指針
//!< 開始繪制
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // !< 6:繪圖
//!< 刪除頂點(diǎn)緩存
glDeleteBuffers(1, &vertexBuffer); // !< 7:刪除
vertexBuffer = 0;
}
6. dealloc時(shí)釋放內(nèi)存, 清空EAGLContext當(dāng)前上下文
- (void)dealloc {
if ([EAGLContext currentContext] == self.glkView.context) {
[EAGLContext setCurrentContext:nil];
}
if (_verticesArray) {
free(_verticesArray);
_verticesArray = nil;
}
}
最終效果如圖:

GLKViewRender