OpenGL ES 案例02:GLKit繪制立方體+旋轉(zhuǎn)

本案例是實(shí)現(xiàn)一個(gè)有紋理的立方體,并根據(jù)任意軸旋轉(zhuǎn),整體效果如下

  • 未加光照

    image
  • 增加光照效果

    image

增加光照的主要的思路如下

image

代碼的實(shí)現(xiàn)主要分為4部分:

  • 準(zhǔn)備工作:這部分主要的相關(guān)庫(kù)的導(dǎo)入及屬性的創(chuàng)建(這里不做過多闡述)
  • ViewDidLoad函數(shù):初始化OpenGL ES相關(guān)屬性怀挠,加載頂點(diǎn)&紋理坐標(biāo)數(shù)據(jù)巴比,以及設(shè)置定時(shí)器
  • GLKViewDelegate函數(shù):視圖的繪制
  • update函數(shù):定時(shí)器方法即横,計(jì)算旋轉(zhuǎn)角度并修改矩陣堆棧,重新渲染立方體苹享,以實(shí)現(xiàn)立方體的旋轉(zhuǎn)

ViewDidLoad函數(shù)

這部分主要是一些初始化工作

  • commonInit: OpenGL ES相關(guān)初始化
  • setupVertex: 加載頂點(diǎn)&紋理坐標(biāo)數(shù)據(jù)
  • addCADisplayLink: 添加定時(shí)器

commonInit函數(shù)

OpenGL ES初始化分為五部分:

  • 初始化上下文 & 設(shè)置當(dāng)前上下文
  • 創(chuàng)建GLKView對(duì)象,并設(shè)置context挣菲,加入view中
  • 配置深度緩沖區(qū)
  • 獲取紋理圖片 & 設(shè)置紋理參數(shù)
  • 初始化effect富稻,并使用effect
  • OC
- (void) commonInit{
//    1掷邦、創(chuàng)建context
    EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    [EAGLContext setCurrentContext:context];

//    2、創(chuàng)建GLKView并設(shè)置代理
    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;

//    3椭赋、使用深度測(cè)試
    self.glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;

//    4抚岗、將glkView加入到view上
    [self.view addSubview:self.glkView];

//    5、獲取紋理圖片
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"mouse" ofType:@"jpg"];
    UIImage *image = [UIImage imageWithContentsOfFile:filePath];

//    6哪怔、設(shè)置紋理參數(shù)(紋理倒置翻轉(zhuǎn)的策略)
    NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft: @(YES)};
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:[image CGImage] options:options error:NULL];

//    7宣蔚、使用effect
    self.baseEffect = [[GLKBaseEffect alloc] init];
    self.baseEffect.texture2d0.name = textureInfo.name;
    self.baseEffect.texture2d0.target = textureInfo.target;

}

setupVertex函數(shù)

這部分主要是設(shè)置頂點(diǎn)數(shù)據(jù)(頂點(diǎn)坐標(biāo) & 紋理坐標(biāo) & 法線),并將這些數(shù)據(jù)從CPU拷貝至GPU

設(shè)置頂點(diǎn)數(shù)據(jù)
下圖是立方體的頂點(diǎn)坐標(biāo)與紋理坐標(biāo)圖示

image

其中6個(gè)面與紋理的映射關(guān)系如下

image

頂點(diǎn)數(shù)據(jù)使用結(jié)構(gòu)體定義

  • OC版本
typedef struct {
    GLKVector3 positionCoord;   //頂點(diǎn)坐標(biāo)
    GLKVector2 textureCoord;    //紋理坐標(biāo)
    GLKVector3 normal;          //法線
} CCVertex;

//初始化--這里數(shù)據(jù)的初始化方式是c語(yǔ)言中的結(jié)構(gòu)體賦值
(CCVertex){{-0.5, 0.5, 0.5}, {0, 1}, {0, 0, 1}};

頂點(diǎn)數(shù)據(jù)的具體代碼見完整demo代碼认境,這里不做過多說明

