OpenGL日常-紋理幀圖(上)

大家好敌呈,歡迎來到聽風(fēng)的OpenGL日常刺洒。

寫在前面

本文主要代碼

上篇主要講OpenGLES FrameBuffer的使用捍岳;理解本篇主要理解下面這幅圖前鹅,所以文中會(huì)再出現(xiàn)一次:

002.png

快速添加到View

我們要自己渲染頁(yè)面毒租,建一個(gè)單視圖的App赘被,接下來創(chuàng)建一個(gè)TFGLView:UIView悴侵,令該View指針指向視圖控制的view瞧剖;

@interface ViewController ()
@property (nonatomic, strong) TFGLView* mView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.mView = (TFGLView*)self.view;
}
@end

添加OpenGLES上下文

OpenGLES在iOS端有自己的實(shí)現(xiàn),直接在Build Phases里添加:

001.png

TFGLView里引用,這里我們使用ES2.0版本:

#import <OpenGLES/ES2/gl.h>

OpenGLES繪制在View的特殊圖層CAEAGLLayer:CALayer上抓于,由于它是CALayer的子類做粤,所以直接更改ViewlayerClass

+(Class)layerClass
{
    return [CAEAGLLayer class];
}

同修改VC的view類似,我們也要對(duì)layer作修改捉撮,設(shè)置全局layer屬性:

@property(nonatomic,strong)CAEAGLLayer *myEagLayer;

另外我們需要獲取上下文來保存OpenGL的狀態(tài):

@property(nonatomic,strong)EAGLContext *myContext;

接下來在layoutSubviews方法中我們?cè)O(shè)置圖層以及上下文怕品;

  1. 圖層
-(void)setupLayer
{
    self.myEagLayer = (CAEAGLLayer *)self.layer;
    /*
     kEAGLDrawablePropertyRetainedBacking 表示繪圖表面顯示后,是否保留其內(nèi)容
     kEAGLDrawablePropertyColorFormat 可繪制表面的內(nèi)部顏色緩存區(qū)格式.
     這個(gè)key對(duì)應(yīng)的值是一個(gè)NSString指定特定顏色緩存區(qū)對(duì)象,默認(rèn)是kEAGLColorFormatRGBA8
     */
    self.myEagLayer.drawableProperties = @{
        kEAGLDrawablePropertyRetainedBacking:@false,
        kEAGLDrawablePropertyColorFormat:kEAGLColorFormatRGBA8
    };
}

這里注意下layer的drawableProperties屬性巾遭,之后具體用到了再修改肉康;

  1. 上下文
-(void)setupContext
{
    //1.指定OpenGL ES 渲染API版本,我們使用2.0
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
    //2.創(chuàng)建圖形上下文
    EAGLContext *context = [[EAGLContext alloc]initWithAPI:api];
    //3.判斷是否創(chuàng)建成功
    if (!context) {
        NSLog(@"Create context failed!");
        return;
    }
    //4.設(shè)置圖形上下文
    if (![EAGLContext setCurrentContext:context]) {
        NSLog(@"setCurrentContext failed!");
        return;
    }
    //5.將局部context灼舍,變成全局的
    self.myContext = context;
}

進(jìn)入GL渲染部分(本文主要部分)

完成了以上環(huán)境設(shè)置吼和,就可以進(jìn)入正式OpenGLES環(huán)節(jié),在此之前我們要先認(rèn)識(shí)兩個(gè)緩沖區(qū)骑素;

兩個(gè)緩沖區(qū)

這篇文章我們要用這兩個(gè)緩沖區(qū)來完成操作炫乓,先來了解一下這兩個(gè)緩沖區(qū):

在應(yīng)用程序調(diào)用OpenGLES之前,都要?jiǎng)?chuàng)建一個(gè)上下文和一個(gè)繪圖表面献丑,而在EAGL末捣、GLFW、GLAD等中都默認(rèn)提供了一個(gè)上下文和繪圖表面(即幀緩沖區(qū))阳距;

  • frame buffer object
    Frame Buffer Object(FBO)擴(kuò)展塔粒,被推薦用于把數(shù)據(jù)渲染到紋理對(duì)象,即綁定到紋理對(duì)象筐摘;用于寫入顏色值的顏色緩沖卒茬、用于寫入深度信息的深度緩沖和允許我們根據(jù)一些條件丟棄特定片段的模板緩沖。這些緩沖結(jié)合起來叫做幀緩沖(Framebuffer)咖熟,它被儲(chǔ)存在內(nèi)存中圃酵。OpenGL允許我們定義我們自己的幀緩沖,也就是說我們能夠定義我們自己的顏色緩沖馍管,甚至是深度緩沖和模板緩沖郭赐。
    對(duì)于這個(gè)對(duì)象的理解,我們現(xiàn)在可能并不能很好的感知确沸,具體到實(shí)際場(chǎng)景會(huì)更好理解捌锭,之后遇到就更清楚了,今天我們用它來渲染紋理罗捎。
    可參考:OpenGL FrameBuffer Object
    framebuffer是幀緩沖對(duì)象观谦,它是一個(gè)容器,但是自身不能用于渲染桨菜,需要與一些可渲染的緩沖區(qū)綁定在一起豁状,像紋理或者渲染緩沖區(qū)捉偏。
    在OpenGL渲染管線中,幾何數(shù)據(jù)和紋理經(jīng)過一系列的測(cè)試最終以2d像素圖渲染到屏幕上泻红,最終的渲染目的地就叫做幀緩沖區(qū)夭禽。它是由一些OpenGL操作的2d數(shù)組和存儲(chǔ)空間組成。這個(gè)緩沖區(qū)完全的由窗口系統(tǒng)創(chuàng)建和管理谊路,這個(gè)默認(rèn)的緩沖區(qū)就叫做“窗口系統(tǒng)提供的”緩沖區(qū)讹躯。

  • render buffer
    可參考:RenderBuffer
    RenderBuffer為顏色、深度和模板緩沖值提供了附著點(diǎn)凶异,而RenderBuffer又被附加到幀緩沖蜀撑。這樣幀緩沖才具有了操作深度信息能力。(為了記憶可以理解為為幀緩沖打開了對(duì)應(yīng)的測(cè)試)

