OpenGL版本
在開發(fā)OpenGL項(xiàng)目前失球,需要根據(jù)業(yè)務(wù)需求選擇合適的版本簿透。在初始化EAGLContext時(shí)指定ES版本號(hào)妒蛇。
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
EAGLContext
與UIKit中CGContextRef相似菱属,EAGLContext相當(dāng)于OpenGL繪制句柄或者上下文引瀑,在繪制試圖之前,需要指定使用創(chuàng)建的上下文繪制
[EAGLContextsetCurrentContext:view.context];
創(chuàng)建和配置GLKit視圖
可以以編程方式或使用Interface Builder創(chuàng)建和配置GLKView對(duì)象州藕。在使用它繪制之前束世,必須將其與EAGLContext對(duì)象相關(guān)聯(lián)。
- 以編程方式創(chuàng)建視圖時(shí)床玻,首先創(chuàng)建上下文毁涉,然后將其傳遞給視圖的initWithFrame:context:方法。
- 從故事板加載視圖后锈死,創(chuàng)建上下文并將其設(shè)置為視圖的上下文屬性的值贫堰。
GLKit視圖會(huì)自動(dòng)創(chuàng)建和配置自己的OpenGL ES framebuffer對(duì)象和renderbuffers〈#可以使用視圖的可繪制屬性來控制這些對(duì)象的屬性其屏。如果更改GLKit視圖的大小,比例因子或可繪制屬性洲敢,則會(huì)在下次繪制內(nèi)容時(shí)自動(dòng)刪除并重新創(chuàng)建相應(yīng)的framebuffer對(duì)象和renderbuffers漫玄。
繪制GLKit視圖
如圖所示,概述了繪制OpenGL ES內(nèi)容的三個(gè)步驟:準(zhǔn)備OpenGL ES基礎(chǔ)設(shè)施压彭,發(fā)布繪圖命令展蒂,并將呈現(xiàn)的內(nèi)容呈現(xiàn)給Core Animation進(jìn)行顯示摩窃。 GLKView類實(shí)現(xiàn)了第一和第三步。對(duì)于第二步,您將實(shí)現(xiàn)一個(gè)繪圖方法和措,如下代碼中的示例所示。
- (void)drawRect:(CGRect)rect
{
// Clear the framebuffer
glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw using previously configured texture, shader, uniforms, and vertex array
glBindTexture(GL_TEXTURE_2D, _planetTexture);
glUseProgram(_diffuseShading);
glUniformMatrix4fv(_uniformModelViewProjectionMatrix, 1, 0, _modelViewProjectionMatrix.m);
glBindVertexArrayOES(_planetMesh);
glDrawElements(GL_TRIANGLE_STRIP, 256, GL_UNSIGNED_SHORT);
}
注意:glClear函數(shù)提示OpenGL ES可以丟棄任何現(xiàn)有的幀緩沖區(qū)內(nèi)容悠夯,避免了昂貴的內(nèi)存操作將以前的內(nèi)容加載到內(nèi)存中是晨。為了確保最佳性能,您應(yīng)該在繪制之前始終調(diào)用此函數(shù)健蕊。
定義要繪制圖片的頂點(diǎn)坐標(biāo)和紋理坐標(biāo)
OpenGL ES中坐標(biāo)系是和iOS常用的Quartz 2D坐標(biāo)系是不一樣的菱阵,Quartz 2D坐標(biāo)系屬于右手坐標(biāo)系,OpenGL ES屬于左手坐標(biāo)系缩功。先說一下左手坐標(biāo)系和右手坐標(biāo)系晴及。
伸出左手,讓拇指和食指成“L”形狀嫡锌,拇指向右虑稼,食指向上,中指指向起那方势木,這時(shí)就建立了一個(gè)“左手坐標(biāo)系”蛛倦,拇指、食指和中指分表代表x啦桌、y溯壶、z軸的正方向。“右手坐標(biāo)系”就是用右手茸塞,如下圖所示:
在iOS開發(fā)中躲庄,屏幕左上角是坐標(biāo)原點(diǎn),往右是x軸正方向钾虐,往下是y軸正方向噪窘。而在OpenGL ES中,屏幕的中點(diǎn)是坐標(biāo)原點(diǎn)效扫,往右是x軸正方向倔监,往下是y軸正方向,其中z軸的正方向是從屏幕往外的方向菌仁,如下圖所示:
根據(jù)OpenGL ES的坐標(biāo)系浩习,我們定義一下要繪制的圖片的幾個(gè)頂點(diǎn),頂點(diǎn)坐標(biāo)和紋理坐標(biāo)是放在一個(gè)GLfloat數(shù)組中管理的济丘,定義一組頂點(diǎn)數(shù)據(jù)的跨度為5谱秽,其中前三個(gè)存儲(chǔ)頂點(diǎn)坐標(biāo),后兩個(gè)存儲(chǔ)紋理坐標(biāo)摹迷,下圖一共定義了4個(gè)頂點(diǎn)疟赊,就是矩形的四個(gè)頂點(diǎn),需要注意的是峡碉,雖然坐標(biāo)都是0.5近哟,但是繪制出來的圖形并不是正方形,因?yàn)槲覀冇脕碜罱K顯示的是iPhone屏幕鲫寄,手機(jī)的長(zhǎng)和寬并不相等吉执。
OpenGL ES不能繪制多邊形,只能繪制點(diǎn)地来,線戳玫,三角形,OpenGL可以繪制多邊形未斑,由于我們繪制的圖片是一個(gè)矩形量九,又兩個(gè)三角形構(gòu)成,就是下圖中的兩個(gè)頂點(diǎn)索引(0颂碧,1,3)和(1类浪,2载城,3)組成的三角形拼成一個(gè)矩形。
- (void)setupOpenGL {
[EAGLContext setCurrentContext:_context];
glEnable(GL_DEPTH_TEST);
// 頂點(diǎn)
GLfloat *vVertices = NULL;
// 紋理
GLfloat *vTextCoord = NULL;
// 索引
GLushort *indices = NULL;
int numVertices = 0;
_numIndices = esGenSphere(200, 1.0, &vVertices, &vTextCoord, &indices, &numVertices);
// 加載頂點(diǎn)索引數(shù)據(jù)
// 創(chuàng)建索引buffer并將indices的數(shù)據(jù)放入
glGenBuffers(1, &_vertexIndicesBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexIndicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _numIndices*sizeof(GLushort), indices, GL_STATIC_DRAW);
// 加載頂點(diǎn)坐標(biāo)
// 創(chuàng)建頂點(diǎn)buffer并將vVertices中的數(shù)據(jù)放入
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices*3*sizeof(GLfloat), vVertices, GL_STATIC_DRAW);
//設(shè)置頂點(diǎn)屬性,對(duì)頂點(diǎn)的位置费就,顏色诉瓦,坐標(biāo)進(jìn)行賦值
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, NULL);
// 創(chuàng)建紋理buffer并將vTextCoord數(shù)據(jù)放入
glGenBuffers(1, &_vertexTexCoord);
glBindBuffer(GL_ARRAY_BUFFER, _vertexTexCoord);
glBufferData(GL_ARRAY_BUFFER, numVertices*2*sizeof(GLfloat), vTextCoord, GL_DYNAMIC_DRAW);
//設(shè)置紋理屬性,對(duì)紋理的位置,顏色,坐標(biāo)進(jìn)行賦值
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*2, NULL);
// 將圖片轉(zhuǎn)換成為紋理信息
NSString *imagePath = [[NSBundle mainBundle] pathForResource:self.imageName ofType:self.imageNameType];
// 由于OpenGL的默認(rèn)坐標(biāo)系設(shè)置在左下角, 而GLKit在左上角, 因此需要轉(zhuǎn)換
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],
GLKTextureLoaderOriginBottomLeft,
nil];
_textureInfo = [GLKTextureLoader textureWithContentsOfFile:imagePath options:options error:nil];
// 設(shè)置著色器的紋理
_effect = [[GLKBaseEffect alloc] init];
_effect.texture2d0.enabled = GL_TRUE;
_effect.texture2d0.name = _textureInfo.name;
}
//啟用頂點(diǎn)位置(坐標(biāo))數(shù)組睬澡,之前說過opengl是狀態(tài)機(jī)固额,需要什么狀態(tài)就啟動(dòng)什么狀態(tài)
glEnableVertexAttribArray(GLKVertexAttribPosition);
GLfloat vertexs[] = {
-0.5, -0.5, 0, 0.0, 0.0, //左下
-0.5, 0.5, 0, 0.0, 1.0, //左上
0.5, 0.5, 0, 1.0, 1.0, //右上
0.5, -0.5, 0, 1.0, 0.0, //右下
};
啟用通用頂點(diǎn)屬性
/*
index:指定通用頂點(diǎn)數(shù)據(jù)的索引,這個(gè)值的范圍從0到支持的最大頂點(diǎn)屬性數(shù)量減1
功能:用于啟用通用頂點(diǎn)屬性
*/
void glEnableVertexAttribArray(GLuint index);
禁止通用頂點(diǎn)屬性
/*
index:指定通用頂點(diǎn)數(shù)據(jù)的索引煞聪,這個(gè)值的范圍從0到支持的最大頂點(diǎn)屬性數(shù)量減1
*/
void glDisableVertexAttribArray(GLuint index);
頂點(diǎn)數(shù)組設(shè)置值
index: 通用頂點(diǎn)屬性索引
size: 頂點(diǎn)數(shù)組中為頂點(diǎn)屬性指定的分量數(shù)量斗躏,取值范圍1~4
type: 數(shù)據(jù)格式 ,兩個(gè)函數(shù)都包括的有效值是
GL_BYTE GL_UNSIGNED_BYTE GL_SHORT GL_UNSIGNED_SHORT GL_INT GL_UNSIGNED_INT
glVertexAttribPointer還包括的值為:GL_HALF_FLOAT GL_FLOAT 等
normalized: 僅glVertexAttribPointer使用昔脯,表示非浮點(diǎn)數(shù)據(jù)類型轉(zhuǎn)換成浮點(diǎn)值時(shí)是否應(yīng)該規(guī)范化
stride: 每個(gè)頂點(diǎn)由size指定的頂點(diǎn)屬性分量順序存儲(chǔ)啄糙。stride指定頂點(diǎn)索引i和i+1表示的頂點(diǎn)之間的偏移。
如果為0云稚,表示順序存儲(chǔ)隧饼。如果不為0,在取下一個(gè)頂點(diǎn)的同類數(shù)據(jù)時(shí)静陈,需要加上偏移燕雁。
ptr: 如果使用“頂點(diǎn)緩沖區(qū)對(duì)象”,表示的是該緩沖區(qū)內(nèi)的偏移量鲸拥。
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *ptr);
// 取值為“整數(shù)”版本
void glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *ptr);
這里由于我們使用iOS封裝好的GLkit框架拐格,不需要我們?cè)O(shè)置著色器程序,里面有內(nèi)置的設(shè)置好的index位置崩泡,就是下面的變量:
typedef NS_ENUM(GLint, GLKVertexAttrib)
{
GLKVertexAttribPosition,
GLKVertexAttribNormal,
GLKVertexAttribColor,
GLKVertexAttribTexCoord0,
GLKVertexAttribTexCoord1
} NS_ENUM_AVAILABLE(10_8, 5_0);
GLKit里面的GLKVertexAttribPosition和GLKVertexAttribTexCoord0分別表示頂點(diǎn)坐標(biāo)和紋理坐標(biāo)兩個(gè)變量的屬性索引禁荒。(頂點(diǎn)索引不是頂點(diǎn)數(shù)據(jù),這里我們不需要管這個(gè)值)
上面的程序最需要注意的是變量的偏移很重要角撞,如果把GLfloat寫成CGFloat呛伴,會(huì)導(dǎo)致圖片渲染不出來。
參考文獻(xiàn):
http://www.reibang.com/p/23e938fab9ca
http://www.reibang.com/p/954339d57541