本文章正确使用姿势:command/Ctrl + f 进行搜索对应的功能代码,找到它的详细解释。 (以下内容如有偏差,欢迎进行指正)
一.CAEAGLLayer 的使用:
官方解释如图CAEAGLLayer,我来简单翻译一下:
CAEAGLLayer 是继承于CALayer 的,可以用它在iOS 和tvOS 的设备上使用。如果你打算用OpenGL 进行绘画的话,那么可以使用这个类作为背景的layer,可以通过重写layerClass 方法进行初始化。代码如下:
self.myEagLayer = (CAEAGLLayer *)self.layer;
+ (Class)layerClass {
return [CAEAGLLayer class];
}
//zs20180312 其实这句话 是通过重写layerClass 方法,重新定义self.layer 的类型 self.myEagLayer只是指向self.layer 的指针。
为了更好的展现最好进行如下的设置:
1.将其不透明度(opaque)设置成true。
2. CAEAGLLayer 的bounds 设置成当前整个展示图层的大小。
3.CAEAGLLayer 不能旋转,不能偏移。
4.可以在CAEAGLLayer上设置非openGL 的视图,需要注意的是绘制透明的2D 的内容的时候,必须保证OpenGL的内容是不透明的。
5.尽量变换CAEAGLLayer上的内容,而不是变换CAEAGLLayer。
1.1 opaque
opaque:不透明的
self.myEagLayer.opaque = YES;
//CAEAGLLayer默认是透明的,必须将它设置为不透明才能其可见
1.2 drawableProperties
皇家翻译:通过这个字典的值来设置绘制的特点。需要注意的一点是这个属性必须在EAGLContext的方法renderbufferStorage:fromDrawable:前设置才能生效。如果要更改这个属性值,还需要再次调用下renderbufferStorage:fromDrawable:的方法才能生效。
//设置描绘属性,在这里设置不维持渲染内容以及颜色格式为 RGBA8。
self.myEagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumbernumberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
详细解释:
/* kEAGLDrawablePropertyRetainedBacking 表示绘图表面显示后,是否保留其内容,一般设置为false; 不保留绘完就释放了。
它是一个key值,通过一个NSNumber包装bool值.
kEAGLDrawablePropertyColorFormat:绘制对象内部的颜色缓存区格式
kEAGLColorFormatRGBA8:32位RGBA的颜色, 4*8=32;
kEAGLColorFormatRGB565:16位RGB的颜色
kEAGLColorFormatSRGBA8:SRGB, */
简单的绘制,CAEAGLLayer的这几属性设置完就够用了。
二.EAGLContext的使用
EAGLContext 对象管理着OpenGL ES 绘制的上下文环境,包括信息状态、命令、绘制的资源(例如:纹理,绘制的缓存区)。继承于Object。
要想执行OpenGL ES 的命令,必须使用当前绘制的上下文环境。
重点来了:当在上下文环境中绘制的时候,必须绑定一个 framebuffer。
2.1上下文的创建
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
//1.指定API版本 1.0~3.0
/*
kEAGLRenderingAPIOpenGLES1 = 1,
kEAGLRenderingAPIOpenGLES2 = 2,
kEAGLRenderingAPIOpenGLES3 = 3,
*/
2.2 设置当前绘制的上下文环境
Bool isSuccess = [EAGLContext setCurrentContext:context];
/*
* 通过类方法设置 当前的绘制的上下文,返回值为YES 设置成功。
*/
2.3 在上下文环境中 给renderBuffer 分配存储空间
- (BOOL)renderbufferStorage:(NSUInteger)target fromDrawable:(nullable id)drawable; 官方解释如图:
// 为 renderbuffer 分配存储空间
[self.myContext renderbufferStorage: GL_RENDERBUFFER
fromDrawable:self.myEagLayer];
//self.myEagLayer 是 CAEAGLLayer 实例对象
//frame buffer仅仅是管理者,不需要分配空间;render buffer的存储空间的分配,对于不同的render buffer,使用不同的API进行分配,而只有分配空间的时候,render buffer句柄才确定其类型。
详细解释:
函数 - (BOOL)renderbufferStorage:(NSUInteger)target fromDrawable:(id)drawable;
在内部使用 参数drawable(在这里是 CAEAGLLayer)的相关信息(drawableProperties 的属性信息)。
drawableProperties的属性信息作为参数调用了 glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
glRenderbufferStorage 指定存储在 renderbuffer 中图像的宽高以及颜色格式,并按照此规格为之分配存储空间。在这里,将使用我们在前面设置 CAEAGLLayer对象的颜色格式 RGBA8, 以及它的宽高作为参数调用 glRenderbufferStorage。
这也解释了为啥CAEAGLLayer的drawableProperties属性的设置要在- (BOOL)renderbufferStorage:(NSUInteger)target fromDrawable:(id)drawable;函数之前。
2.4 - (BOOL)presentRenderbuffer:(NSUInteger)target;
//要求本地窗口系统显示OpenGL ES渲染<目标>
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];
详细解释:
- (BOOL)presentRenderbuffer:(NSUInteger)target 是将指定 renderbuffer 呈现在屏幕上,在这里我们指定的是前面已经绑定为当前 renderbuffer 的那个,在 renderbuffer 可以被呈现之前,必须调用renderbufferStorage:fromDrawable: 为之分配存储空间。
在前面设置 drawable 属性时,我们设置 kEAGLDrawablePropertyRetainedBacking 为FALSE,表示不想保持呈现的内容,因此在下一次呈现时,应用程序必须完全重绘一次。
将该设置为 TRUE 对性能和资源影像较大,因此只有当renderbuffer需要保持其内容不变时,我们才设置 kEAGLDrawablePropertyRetainedBacking 为 TRUE。
三. API
3.1 setContentScaleFactor:
contentScaleFactor 内容缩放因子,一般设置成和屏幕相同的scale 。scale 的值 和咱们工程中使用的几倍图是相对应的,例如@x @2x @3x ,iPhone8 的 scale = 2,iPhone8 Plus 的scale = 3。scale 就是甚至一个point(点)有几个pixels(像素)。
[self setContentScaleFactor:[[UIScreen mainScreen]scale]];
借用cocoaChina上的回答如下:
DesignResolutionSize是设计分辨率,做逻辑时用到的所有屏幕相关数据都是基于它的,比如你写了条语句moveBy,移动50个像素,不管你设备什么分辨率,屏幕上看到的移动距离是一致的,这50像素是设计分辨率下的像素,和设备无关,cocos用设计分辨率来解决这种逻辑上的一致性。ContentScaleFactor的作用是为了在设计分辨率不变的情况下给不同设备提供不同清晰度的图片。比如你设备分辨率是1136*640,那你放一张1136*640的图片到屏幕上就是刚好充满屏幕,你设备分辨率是2278*1280的话,这图片一样是充满屏幕。为什么会这样,因为cocos屏蔽了设备分辨率,用DesignResolutionSize来确保了屏幕显示的一致性,那这时候这张图片就会变的模糊。为了不让它变的模糊就需要用一张2倍大小的图片替换之。但在设计分辨率不变的情况下,这张2倍的图片会显得非常大。为了让它能和之前的图片显示一致,就需要告诉cocos你现在用的是2倍图片,ContentScaleFactor就是起这个作用,告诉cocos当前素材和设计分辨率之间的比值,让cocos显示图片时做缩放处理。而这种缩放处理对于逻辑来说是透明的,这样就使得cocos在设计分辨率不变的情况下能够支持各种不同清晰度的素材。
3.2 OpenGLES/ES2/gl.h 下的API
3.2.1 glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
申请一个缓存区标志
GLuint buffer;//1.定义一个缓存区
glGenRenderbuffers(1, &buffer);//2.申请一个缓存区标志
/*它是为 renderbuffer 申请一个 id(或名字)。参数 n 表示申请生成 renderbuffer 的个数,而 renderbuffers 返回分配给 renderbuffer 的 id,注意:返回的 id 不会为0,id 0 是OpenGL ES 保留的,我们也不能使用 id 为0的 renderbuffer。*/
3.2.2 glDeleteBuffers (GLsizei n, const GLuint* buffers);
参数含义: n 删除几个缓存对象,一般设置成1, *buffers 去缓存区的ID的地址。
使用如下:
glDeleteBuffers(1, &_myColorRenderBuffer);
self.myColorRenderBuffer = 0;
glDeleteBuffers(1, &_myColorFrameBuffer);
self.myColorFrameBuffer = 0;
3.2.3 glBindRenderbuffer (GLenum target, GLuint renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
这个函数将指定 id 的 renderbuffer 设置为当前 renderbuffer。参数 target 必须为 GL_RENDERBUFFER,参数 renderbuffer 是就是使用 glGenRenderbuffers 生成的 id。当指定 id 的 renderbuffer 第一次被设置为当前 renderbuffer 时,会初始化该 renderbuffer 对象。
3.2.4 glBindFramebuffer (GLenum target, GLuint framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer);
设置当前的frameBuffer ,与glBindRenderbuffer类似。
3.2.5 glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);
//self.myColorRenderBuffer 是glGenRenderbuffers 生成的renderBuffer
需要将renderbuffer跟framebuffer进行绑定,调用glFramebufferRenderbuffer函数进行绑定,后面的绘制才能起作用
该函数是将相关 buffer(三大buffer之一)attach到framebuffer上,参数 attachment 是指定 renderbuffer 被装配到那个装配点上,其值是GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT中的一个,分别对应 color,depth和 stencil三大buffer。
接下来,可以调用OpenGL ES进行绘制处理,最后则需要在EGALContext的OC方法进行最终的渲染绘制。这里渲染的color buffer,这个方法会将buffer渲染到CALayer上。- (BOOL)presentRenderbuffer:(NSUInteger)target;
3.2.6 glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f); 字面意思是设置清屏颜色,这个命名容易有歧义,可以理解为设置屏幕(将要显示)的颜色,因为glClear 设置后颜色才生效。
glClear(GL_COLOR_BUFFER_BIT);
glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) 用来设置清屏颜色,默认为黑色;
glClear (GLbitfield mask)用来指定要用清屏颜色来清除由mask指定的buffer,mask 可以是 GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT的自由组合。在这里我们只使用到 color buffer,所以清除的就是 clolor buffer。
3.2.7 glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
3.2.8 glCreateProgram (void)
创建一个渲染程序。shader(着色器) 就是一段在GPU运行的程序,由于GPU的硬件设计结构与CPU 有很大的不同,所以GPU 用一种不同的语言。
//创建program
GLint program = glCreateProgram();
四.相关概念
4.1 屏幕渲染方式
当前屏幕渲染(On-Screen Rendering):
指的是GPU的渲染操作是在当前用于显示的屏幕缓存区中进行的。
离幕渲染(Off-Screen Rendering):
指的是GPU在当前屏幕缓存区以外新开辟一个缓存区进行渲染操作。
一般情况下,OpenGL ES会将应用提供到渲染服务的动画直接渲染显示(使用基本的渲染的流程)但对于一些复杂的图像动画的渲染,并不能够直接渲染叠加显示出来。而是需要根据Command Buffer分通道进行渲染再组合。这个组合过程中,就有些渲染通道是不会直接显示出来的。标记此次渲染需要更多的渲染通道和合并步骤,而这些没有直接渲染显示在屏幕上的通道就是离屏渲染通道。
离屏渲染为什么会卡顿?
离屏渲染需要更多的渲染通道,而不同的渲染通道间切换需要消耗一定的时间,这个时间内GPU会闲置。当通道数量足够多,对性能也会有较大的影响。
相对于当前屏幕渲染,离屏渲染的代价相对而言较高。主要有以下2个原因:
1.创建新的缓存区
2.上下文切换
哪些情况会使用离屏渲染(off-Screen Render)?
1.drawRect
2.layer.shouldRasterize = true;
3.有mask或者阴影(layer.makesToBounds) shouldRasterize(光栅化)、masks(遮罩)、shadows(阴影) edge antialiasing(抗锯 )、group opacity( 透明)
4.Text(UILabel,CATextLayer,CoreText)
4.2 frame buffer 和 render buffer
OpenGLES 中buffer分为frame buffer 和 render buffer2个大类。
其中frame buffer 相当于render buffer的管理者。
frame buffer object即称FBO,常用于离屏渲染缓存等。
render buffer则又可分为3类:colorBuffer、depthBuffer、stencilBuffer。
一个 frameBuffer 对象(通常被称为一个FBO)。是一个收集颜色、深度和模板缓存区的附着点。描述属性的状态,例如如颜色、 深度和模板缓存区的大小和格式,都关联到FBO(Frame Buffer Object)。并且纹理的名字和renderBuffer 对象也都是 关联于FBO。各种各样的2D图形能够被附着framebuffer对象的颜色附着点。它们包含 renderbuffer对象存储的颜色值、一个2D纹理或立方体贴图。
内容已经全部展示 不需要购买!