iOS全景圖片之OpenGL學(xué)習(xí)筆記

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視圖

GLKView_diagram_2x.png

如圖所示,概述了繪制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)系”就是用右手茸塞,如下圖所示:

“左手坐標(biāo)系”和“右手坐標(biāo)系”.png

在iOS開發(fā)中躲庄,屏幕左上角是坐標(biāo)原點(diǎn),往右是x軸正方向钾虐,往下是y軸正方向噪窘。而在OpenGL ES中,屏幕的中點(diǎn)是坐標(biāo)原點(diǎn)效扫,往右是x軸正方向倔监,往下是y軸正方向,其中z軸的正方向是從屏幕往外的方向菌仁,如下圖所示:

OpenGL ES坐標(biāo)系.png

根據(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)和寬并不相等吉执。

頂點(diǎn)坐標(biāo)和紋理坐標(biāo).png

OpenGL ES不能繪制多邊形,只能繪制點(diǎn)地来,線戳玫,三角形,OpenGL可以繪制多邊形未斑,由于我們繪制的圖片是一個(gè)矩形量九,又兩個(gè)三角形構(gòu)成,就是下圖中的兩個(gè)頂點(diǎn)索引(0颂碧,1,3)和(1类浪,2载城,3)組成的三角形拼成一個(gè)矩形。

頂點(diǎn)索引.png
- (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è)值)

啟用頂點(diǎn)數(shù)組和指定頂點(diǎn)屬性.png

上面的程序最需要注意的是變量的偏移很重要角撞,如果把GLfloat寫成CGFloat呛伴,會(huì)導(dǎo)致圖片渲染不出來。

參考文獻(xiàn):
http://www.reibang.com/p/23e938fab9ca
http://www.reibang.com/p/954339d57541

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谒所,一起剝皮案震驚了整個(gè)濱河市热康,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌劣领,老刑警劉巖姐军,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異尖淘,居然都是意外死亡奕锌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門村生,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惊暴,“玉大人,你說我怎么就攤上這事趁桃×苫埃” “怎么了肄鸽?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)油啤。 經(jīng)常有香客問我,道長(zhǎng)益咬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任础废,我火速辦了婚禮,結(jié)果婚禮上评腺,老公的妹妹穿的比我還像新娘。我一直安慰自己蒿讥,他們只是感情好蝶念,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布媒殉。 她就那樣靜靜地躺著,像睡著了一般摔敛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上马昙,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音行楞,去河邊找鬼攒暇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛子房,可吹牛的內(nèi)容都是我干的形用。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼证杭,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼田度!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起解愤,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤每币,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后琢歇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兰怠,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年李茫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了揭保。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡魄宏,死狀恐怖秸侣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宠互,我是刑警寧澤味榛,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站予跌,受9級(jí)特大地震影響搏色,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜券册,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一频轿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烁焙,春花似錦航邢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至九火,卻和暖如春赚窃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吃既。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工考榨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鹦倚。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓河质,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親震叙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容