OpenGL ES需要渲染上下文和绘制表面才能完成图像的绘制。但是OpenGL的API并没有提供如何创建渲染上下文或者如何连接到原生窗口系统。EGL时Khronos渲染API和原生系统之间的接口。
唯一支持OpenGL ES 却不支持EGL的平台时iOS。因此我们在iOS系统上使用的EGL是苹果自己定义的EGL。
在本案例中,使用的EGL是CAEAGLLayer。
下面介绍一下EGL的主要功能:
1、和本地窗口系统通讯
2、查询可用的配置
3、创建OpenGL ES可用的“绘图表面”
4、同步不同类别的API之间的渲染。
5、管理“渲染资源”,比如纹理映射。
这个案例需要实现的目标有:
1、用EAGL创建屏幕上的渲染表面
2、加载顶点/片元着色器
3、创建一个程序对象,并链接顶点/片元着色器,并链接程序对象
4、设置视口
5、清除颜色缓冲区
6、渲染简单图元
7、使颜色缓冲区的内容在EAGL窗口表现呈现
案例的最终效果:
Simulator Screen Shot - iPhone SE -2nd generation- - 2020-07-30 at 20.52.24.png如何实现上面图形的效果呢?
首先我们要去定义顶点着色器和片元着色器去加载数据
我们定义两个空文件,一个后缀为fsh(片元着色器),一个为vsh(顶点着色器)
片元着色器代码
precision highp float;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main(){
gl_FragColor = texture2D(colorMap,varyTextCoord);
}
顶点着色器代码
attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;
void main(){
varyTextCoord = textCoordinate;
gl_Position = position;
}
在定义完着色器后,就可以实现用GLSL去加载图片
我们分六步完成:
第一步:设置图层
将CAEAGLLayer替换CALayer,然后设置屏幕大小,设置描述属性。
self.myEagLayer = (CAEAGLLayer *)self.layer;
[self setContentScaleFactor:[[UIScreen mainScreen]scale]];
self.myEagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:@false,kEAGLDrawablePropertyRetainedBacking,kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];
第二步:设置上下文
上下文是就是存储程序的状态
首先确定OpenGL ES渲染API的版本,然后创建图像上下文
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES3;
EAGLContext *context = [[EAGLContext alloc]initWithAPI:api];
第三步:清空缓冲区
glDeleteBuffers(1, &_myColorRenderBuffer);
self.myColorRenderBuffer = 0;
glDeleteBuffers(1, &_myColorFrameBuffer);
self.myColorFrameBuffer = 0;
第四步:设置RenderBuffer(renderbuffer 能够被⽤用来分配和存储颜⾊色、
深度或者模板值)
GLuint buffer;
glGenRenderbuffers(1, &buffer);
glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer);
[self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];
第五步:设置FrameBuffer(是⼀个收集颜⾊色、深
度和模板缓存区的附着点。描述属性的状态,例如颜色、深度和模板
缓存区的⼤小和格式,都关联到FBO(Frame Buffer Object))
GLuint buffer;
glGenFramebuffers(1, &buffer);
glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);
第四步和第五步代码步骤都差不多,都是创建一个缓冲区id,然后申请缓冲区标志,然后绑定,再与EAGL绑定在一起
第六步:绘制,在这个过程中,我们需要引用我们之前写的着色器。并且加载顶点数据和纹理也是在这一步当中
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
CGFloat scale = [[UIScreen mainScreen] scale];
glViewport(self.frame.origin.x*scale, self.frame.origin.y*scale, self.frame.size.width*scale, self.frame.size.height*scale);
NSString *verFile = [[NSBundle mainBundle]pathForResource:@"shaderv" ofType:@"vsh"];
NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"];
self.myPrograme = [self loadShaders:verFile Withfrag:fragFile];
glLinkProgram(self.myPrograme);
GLint linkStatus;
glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkStatus);
glUseProgram(self.myPrograme);
GLfloat attrArr[] =
{
0.5f, -0.5f, -1.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f,
0.5f, -0.5f, -1.0f, 1.0f, 0.0f,
};
GLuint attriBuffer;
glGenBuffers(1, &attriBuffer);
glBindBuffer(GL_ARRAY_BUFFER, attriBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
GLuint position = glGetAttribLocation(self.myPrograme, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, NULL);
GLuint textCoor = glGetAttribLocation(self.myPrograme, "textCoordinate");
glEnableVertexAttribArray(textCoor);
glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL+3);
[self setupTexture:@"fengjing"];
glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];
整个过程就此结束,从上面的图来看,它是倒着的,这又是什么原因呢?
那是因为它开始加载的顶点是从左下角开始加载,因此图片是反的。
那么我们如何实现它的正向显示呢?
在案例中,我们可以在加载纹理的过程中,去对图片进行翻转,将它翻转之后,再加载上去。
CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
CGContextTranslateCTM(spriteContext, 0, rect.size.height);
CGContextScaleCTM(spriteContext, 1.0, -1.0);
CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
CGContextDrawImage(spriteContext, rect, spriteImage);
在加上上面的代码之后,图片就能正常显示了,当然翻转的方式有很多种,这边就使用了一种简单的方法去实现
附上demo
网友评论