OpnGL的初識

前言

開發(fā)OpenGL App一年多了, 平時就是在各種趕項目, 趕功能; 做了不少筆記, 踩了不少坑, 但是僅僅是工作需要就去學習哪塊, 很少靜下來做總結;

今年年春換了一家東家, 開發(fā)直播類App, 需要視頻處理等知識, 正好總結一番;

目前發(fā)現,在OpenGL的世界里 相對于渲染管線來說, 數學才是真正的大頭;

相比于復雜的理論知識, 我們直接手上吧.


  • 本文環(huán)境

    • Xcode 9.0

    • OpenGLES 3.0

基本操作步驟

  • 導入GLKit框架

  • 直接集成GLKViewController, 或者GLKView

  • 創(chuàng)建OpenGL上下文 EAGLContext

  • 創(chuàng)建程序對象ShaderProgram

    • 連接頂點著色器片段著色器
  • 指定清屏顏色,填充到ColorBuffer


導入框架, 直接集成與GLKViewController

#import <GLKit/GLKit.h>

@interface ViewController : GLKViewController

@end

創(chuàng)建OpenGL 上下文

  • EAGLContext
    • 調度中樞

    • 保存繪制命令, 狀態(tài), 資源所有調度;

    • 因為OpenGL 是狀態(tài)機機制, 故需要一個調度中樞的存在

    • 這里直接使用OpenGLES 3.0

#pragma mark - setupContext
- (void)setupContext {
    
    // 1.0 創(chuàng)建OpenGl上下文
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    
#if DEBUG
    if (!self.context) {
        NSLog(@"Create OpenGLES3.0 context fail.");
    }
#endif
}
  • 設置Context為當前上下文, 并傳遞到glview
[EAGLContext setCurrentContext:self.context];
 
GLKView *glView = (GLKView *)self.view;
glView.context = self.context;

創(chuàng)建程序對象Program

  • 創(chuàng)建頂點著色器, 片段著色器

    • 著色器最終以字符串的形式傳遞到program

    • 下面是最簡單的兩個著色器, 有影響即可, 暫無需深入

創(chuàng)建glsl
著色器
  • 頂點著色器Vertxt.glsl
// 頂點著色器

// 輸入變量
attribute vec4 position;
attribute vec4 color;

// 輸出變量
varying vec4 fragColor;

void main(void) {
    
    // 傳遞到片段著色器
    fragColor = color;
    
    // 內建變量
    gl_Position = position;
}
  • 片段著色器Fragment.glsl
// 片段著色器

varying lowp vec4 fragColor;

void main(void) {

    // 內建變量
    gl_FragColor = fragColor;
}
  • 創(chuàng)建program固定套路

    • 創(chuàng)建program

    • 加載著色器, 并關聯到program

    • 鏈接porgram

    • 釋放shader資源

GLuint program, vertShader, fragShader;
    
// 創(chuàng)建program
program = glCreateProgram();

// 加載shader (頂點著色器, 片段著色器)
*shader = glCreateShader(type);    
glShaderSource(*shader, 1, &source, NULL);
glCompileShader(*shader);

// 關聯著色器到program
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);

// 鏈接programe
glLinkProgram(program);

// 釋放shader資源
glDetachShader(program, vertShader);
glDeleteShader(vertShader);

glDetachShader(program, fragShader);
glDeleteShader(fragShader);

渲染

  • 實現GLKViewDelegate代理方法

    • 該方法會被定時調用默認是1s/60幀
  • 設置清屏顏色

#pragma mark - GLKViewDelegate
- (void)update {
    
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    
    // 設置清屏顏色, 并填充到colorBuffer
    glClearColor(0.0, 0.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
}

全流程已經實現, 運行即可.

題外話, 如果對上述一些關鍵名字不甚理解的話, 也無妨; 大概有個影響即可;

畢竟后面見多了, 也就熟悉了.


Others

除了使用GLKViewController, 是否還有其他方法?

當然, 還可以直接使用UIViewController, 重寫- (void)loadView方法, 返回GLKView.

- (void)loadView {
    self.view = [[GLKView alloc] initWithFrame:[UIScreen mainScreen].bounds];
}

- (void)setupGLKView {
    GLKView *glView = (GLKView *)self.view;
    
    // 此時需設置代理, 如果是`GLKViewController`已經默認設置代理為本身, 如`UITablviewController`
    glView.delegate = self;
    glView.context = self.context;
}

// 其他和使用`GLKViewController`一致
  • 此時發(fā)現代理方法只會執(zhí)行一次

    • 需創(chuàng)建定時器, 重復調用代理方法
const NSInteger DefaultFramesPerSecond = 30;

// 手動刷新
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(draw)];
[self.displayLink setPreferredFramesPerSecond:MAX(1, 60.0f / DefaultFramesPerSecond)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

- (void)draw {
    GLKView *glView = (GLKView *)self.view;
    [self update];
    
    // 不能手動調用`- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect`; 需調用`display`
    [glView display];
}

一層層往下扒的話, 發(fā)現真正用來渲染的是CAEAGLLayer;

GLKViewCAEAGLLayer做了一層封裝;

GLKViewControllerGLKView做了一層封裝, 設置自身為GLKView代理;

蘋果到底對GLKView做什么?

首先是GLKView的layer是CAEAGLLayer

+ (Class)layerClass {

    // OpenGL在iOS中,只能在CAEAGLLayer類型的layer上繪制內容
    return [CAEAGLLayer class];
}
// 設置layer的屬性
- (void)setupLayer{

    _eaglLayer = (CAEAGLLayer *)self.layer;
    
    // 設置layer為不透明, 其默認為透明
    _eaglLayer.opaque = YES;
    
    // 設置繪制屬性
    _eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithBool:NO],
                                     kEAGLDrawablePropertyRetainedBacking,
                                     kEAGLColorFormatRGBA8,
                                     kEAGLDrawablePropertyColorFormat,
                                     nil];
}
  • 創(chuàng)建一個FrameBuffer, 并關聯ColorBuffer