001.png

上面兩個(gè)緩沖區(qū)及緩沖區(qū)對(duì)象的關(guān)系大致如下圖:

002.png

清空緩沖區(qū)

我們需要添加兩個(gè)標(biāo)識(shí)用來獲取RenderBuffer和FrameBuffer:

@property(nonatomic,assign)GLuint colorRenderBuffer;
@property(nonatomic,assign)GLuint colorFrameBuffer;

清空緩沖區(qū)操作:

- (void)clearBuffers
{
    glDeleteBuffers(1, &_colorFrameBuffer);
    self.colorFrameBuffer = 0;
    
    glDeleteBuffers(1, &_colorRenderBuffer);
    self.colorRenderBuffer = 0;
}

設(shè)置RenderBuffer

生成渲染緩沖區(qū)剩彬,并保存在全局變量中:

GLuint buffer;
glGenRenderbuffers(1, &buffer);
self.colorRenderBuffer = buffer;

將標(biāo)識(shí)符綁定到渲染緩存:

glBindRenderbuffer(GL_RENDERBUFFER, buffer);

將渲染緩存綁定到OpenGLES上:

[self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];

而對(duì)于不使用EAGL的情況酷麦,則需要:

glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);

上面這段代碼創(chuàng)建了一個(gè)800*600的模板緩沖對(duì)象用于將模板緩沖綁定在RenderBuffer上;

設(shè)置FrameBuffer

同樣喉恋,設(shè)置幀緩存對(duì)象沃饶,并綁定到幀緩存:

GLuint buffer;
glGenFramebuffers(1, &buffer);
self.colorFrameBuffer = buffer;

glBindFramebuffer(GL_FRAMEBUFFER, buffer);

接下來就是建立RenderBuffer與FrameBuffer的聯(lián)系,將RBO附著在FBO的GL_COLOR_ATTACHMENT0上:

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, buffer);

設(shè)置著色器程序

本篇直接給出著色器程序轻黑,有關(guān)于著色器的用法見04-Shader糊肤;
頂點(diǎn)著色器shader.vsh

attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main()
{
    varyTextCoord = textCoordinate;
    gl_Position = position;
}

片元著色器shader.fsh

precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{
    //lowp vec4 temp = texture2D(colorMap, varyTextCoord);
    //gl_FragColor = temp;
    
    gl_FragColor = texture2D(colorMap, varyTextCoord);

}

將生成寫成一個(gè)函數(shù):

- (GLuint)genShader:(NSString *)file :(GLenum)type
{
    NSString* content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
    const GLchar* source = (GLchar *)[content UTF8String];
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);
    
    return shader;
}

生成并編譯著色器:

//頂點(diǎn)著色器
NSString *vertFile = [[NSBundle mainBundle]pathForResource:@"shaderv" ofType:@"vsh"];
GLuint vShader = [self genShader:vertFile :GL_VERTEX_SHADER];

//片元著色器
NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"];
GLuint fShader = [self genShader:fragFile :GL_FRAGMENT_SHADER];

生成著色器程序,并把編譯好的著色器附著在其上:

GLuint program = glCreateProgram();
glAttachShader(program, vShader);
glAttachShader(program, fShader);
//鏈接到程序后就可以刪除著色器了氓鄙,這是個(gè)好習(xí)慣
glDeleteShader(vShader);
glDeleteShader(fShader);

繪制

前面的準(zhǔn)備工作已經(jīng)完成馆揉,接下來開始正式開始繪制紋理;我們將在一個(gè)drawTexture完成

- (void)drawTexture
{
    //
}

渲染背景

//設(shè)置清屏顏色
glClearColor(0.3f, 0.45f, 0.5f, 1.0f);
//清除屏幕
glClear(GL_COLOR_BUFFER_BIT);

鏈接并檢查著色器程序

GLuint program = [self setupProgram];
glLinkProgram(program);

鏈接后需要對(duì)程序做檢查抖拦,如果有錯(cuò)誤升酣,則我們?nèi)菀锥ㄎ恢鞒鲥e(cuò)的細(xì)節(jié):

GLint linkStatus;
//獲取鏈接狀態(tài)
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) {
    GLchar message[512];
    glGetProgramInfoLog(program, sizeof(message), 0, &message[0]);
    NSString *messageString = [NSString stringWithUTF8String:message];
    NSLog(@"Program Link Error:%@",messageString);
    return;
}

見下篇

下篇

最后編輯于
?著作權(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
  • 序言:老撾萬(wàn)榮一對(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