本篇主要講解GPUImage底層是如何渲染的,GPUImage底層使用的是OPENGL,操控GPU來實(shí)現(xiàn)屏幕展示
一、由于網(wǎng)上OpenGL實(shí)戰(zhàn)資料特別少,官方文檔對(duì)一些方法也是解釋不清楚,我通過查找一些博客,文檔整理相關(guān)的知識(shí)如下,有些不到位的地方希望大家指教,我虛心學(xué)習(xí)
二、GPUImageVideoCamera
可以捕獲采集的視頻數(shù)據(jù)
關(guān)鍵是捕獲到一幀一幀視頻數(shù)據(jù)如何展示?
通過這個(gè)方法可以獲取采集的視頻數(shù)據(jù)
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
采集視頻注意點(diǎn):要設(shè)置采集豎屏,否則獲取的數(shù)據(jù)是橫屏
通過AVCaptureConnection就可以設(shè)置
[connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
三、自定義OpenGLView渲染視頻? //以下的一些采集原理GPUImage框架GPUImageMovieWriter基本封裝的比較好了(直接查看GPUImageMovieWriter方法也行),下面是講的是采集到視頻的幀數(shù)據(jù) 渲染實(shí)現(xiàn)的原理和步驟
暴露一個(gè)接口,獲取采集到的幀數(shù)據(jù),然后把幀數(shù)據(jù)傳遞給渲染View,展示出來
- (void)displayFramebuffer:(CMSampleBufferRef)sampleBuffer;
四、利用OpenGL渲染幀數(shù)據(jù)并顯示
導(dǎo)入頭文件#import ,GLKit.h底層使用了OpenGLES,導(dǎo)入它,相當(dāng)于自動(dòng)導(dǎo)入了OpenGLES
步驟
01-自定義圖層類型
02-初始化CAEAGLLayer圖層屬性(可以參考GPUImageView里面的內(nèi)容)
03-創(chuàng)建EAGLContext
04-創(chuàng)建渲染緩沖區(qū)
05-創(chuàng)建幀緩沖區(qū)
06-創(chuàng)建著色器
07-創(chuàng)建著色器程序
08-創(chuàng)建紋理對(duì)象
09-YUV轉(zhuǎn)RGB繪制紋理
10-渲染緩沖區(qū)到屏幕
11-清理內(nèi)存
01-自定義圖層類型
為什么要自定義圖層類型CAEAGLLayer? CAEAGLLayer是OpenGL專門用來渲染的圖層,使用OpenGL必須使用這個(gè)圖層
#pragma mark - 1.自定義圖層類型
+ (Class)layerClass
{
return [CAEAGLLayer class];
}
02-初始化CAEAGLLayer圖層屬性
1.不透明度(opaque)=YES,CALayer默認(rèn)是透明的,透明性能不好,最好設(shè)置為不透明.
2.設(shè)置繪圖屬性
kEAGLDrawablePropertyRetainedBacking :NO (告訴CoreAnimation不要試圖保留任何以前繪制的圖像留作以后重用)
kEAGLDrawablePropertyColorFormat :kEAGLColorFormatRGBA8 (告訴CoreAnimation用8位來保存RGBA的值)
其實(shí)設(shè)置不設(shè)置都無所謂,默認(rèn)也是這個(gè)值,只不過GPUImage設(shè)置了
#pragma mark - 2.初始化圖層
- (void)setupLayer
{
CAEAGLLayer *openGLLayer = (CAEAGLLayer *)self.layer;
_openGLLayer = openGLLayer;
// 設(shè)置不透明,CALayer 默認(rèn)是透明的,透明性能不好,最好設(shè)置為不透明.
openGLLayer.opaque = YES;
// 設(shè)置繪圖屬性drawableProperties
// kEAGLColorFormatRGBA8 : red、green、blue、alpha共8位
openGLLayer.drawableProperties = @{
kEAGLDrawablePropertyRetainedBacking :[NSNumber numberWithBool:NO],
kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8
};
}
03-創(chuàng)建EAGLContext
需要將它設(shè)置為當(dāng)前context,所有的OpenGL ES渲染默認(rèn)渲染到當(dāng)前上下文
EAGLContext管理所有使用OpenGL ES進(jìn)行描繪的狀態(tài),命令以及資源信息,要繪制東西,必須要有上下文,跟圖形上下文類似。
當(dāng)你創(chuàng)建一個(gè)EAGLContext,你要聲明你要用哪個(gè)version的API。這里,我們選擇OpenGL ES 2.0
#pragma mark - 3、創(chuàng)建OpenGL上下文,并且設(shè)置上下文
- (void)setupContext
{
// 指定OpenGL 渲染 API 的版本,目前都使用 OpenGL ES 2.0
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
// 創(chuàng)建EAGLContext上下文
_context = [[EAGLContext alloc] initWithAPI:api];
// 設(shè)置為當(dāng)前上下文,所有的渲染默認(rèn)渲染到當(dāng)前上下文
[EAGLContext setCurrentContext:_context];
}
04-創(chuàng)建渲染緩沖區(qū)
有了上下文,openGL還需要在一塊buffer進(jìn)行描繪,這塊buffer就是RenderBuffer
OpenGLES 總共有三大不同用途的color buffer,depth buffer 和 stencil buffer.
最基本的是color buffer,創(chuàng)建它就好了
函數(shù)glGenRenderbuffers
函數(shù) void glGenRenderbuffers (GLsizei n, GLuint* renderbuffers)
它是為renderbuffer(渲染緩存)申請(qǐng)一個(gè)id(名字),創(chuàng)建渲染緩存
參數(shù)n表示申請(qǐng)生成renderbuffer的個(gè)數(shù)
參數(shù)renderbuffers返回分配給renderbuffer(渲染緩存)的id
。 注意:返回的id不會(huì)為0,id 0 是OpenGL ES保留的,我們也不能使用id 為0的renderbuffer(渲染緩存)。
函數(shù)glBindRenderbuffer
void glBindRenderbuffer (GLenum target, GLuint renderbuffer)
告訴OpenGL:我在后面引用GL_RENDERBUFFER的地方,其實(shí)是引用_colorRenderBuffer
參數(shù)target必須為GL_RENDERBUFFER
參數(shù)renderbuffer就是使用glGenRenderbuffers生成的id
。 當(dāng)指定id的renderbuffer第一次被設(shè)置為當(dāng)前renderbuffer時(shí),會(huì)初始化該 renderbuffer對(duì)象,其初始值為:
width 和 height:像素單位的寬和高,默認(rèn)值為0;
internal format:內(nèi)部格式,三大 buffer 格式之一 -- color,depth or stencil;
Color bit-depth:僅當(dāng)內(nèi)部格式為 color 時(shí),設(shè)置顏色的 bit-depth,默認(rèn)值為0;
Depth bit-depth:僅當(dāng)內(nèi)部格式為 depth時(shí),默認(rèn)值為0;
Stencil bit-depth: 僅當(dāng)內(nèi)部格式為 stencil,默認(rèn)值為0
函數(shù)renderbufferStorage
EAGLContext方法 - (BOOL)renderbufferStorage:(NSUInteger)target fromDrawable:(id)drawable
把渲染緩存(renderbuffer)綁定到渲染圖層(CAEAGLLayer)上,并為它分配一個(gè)共享內(nèi)存。
參數(shù)target,為哪個(gè)renderbuffer分配存儲(chǔ)空間
參數(shù)drawable,綁定在哪個(gè)渲染圖層,會(huì)根據(jù)渲染圖層里的繪圖屬性生成共享內(nèi)存。
//? ? 底層調(diào)用這個(gè)分配內(nèi)存
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, _openGLLayer.bounds.size.width, _openGLLayer.bounds.size.height);
實(shí)戰(zhàn)代碼
#pragma mark - 4、創(chuàng)建渲染緩存
- (void)setupRenderBuffer
{
glGenRenderbuffers(1, &_colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
// 把渲染緩存綁定到渲染圖層上CAEAGLLayer,并為它分配一個(gè)共享內(nèi)存。
// 并且會(huì)設(shè)置渲染緩存的格式,和寬度
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_openGLLayer];
}
05-創(chuàng)建幀緩沖區(qū)
它相當(dāng)于buffer(color, depth, stencil)的管理者,三大buffer可以附加到一個(gè)framebuffer上
本質(zhì)是把framebuffer內(nèi)容渲染到屏幕
函數(shù)glFramebufferRenderbuffer
void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
該函數(shù)是將相關(guān)buffer()三大buffer之一)attach到framebuffer上,就會(huì)自動(dòng)把渲染緩存的內(nèi)容填充到幀緩存,在由幀緩存渲染到屏幕
參數(shù)target,哪個(gè)幀緩存
參數(shù)attachment是指定renderbuffer被裝配到那個(gè)裝配點(diǎn)上,其值是GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT中的一個(gè),分別對(duì)應(yīng) color,depth和 stencil三大buffer。
renderbuffertarget:哪個(gè)渲染緩存
renderbuffer渲染緩存id
#pragma mark - 5、創(chuàng)建幀緩沖區(qū)
- (void)setupFrameBuffer
{
glGenFramebuffers(1, &_framebuffers);
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffers);
// 把顏色渲染緩存 添加到 幀緩存的GL_COLOR_ATTACHMENT0上,就會(huì)自動(dòng)把渲染緩存的內(nèi)容填充到幀緩存,在由幀緩存渲染到屏幕
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
}
06-創(chuàng)建著色器
著色器
什么是著色器? 通常用來處理紋理對(duì)象,并且把處理好的紋理對(duì)象渲染到幀緩存上,從而顯示到屏幕上。
提取紋理信息,可以處理頂點(diǎn)坐標(biāo)空間轉(zhuǎn)換,紋理色彩度調(diào)整(濾鏡效果)等操作。
著色器分為頂點(diǎn)著色器,片段著色器
頂點(diǎn)著色器用來確定圖形形狀
片段著色器用來確定圖形渲染顏色
步驟: 1.編輯著色器代碼 2.創(chuàng)建著色器 3.編譯著色器
只要?jiǎng)?chuàng)建一次,可以在一開始的時(shí)候創(chuàng)建
著色器代碼
// 頂點(diǎn)著色器代碼
NSString *const kVertexShaderString = SHADER_STRING
(
attribute vec4 position;
attribute vec2 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate;
}
);
// 片段著色器代碼
NSString *const kYUVFullRangeConversionForLAFragmentShaderString = SHADER_STRING
(
varying highp vec2 textureCoordinate;
precision mediump float;
uniform sampler2D luminanceTexture;
uniform sampler2D chrominanceTexture;
uniform mediump mat3 colorConversionMatrix;
void main()
{
mediump vec3 yuv;
lowp vec3 rgb;
yuv.x = texture2D(luminanceTexture, textureCoordinate).r;
yuv.yz = texture2D(chrominanceTexture, textureCoordinate).ra - vec2(0.5, 0.5);
rgb = colorConversionMatrix * yuv;
gl_FragColor = vec4(rgb, 1);
}
);
實(shí)戰(zhàn)代碼
#pragma mark - 06、創(chuàng)建著色器
- (void)setupShader
{
// 創(chuàng)建頂點(diǎn)著色器
_vertShader = [self loadShader:GL_VERTEX_SHADER withString:kVertexShaderString];
// 創(chuàng)建片段著色器
_fragShader = [self loadShader:GL_FRAGMENT_SHADER withString:kYUVFullRangeConversionForLAFragmentShaderString];
}
// 加載著色器
- (GLuint)loadShader:(GLenum)type withString:(NSString *)shaderString
{
// 創(chuàng)建著色器
GLuint shader = glCreateShader(type);
if (shader == 0) {
NSLog(@"Error: failed to create shader.");
return 0;
}
// 加載著色器源代碼
const char * shaderStringUTF8 = [shaderString UTF8String];
glShaderSource(shader, 1, &shaderStringUTF8, NULL);
// 編譯著色器
glCompileShader(shader);
// 檢查是否完成
GLint compiled = 0;
// 獲取完成狀態(tài)
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (compiled == 0) {
// 沒有完成就直接刪除著色器
glDeleteShader(shader);
return 0;
}
return shader;
}
07-創(chuàng)建著色器程序
步驟: 1.創(chuàng)建程序 2.貼上頂點(diǎn)和片段著色器 3.綁定attribute屬性 4.連接程序 5.綁定uniform屬性 6.運(yùn)行程序
注意點(diǎn):第3步和第5步,綁定屬性,必須有順序,否則綁定不成功,造成黑屏
#pragma mark - 7、創(chuàng)建著色器程序
- (void)setupProgram
{
// 創(chuàng)建著色器程序
_program = glCreateProgram();
// 綁定著色器
// 綁定頂點(diǎn)著色器
glAttachShader(_program, _vertShader);
// 綁定片段著色器
glAttachShader(_program, _fragShader);
// 綁定著色器屬性,方便以后獲取,以后根據(jù)角標(biāo)獲取
// 一定要在鏈接程序之前綁定屬性,否則拿不到
glBindAttribLocation(_program, ATTRIB_POSITION, "position");
glBindAttribLocation(_program, ATTRIB_TEXCOORD, "inputTextureCoordinate");
// 鏈接程序
glLinkProgram(_program);
// 獲取全局參數(shù),注意 一定要在連接完成后才行,否則拿不到
_luminanceTextureAtt = glGetUniformLocation(_program, "luminanceTexture");
_chrominanceTextureAtt = glGetUniformLocation(_program, "chrominanceTexture");
_colorConversionMatrixAtt = glGetUniformLocation(_program, "colorConversionMatrix");
// 啟動(dòng)程序
glUseProgram(_program);
}
08-創(chuàng)建紋理對(duì)象
紋理
采集的是一張一張的圖片,可以把圖片轉(zhuǎn)換為OpenGL中的紋理, 然后再把紋理畫到OpenGL的上下文中
什么是紋理?一個(gè)紋理其實(shí)就是一幅圖像。
紋理映射,我們可以把這幅圖像的整體或部分貼到我們先前用頂點(diǎn)勾畫出的物體上去.
比如繪制一面磚墻,就可以用一幅真實(shí)的磚墻圖像或照片作為紋理貼到一個(gè)矩形上,這樣,一面逼真的磚墻就畫好了。如果不用紋理映射的方法,則墻上的每一塊磚都必須作為一個(gè)獨(dú)立的多邊形來畫。另外,紋理映射能夠保證在變換多邊形時(shí),多邊形上的紋理圖案也隨之變化。
紋理映射是一個(gè)相當(dāng)復(fù)雜的過程,基本步驟如下:
1)激活紋理單元、2)創(chuàng)建紋理 、3)綁定紋理 、4)設(shè)置濾波
注意:紋理映射只能在RGBA方式下執(zhí)行
函數(shù)glTexParameter
void glTexParameter{if}[v](GLenum target,GLenum pname,TYPE param);
{if}:表示可能是否i,f
[v]:表示v可有可無
控制濾波,濾波就是去除沒用的信息,保留有用的信息
一般來說,紋理圖像為正方形或長(zhǎng)方形。但當(dāng)它映射到一個(gè)多邊形或曲面上并變換到屏幕坐標(biāo)時(shí),紋理的單個(gè)紋素很少對(duì)應(yīng)于屏幕圖像上的像素。根據(jù)所用變換和所用紋理映射,屏幕上單個(gè)象素可以對(duì)應(yīng)于一個(gè)紋素的一小部分(即放大)或一大批紋素(即縮小)
固定寫法
/* 控制濾波 */
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
函數(shù)glPixelStorei
void glPixelStorei(GLenum pname, GLint param);
設(shè)置像素存儲(chǔ)方式
pname:像素存儲(chǔ)方式名
一種是GL_PACK_ALIGNMENT,用于將像素?cái)?shù)據(jù)打包,一般用于壓縮。
另一種是GL_UNPACK_ALIGNMENT,用于將像素?cái)?shù)據(jù)解包,一般生成紋理對(duì)象,就需要用到解包.
param:用于指定存儲(chǔ)器中每個(gè)像素行有多少個(gè)字節(jié)對(duì)齊。這個(gè)數(shù)值一般是1、2、4或8,
一般填1,一個(gè)像素對(duì)應(yīng)一個(gè)字節(jié);
函數(shù)CVOpenGLESTextureCacheCreateTextureFromImage
CVOpenGLESTextureCacheCreateTextureFromImage(CFAllocatorRef? _Nullable allocator, CVOpenGLESTextureCacheRef? _Nonnull textureCache, CVImageBufferRef? _Nonnull sourceImage, CFDictionaryRef? _Nullable textureAttributes, GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, size_t planeIndex, CVOpenGLESTextureRef? _Nullable * _Nonnull textureOut)
根據(jù)圖片生成紋理
參數(shù)allocator kCFAllocatorDefault,默認(rèn)分配內(nèi)存
參數(shù)textureCache 紋理緩存
參數(shù)sourceImage 圖片
參數(shù)textureAttributes NULL
參數(shù)target , GL_TEXTURE_2D(創(chuàng)建2維紋理對(duì)象)
參數(shù)internalFormat GL_LUMINANCE,亮度格式
參數(shù)width 圖片寬
參數(shù)height 圖片高
參數(shù)format GL_LUMINANCE 亮度格式
參數(shù)type 圖片類型 GL_UNSIGNED_BYTE
參數(shù)planeIndex 0,切面角標(biāo),表示第0個(gè)切面
參數(shù)textureOut 輸出的紋理對(duì)象
fotmat格式? ? ? ? ? ? ? ? ? ? 描述
GL_ALPHA? ? ? ? ? ? 按照ALPHA值存儲(chǔ)紋理單元
GL_LUMINANCE? ? ? ? 按照亮度值存儲(chǔ)紋理單元
GL_LUMINANCE_ALPHA? ? 按照亮度和alpha值存儲(chǔ)紋理單元
GL_RGB? ? ? ? ? ? ? ? 按照RGB成分存儲(chǔ)紋理單元
GL_RGBA? ? ? ? ? ? ? ? 按照RGBA成分存儲(chǔ)紋理單元
實(shí)戰(zhàn)代碼
#pragma mark - 7、創(chuàng)建紋理對(duì)象,渲染采集圖片到屏幕
- (void)setupTexture:(CMSampleBufferRef)sampleBuffer
{
// 獲取圖片信息
CVImageBufferRef imageBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer);
// 獲取圖片寬度
GLsizei bufferWidth = (GLsizei)CVPixelBufferGetWidth(imageBufferRef);
_bufferWidth = bufferWidth;
GLsizei bufferHeight = (GLsizei)CVPixelBufferGetHeight(imageBufferRef);
_bufferHeight = bufferHeight;
// 創(chuàng)建亮度紋理
// 激活紋理單元0, 不激活,創(chuàng)建紋理會(huì)失敗
glActiveTexture(GL_TEXTURE0);
// 創(chuàng)建紋理對(duì)象
CVReturn err;
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCacheRef, imageBufferRef, NULL, GL_TEXTURE_2D, GL_LUMINANCE, bufferWidth, bufferHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0, &_luminanceTextureRef);
if (err) {
NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}
// 獲取紋理對(duì)象
_luminanceTexture = CVOpenGLESTextureGetName(_luminanceTextureRef);
// 綁定紋理
glBindTexture(GL_TEXTURE_2D, _luminanceTexture);
// 設(shè)置紋理濾波
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// 激活單元1
glActiveTexture(GL_TEXTURE1);
// 創(chuàng)建色度紋理
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCacheRef, imageBufferRef, NULL, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, bufferWidth / 2, bufferHeight / 2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &_chrominanceTextureRef);
if (err) {
NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}
// 獲取紋理對(duì)象
_chrominanceTexture = CVOpenGLESTextureGetName(_chrominanceTextureRef);
// 綁定紋理
glBindTexture(GL_TEXTURE_2D, _chrominanceTexture);
// 設(shè)置紋理濾波
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
09-YUV轉(zhuǎn)RGB繪制紋理
紋理映射只能在RGBA方式下執(zhí)行
而采集的是YUV,所以需要把YUV 轉(zhuǎn)換 為 RGBA,
本質(zhì)其實(shí)就是改下矩陣結(jié)構(gòu)
注意點(diǎn):glDrawArrays如果要繪制著色器上的點(diǎn)和片段,必須和著色器賦值代碼放在一個(gè)代碼塊中,否則找不到繪制的信息,就繪制不上去,造成屏幕黑屏
之前是把glDrawArrays和YUV轉(zhuǎn)RGB方法分開,就一直黑屏.
函數(shù)glUniform1i
glUniform1i(GLint location, GLint x)
指定著色器中亮度紋理對(duì)應(yīng)哪一層紋理單元
參數(shù)location:著色器中紋理坐標(biāo)
參數(shù)x:指定那一層紋理
函數(shù)glEnableVertexAttribArray
glEnableVertexAttribArray(GLuint index)
開啟頂點(diǎn)屬性數(shù)組,只有開啟頂點(diǎn)屬性,才能給頂點(diǎn)屬性信息賦值
函數(shù)glVertexAttribPointer
glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *ptr)
設(shè)置頂點(diǎn)著色器屬性,描述屬性的基本信息
參數(shù)indx:屬性ID,給哪個(gè)屬性描述信息
參數(shù)size:頂點(diǎn)屬性由幾個(gè)值組成,這個(gè)值必須位1,2,3或4;
參數(shù)type:表示屬性的數(shù)據(jù)類型
參數(shù)normalized:GL_FALSE表示不要將數(shù)據(jù)類型標(biāo)準(zhǔn)化
參數(shù)stride 表示數(shù)組中每個(gè)元素的長(zhǎng)度;
參數(shù)ptr 表示數(shù)組的首地址
10-渲染緩沖區(qū)到屏幕
注意點(diǎn):必須設(shè)置窗口尺寸glViewport
注意點(diǎn):渲染代碼必須調(diào)用[EAGLContext setCurrentContext:_context]
原因:因?yàn)槭嵌嗑€程,每一個(gè)線程都有一個(gè)上下文,只要在一個(gè)上下文繪制就好,設(shè)置線程的上下文為我們自己的上下文,就能繪制在一起了,否則會(huì)黑屏.
注意點(diǎn):每次創(chuàng)建紋理前,先把之前的紋理引用清空[self cleanUpTextures],否則卡頓
函數(shù)glViewport
glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
設(shè)置OpenGL渲染窗口的尺寸大小,一般跟圖層尺寸一樣.
注意:在我們繪制之前還有一件重要的事情要做,我們必須告訴OpenGL渲染窗口的尺寸大小
方法presentRenderbuffer
- (BOOL)presentRenderbuffer:(NSUInteger)target
是將指定renderbuffer呈現(xiàn)在屏幕上
11-清理內(nèi)存
注意:只要有Ref結(jié)尾的,都需要自己手動(dòng)管理,清空
函數(shù)glClearColor
glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampfalpha)
設(shè)置一個(gè)RGB顏色和透明度,接下來會(huì)用這個(gè)顏色涂滿全屏.
函數(shù)glClear
glClear (GLbitfieldmask)
用來指定要用清屏顏色來清除由mask指定的buffer,mask可以是 GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT的自由組合。
在這里我們只使用到 color buffer,所以清除的就是 clolor buffer。
#pragma mark - 11.清理內(nèi)存
- (void)dealloc
{
// 清空緩存
[self destoryRenderAndFrameBuffer];
// 清空紋理
[self cleanUpTextures];
}
#pragma mark - 銷毀渲染和幀緩存
- (void)destoryRenderAndFrameBuffer
{
glDeleteRenderbuffers(1, &_colorRenderBuffer);
_colorRenderBuffer = 0;
glDeleteBuffers(1, &_framebuffers);
_framebuffers = 0;
}
// 清空紋理
- (void)cleanUpTextures
{
// 清空亮度引用
if (_luminanceTextureRef) {
CFRelease(_luminanceTextureRef);
_luminanceTextureRef = NULL;
}
// 清空色度引用
if (_chrominanceTextureRef) {
CFRelease(_chrominanceTextureRef);
_chrominanceTextureRef = NULL;
}
// 清空紋理緩存
CVOpenGLESTextureCacheFlush(_textureCacheRef, 0);
}
GPUImage工作原理
GPUImage最關(guān)鍵在于GPUImageFramebuffer這個(gè)類,這個(gè)類會(huì)保存當(dāng)前處理好的圖片信息。
GPUImage是通過一個(gè)鏈條處理圖片,每個(gè)鏈條通過target連接,每個(gè)target處理完圖片后,會(huì)生成一個(gè)GPUImageFramebuffer對(duì)象,并且把圖片信息保存到GPUImageFramebuffer。
這樣比如targetA處理好,要處理targetB,就會(huì)先取出targetA的圖片,然后targetB在targetA的圖片基礎(chǔ)上在進(jìn)行處理.
總結(jié):GPUImage是基于OpenGL ES 處理,我一直在持續(xù)學(xué)習(xí)過程中,分析和總結(jié)的東西那些不到位的地方,希望讀友們指點(diǎn),我會(huì)虛心學(xué)習(xí),我們一起進(jìn)步。