// 設置渲染buffer, RenderBuffer分為三大模塊: colorBuffer, depthBuffer, stencilBuffer
- (void)setupRenderBuffer {

    // 創(chuàng)建1個buffer, 返回的id不為0, 0為系統保留
    glGenRenderbuffers(1, &_colorBuffer);
    
    // 綁定buffer為當前渲染緩沖對象
    glBindRenderbuffer(GL_RENDERBUFFER, _colorBuffer);
    
    // 為_colorBuffer分配存儲空間
    [self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}

// 創(chuàng)建幀緩存對象(framebuffer object), FBO
- (void)setupFrameBuffer {
    
    // 創(chuàng)建framebuffer
    glGenFramebuffers(1, &_frameBuffer); 
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    
    // 將_colorBuffer到裝配到FBO的GL_COLOR_ATTACHMENT0裝配點上
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorBuffer);
    
}
  • 渲染

    • 將當前context指定的colorBuffer渲染到屏幕
- (void)renderTest {

    // 設置清屏顏色R, G, B, A
    glClearColor(0.0, 1.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 將context中指定的buffer渲染到屏幕上
    [self.context presentRenderbuffer:GL_RENDERBUFFER];
}
  • 運行結果
運行結果

目前OpnGL狀況

WWDC 18已經把OpnGL 相關API標記為棄用; 說不定什么時候就被移除掉了, 蘋果正大力推薦自己的Metal;

前段時間, 看過Metal相關知識, 發(fā)現有OpenGL經驗能較好上手, 而且無論是Directx11還是OpenGL, Metal圖像渲染流程, 數學運用手段都是一樣的;

為甚么還要學習OpenGL?
Swift一般, OpenGL API什么時候才會真正被棄用?
市面上OpenGL學習書籍以及論壇相比于Metal更豐富, 完善以及面向新手.

對于紅寶書OpenGL編程指南, 藍寶書OpenGL超級寶典;
藍寶書雖然事無巨細,但更面向新手;
而紅寶書默認你熟悉整個渲染管線流程;


后續(xù)會陸續(xù)發(fā)布其他文章, 如果有錯誤, 還請指正;

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末喉钢,一起剝皮案震驚了整個濱河市绒障,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異债沮,居然都是意外死亡,警方通過查閱死者的電腦和手機本鸣,發(fā)現死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門疫衩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荣德,你說我怎么就攤上這事隧土。” “怎么了命爬?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵曹傀,是天一觀的道長。 經常有香客問我饲宛,道長皆愉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任艇抠,我火速辦了婚禮幕庐,結果婚禮上,老公的妹妹穿的比我還像新娘家淤。我一直安慰自己异剥,他們只是感情好,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布絮重。 她就那樣靜靜地躺著冤寿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪青伤。 梳的紋絲不亂的頭發(fā)上督怜,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音狠角,去河邊找鬼号杠。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的姨蟋。 我是一名探鬼主播屉凯,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼眼溶!你這毒婦竟也來了悠砚?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤偷仿,失蹤者是張志新(化名)和其女友劉穎哩簿,沒想到半個月后宵蕉,有當地人在樹林里發(fā)現了一具尸體酝静,經...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年羡玛,在試婚紗的時候發(fā)現自己被綠了别智。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡稼稿,死狀恐怖薄榛,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情让歼,我是刑警寧澤敞恋,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站谋右,受9級特大地震影響硬猫,放射性物質發(fā)生泄漏。R本人自食惡果不足惜改执,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一啸蜜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辈挂,春花似錦衬横、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拇泣,卻和暖如春悉尾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挫酿。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工构眯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人早龟。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓惫霸,卻偏偏與公主長得像猫缭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子壹店,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359