基于上一個demo 我們已經(jīng)可以簡單繪制一個三角形了,下面我們把一張圖片通過Opengl ES的方式繪制到屏幕上
效果如下:
IMG_4462.PNG
1.創(chuàng)建一個view 并改變使其 支持 CAEAGLLayer
{
CAEAGLLayer *_eaglLayer;
GLuint _frameBuffer;
GLuint _renderBuffer;
GLuint _program;
EAGLContext *_currentContext;
GLint _frameWidth;
GLint _frameHeight;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setuLayer];
}
return self;
}
- (void)setuLayer{
_currentContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
_eaglLayer = (CAEAGLLayer *) self.layer;
_eaglLayer.frame = self.frame;
_eaglLayer.opaque = YES;
_eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];
[EAGLContext setCurrentContext:_currentContext];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self setupBindFrameBuffer];
[self setupProgram];
}
+(Class)layerClass{
return [CAEAGLLayer class];
}
2.創(chuàng)建frameBuffer
-(void)setupFrameBuffer {
glGenFramebuffers(1, &_frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderBuffer);
}
3.創(chuàng)建renderBuffer
- (void)setupRenderBuffer {
glGenRenderbuffers(1, &_renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
[_currentContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}
4.創(chuàng)建著色器程序
頂點著色器
attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;
void main(){
varyTextCoord = textCoordinate;
gl_Position = position;
}
片源著色器
precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main(){
gl_FragColor = texture2D(colorMap, varyTextCoord);
}
- (void)setupProgram {
GLuint vertexShader = [self loadShaderType:GL_VERTEX_SHADER fileName:@"vertex.vsh"];
GLuint fragmentShader = [self loadShaderType:GL_FRAGMENT_SHADER fileName:@"fragment.fsh"];
_program = glCreateProgram();
glAttachShader(_program, vertexShader);
glAttachShader(_program, fragmentShader);
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);
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
數(shù)據(jù)源介紹
GLfloat vertices[] = {
0.5f, -0.5f, -1.0f, 1.0f, 0.0f, //右下角A
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f, //左上角B
-0.5f, -0.5f, -1.0f, 0.0f, 0.0f, //左下角C
0.5f, 0.5f, -1.0f, 1.0f, 1.0f, //右上角D
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f, //左上角B
0.5f, -0.5f, -1.0f, 1.0f, 0.0f, //右下角A
};
數(shù)據(jù)部分沒什么好講的,字節(jié)找張紙畫一下ABCD 幾個點,就知道是什么形狀;
紋理坐標(biāo)的取值范圍是(0 ~1);

image.png
紋理坐標(biāo)系如下圖所示,左下角是(0,0 ),右上角是( 1,1);

image.png
5.加載一張圖片并轉(zhuǎn)成紋理
// 從圖片中加載紋理
- (GLuint)setupTexture: (NSString *)fileName {
//1、將UIImage轉(zhuǎn)換為CGImageRef & 判斷圖片是否獲取成功
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
if (!spriteImage) {
NSLog(@"Failed to lead image %@", fileName);
exit(1);
}
//2、讀取圖片的大小、寬和高
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
//3、獲取圖片字節(jié)數(shù) 寬*高*4(RGBA)
GLubyte *spriteData = (GLubyte *)calloc(width*height*4, sizeof(GLubyte));
// 4、創(chuàng)建上下文
/*
參數(shù)1:data,指向要渲染的繪制圖像的內(nèi)存地址
參數(shù)2:width,bitmap的寬度,單位為像素
參數(shù)3:height,bitmap的高度,單位為像素
參數(shù)4:bitPerComponent,內(nèi)存中像素的每個組件的位數(shù),比如32位RGBA,就設(shè)置為8
參數(shù)5:bytesPerRow,bitmap的沒一行的內(nèi)存所占的比特數(shù)
參數(shù)6:colorSpace,bitmap上使用的顏色空間 kCGImageAlphaPremultipliedLast:RGBA
*/
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
NSLog(@"kCGImageAlphaPremultipliedLast %d", kCGImageAlphaPremultipliedLast);
// 5、在CGContextRef上 --- 將圖片繪制出來
/*
CGContextDrawImage 使用的是Core Graphics框架,坐標(biāo)系與UIKit 不一樣。UIKit框架的原點在屏幕的左上角,Core Graphics框架的原點在屏幕的左下角。
CGContextDrawImage
參數(shù)1:繪圖上下文
參數(shù)2:rect坐標(biāo)
參數(shù)3:繪制的圖片
*/
CGRect rect = CGRectMake(0, 0, width, height);
//6、使用默認(rèn)方式繪制
CGContextDrawImage(spriteContext, rect, spriteImage);
//7、畫圖完畢就釋放上下文
CGContextRelease(spriteContext);
//8、綁定紋理到默認(rèn)的紋理ID
glBindTexture(GL_TEXTURE_2D, 1);
//9、設(shè)置紋理屬性
/*
參數(shù)1:紋理維度
參數(shù)2:線性過濾、為s,t坐標(biāo)設(shè)置模式
參數(shù)3:wrapMode,環(huán)繞模式
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
float fw = width, fh = height;
//10、載入紋理2D數(shù)據(jù)
/*
參數(shù)1:紋理模式,GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
參數(shù)2:加載的層次,一般設(shè)置為0
參數(shù)3:紋理的顏色值GL_RGBA
參數(shù)4:寬
參數(shù)5:高
參數(shù)6:border,邊界寬度
參數(shù)7:format
參數(shù)8:type
參數(shù)9:紋理數(shù)據(jù)
*/
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
//11、釋放spriteData
free(spriteData);
return 0;
}
6.加載圖片對應(yīng)的紋理并渲染出來
- (void)layoutSubviews {
[self renderlayer];
}
- (void)renderlayer {
glViewport(0, 0, _frameWidth, _frameHeight);
GLuint attributeBuffer;
glGenBuffers(1, &attributeBuffer);
glBindBuffer(GL_ARRAY_BUFFER, attributeBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
///頂點,(向定位置填充數(shù)據(jù))
GLuint position = glGetAttribLocation(_program, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, NULL);
///紋理坐標(biāo) (向紋理坐標(biāo)填充數(shù)據(jù))
GLuint textCoor = glGetAttribLocation(_program, "textCoordinate");
glEnableVertexAttribArray(textCoor);
glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL+3);
GLuint texture = [self setupTexture:@"mouse"];
//設(shè)置這個紋理對應(yīng)第0層紋理,
glUniform1i(glGetUniformLocation(_program, "colorMap"), 0);
[_currentContext presentRenderbuffer:_renderBuffer];
/// 繪制
glViewport(0, 0, _frameWidth, _frameHeight);
glClearColor(0, 0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(_program);
glDrawArrays(GL_TRIANGLES, 0, 6);
[_currentContext presentRenderbuffer:GL_RENDERBUFFER];
}
效果如下:
IMG_0091.PNG
反思:
繪制的圖是和圖片本身是反的;這是因為紋理坐標(biāo)的原點(0,0)是在左下角,而屏幕的坐標(biāo)原點(0,0)是在左上角,下一節(jié)我們將圖片反轉(zhuǎn)過來;
源碼地址:https://github.com/hunter858/OpenGL_Study/tree/main/OpenGL06-EAGL加載圖片