OpenGL 渲染流程
在OpenGL中,任何事物都在3D空間中铲敛,而屏幕和窗口卻是2D像素?cái)?shù)組褐澎,這導(dǎo)致OpenGL的大部分工作都是關(guān)于把3D坐標(biāo)轉(zhuǎn)變?yōu)檫m應(yīng)你屏幕的2D像素。3D坐標(biāo)轉(zhuǎn)為2D坐標(biāo)的處理過程是由OpenGL的圖形渲染管線(Graphics Pipeline伐蒋,大多譯為管線工三,實(shí)際上指的是一堆原始圖形數(shù)據(jù)途經(jīng)一個(gè)輸送管道,期間經(jīng)過各種變化處理最終出現(xiàn)在屏幕的過程)管理的咽弦。
OpenGL 渲染流程如下圖幾個(gè)階段:
使用CAEAGLLayer
1.自定義一個(gè)view 并改變他的layer的類型
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_currentContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
_eaglLayer = [[CAEAGLLayer alloc]init];
_eaglLayer.frame = frame;
_eaglLayer.opaque = YES;
///默認(rèn)透明徒蟆,設(shè)置成不透明
_eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];
///kEAGLDrawablePropertyRetainedBacking表示繪圖表面顯示后,是否保留其內(nèi)容型型。
///kEAGLColorFormatRGBA8:32位RGBA的顏色段审,4*8=32位
[EAGLContext setCurrentContext:_currentContext];
[self.layer addSublayer:_eaglLayer];
[self setupFrameBuffer];
[self setupColorBuffer];
[self setupBindFrameBuffer];
[self setupProgram];
}
return self;
}
- (Class)layerClass {
return [CAEAGLLayer class];
}
- 創(chuàng)建frameBuffer
- (void)setupFrameBuffer {
///生成一個(gè)frameBuffer ,1表示數(shù)量
glGenFramebuffers(1, &_frameBuffer);
///幀緩沖區(qū)與framebuffer 建立綁定關(guān)系闹蒜,
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
///啟用頂點(diǎn)數(shù)組
glEnableVertexAttribArray(GLKVertexAttribPosition);
///指定渲染的頂點(diǎn)數(shù)據(jù)
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT)*3, vertices);
}
GLfloat vertices[] = {
-0.5f,0.5f,0.0f,
-0.5f,-0.5f,0.0f,
0.5f,-0.5f,0.0f,
};
vertex 頂點(diǎn)著色器程序
attribute vec3 a_Position;
void main(void) {
gl_Position = vec4(a_Position, 1.0);
}
fragment片源著色器程序
void main(void) {
gl_FragColor = vec4(1, 1, 0, 1);
}
頂點(diǎn)坐標(biāo)的數(shù)據(jù)應(yīng)該繪制的位置如下圖
3.創(chuàng)建colorBuffer
- (void)setupColorBuffer {
///生成渲染緩沖區(qū)對(duì)象名稱
glGenRenderbuffers(1, &_colorBuffer);
/// 綁定一個(gè)命名的渲染緩沖區(qū)對(duì)象
glBindRenderbuffer(GL_RENDERBUFFER, _colorBuffer);
///開啟顏色通道
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT)*4, colorTexts);
}
4.綁定frameBuffer
- (void)setupBindFrameBuffer {
///將renderbuffer對(duì)象附加到framebuffer對(duì)象
/*
target
指定幀緩沖目標(biāo)寺枉。 符號(hào)常量必須是GL_FRAMEBUFFER。
attachment
指定renderbuffer應(yīng)附加到的附著點(diǎn)绷落。 必須是以下符號(hào)常量之一:GL_COLOR_ATTACHMENT0姥闪,GL_DEPTH_ATTACHMENT或 GL_STENCIL_ATTACHMENT
renderbuffertarget
指定renderbuffer目標(biāo)。 符號(hào)常量必須為GL_RENDERBUFFER砌烁。
renderbuffer
指定要附加的renderbuffer對(duì)象筐喳。
*/
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorBuffer);
[_currentContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
/// 獲取渲染的width催式、height
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_frameWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_frameHeight);
}
4.創(chuàng)建著色器
- (void)setupProgram {
///加載頂點(diǎn)著色器
GLuint vertexShader = [self loadShaderType:GL_VERTEX_SHADER fileName:@"vertex.vsh"];
///加載片源著色器
GLuint fragmentShader = [self loadShaderType:GL_FRAGMENT_SHADER fileName:@"fragment.fsh"];
///創(chuàng)建program
_program = glCreateProgram();
///指定著色器對(duì)象將附加到的program對(duì)象。
glAttachShader(_program, vertexShader);
glAttachShader(_program, fragmentShader);
///鏈接一個(gè)程序?qū)ο蟆? glLinkProgram(_program);
//檢查program結(jié)果
GLint linkSuccess;
glGetProgramiv(_program, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(_program, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"error message: %@", messageString);
}
///刪除臨時(shí)創(chuàng)建的頂點(diǎn)/片源著色器
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
- (GLuint)loadShaderType:(GLenum)type fileName:(NSString *)shaderName {
NSString *shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:nil];
NSError *error;
///1.獲取shader 的內(nèi)容
NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
if (!shaderString) {
NSLog(@"Error loading shader: %@", error.localizedDescription);
return -1;
}
///2.創(chuàng)建一個(gè)shader(根據(jù)type類型)
GLuint shader = glCreateShader(type);
const char * shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = (int)[shaderString length];
//3.將著色器源碼附加到著色器對(duì)象上避归。
//參數(shù)1:shader,要編譯的著色器對(duì)象 *shader
//參數(shù)2:numOfStrings,傳遞的源碼字符串?dāng)?shù)量 1個(gè)
//參數(shù)3:strings,著色器程序的源碼(真正的著色器程序源碼)
//參數(shù)4:lenOfStrings,長度荣月,具有每個(gè)字符串長度的數(shù)組,或NULL梳毙,這意味著字符串是NULL終止的
glShaderSource(shader, 1, &shaderStringUTF8, &shaderStringLength);
///4.把著色器源代碼編譯成目標(biāo)代碼
glCompileShader(shader);
///刪除
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
///5.獲取shader 的狀態(tài)哺窄,如果失敗,會(huì)有相應(yīng)的日志
if (status == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shader, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"%@", messageString);
return -1;
}
return shader;
}
4.繪制
-(void)drawTrangles {
///確保在當(dāng)前opengL 上下文
[EAGLContext setCurrentContext:_currentContext];
///設(shè)置繪制窗口的位置和寬高
glViewport(0, 0, _frameWidth, _frameHeight);
///清除上一次的緩存
glClearColor(0, 0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(_program);
///開始繪制
glDrawArrays(GL_TRIANGLES, 0, 3);
///請(qǐng)求將繪制的內(nèi)容顯示到綁定的renderBuffer 上
[_currentContext presentRenderbuffer:GL_RENDERBUFFER];
}
最終效果
源碼地址:
OpenGL03-EAGL三角形1