開辟緩存區(qū)胚委,copy頂點(diǎn)數(shù)據(jù)到GPU
將頂點(diǎn)數(shù)據(jù)從內(nèi)存(CPU)拷貝至顯存(GPU)中
頂點(diǎn)緩沖區(qū):簡(jiǎn)稱VBO
頂點(diǎn)數(shù)組:簡(jiǎn)稱VAO
glBufferData中確認(rèn)了緩存區(qū)的大小

  • OC版本
    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(CCVertex)*kCoordCount, self.vertices, GL_STATIC_DRAW);

打開通道
attribute的開關(guān)在ios中是默認(rèn)關(guān)閉的,需要使用代碼手動(dòng)開啟叉信,同時(shí)通道需要打開三次(頂點(diǎn)亩冬,紋理,法線各需要打開一次)硼身,將頂點(diǎn)數(shù)據(jù)從顯存中讀取到GLKit的著色器中

  • OC版本
    其中的NULL是可以省略的硅急,但是加上代碼可讀性強(qiáng)
//    頂點(diǎn)數(shù)據(jù)
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(CCVertex), NULL+offsetof(CCVertex, positionCoord));

//    紋理數(shù)據(jù)
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(CCVertex), NULL+offsetof(CCVertex, textureCoord));

//    光照
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(CCVertex), NULL+offsetof(CCVertex, normal));

addCADisplayLink函數(shù)

初始化定時(shí)器,并將定時(shí)器加入runloop中佳遂,用于立方體旋轉(zhuǎn)效果的實(shí)現(xiàn)

  • OC版本
- (void)addCADisplayLink{

    self.angle = 0;
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

}

update更新

CADisplayLink定時(shí)器的刷新的頻率與屏幕刷新頻率一致营袜,每次刷新都需要計(jì)算旋轉(zhuǎn)角度,并應(yīng)用于立方體

  • OC版本
- (void) update{
    //計(jì)算旋轉(zhuǎn)度數(shù)
    self.angle = (self.angle +5) % 360;
//    修改baseEffect.transform.modelviewMatrix
    self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeRotation(GLKMathDegreesToRadians(self.angle), 0.3, 1, 0.7);

//    重新渲染
    [self.glkView display];
}

GLKViewDelegate代理

由于GLKView是自定義的丑罪,所以需要在前面設(shè)置delegate荚板,當(dāng)然也可以將控制器默認(rèn)的view的父類改為GLKView,不需要設(shè)置delegate

代理方法的主要目的是繪制視圖的內(nèi)容吩屹,并根據(jù)定時(shí)器的旋轉(zhuǎn)變換跪另,重新渲染視圖

  • OC版本
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{

//    開啟深度測(cè)試
    glEnable(GL_DEPTH_TEST);

//    清除緩存區(qū)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//    準(zhǔn)備繪制
    [self.baseEffect prepareToDraw];

//    繪圖(數(shù)組繪制)
    glDrawArrays(GL_TRIANGLES, 0, kCoordCount);

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市煤搜,隨后出現(xiàn)的幾起案子罚斗,更是在濱河造成了極大的恐慌,老刑警劉巖宅楞,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件针姿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡厌衙,警方通過查閱死者的電腦和手機(jī)距淫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來婶希,“玉大人榕暇,你說我怎么就攤上這事。” “怎么了彤枢?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵狰晚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我缴啡,道長(zhǎng)壁晒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任业栅,我火速辦了婚禮秒咐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碘裕。我一直安慰自己携取,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布帮孔。 她就那樣靜靜地躺著雷滋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪文兢。 梳的紋絲不亂的頭發(fā)上惊豺,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音禽作,去河邊找鬼。 笑死揩页,一個(gè)胖子當(dāng)著我的面吹牛旷偿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播爆侣,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼萍程,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了兔仰?” 一聲冷哼從身側(cè)響起茫负,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乎赴,沒想到半個(gè)月后忍法,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡榕吼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年饿序,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羹蚣。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡原探,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咽弦,我是刑警寧澤徒蟆,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站型型,受9級(jí)特大地震影響段审,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜输莺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一戚哎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嫂用,春花似錦型凳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至往弓,卻和暖如春疏唾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背函似。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工槐脏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撇寞。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓顿天,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蔑担。 傳聞我的和親對(duì)象是個(gè)殘疾皇子牌废,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355