1. 介绍
ios并没有像Android glsurfaceview或者Qt QOpenglWidget
那样完整Opengl渲染View封装,官方demo也是主线程创建的CADisplayLink提供的渲染loop来执行Opengl渲染操作,可能会影响到主线程其他view的操作造成卡顿,所以此篇仿照Android GlSurfaceView在子线程渲染Opengl。
2. 封装
- ios opengl渲染环境和渲染子线程创建
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
self.layer.opaque = YES;
_playFlag = TRUE;
_isInitContext = FALSE;
_isSurfaceChanged = FALSE;
_layerPtr = (CAEAGLLayer *) self.layer;
self.layer.opaque = YES;
self.layer.contentsScale = [[UIScreen mainScreen] scale];
((CAEAGLLayer *) self.layer).drawableProperties = @{kEAGLDrawablePropertyRetainedBacking: [NSNumber numberWithBool:YES],};
}
_renderLoopThread = [[NSThread alloc] initWithTarget:self selector:@selector(renderThreadFunc) object:nil];
[_renderLoopThread start];
[self registerSystemActiveEvent];
return self;
}
- 依附于子线程创建Opengl 上下文
- (void)renderThreadFunc {
if (!_isInitContext) {
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
_isInitContext = TRUE;
[EAGLContext setCurrentContext:_context];
//glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_windowWidth);
//glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_windowHeight);
}
@autoreleasepool {
_renderTimer = [NSTimer scheduledTimerWithTimeInterval:0.0333 target:self selector:@selector(renderLoop) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
[self destroyFrameBuffer];
[EAGLContext setCurrentContext:nil];
self.context = nil;
NSLog(@"this is the render thread destroy!");
}
这里当timer被取消,渲染线程结束,销毁Opengl上下文和相关FrameBuffer
- 渲染FrameBuffer和帧缓冲区创建
- (void)renderLoop {
if (_isInitContext && _isSurfaceChanged) {
@synchronized (self) {
[self destroyFrameBuffer];
[self createFrameBuffer];
//NSLog(@"onSurfaceSizeChanged:%d, width:%d, height:%d", _multisampleFramebuffer, _windowWidth, _windowHeight);
_isSurfaceChanged = FALSE;
}
}
if (!_playFlag || !_isInitContext || _multisampleFramebuffer == 0) {
return;
}
[self bindFrameBuffer];
[self renedeOperation];
[self presentFrameBuffer];
}
因为创建窗口大小可能会发生改变,这时候需要根据窗口大小变化重新创建附着在多重采样FrameBuffer上的帧缓冲区RenderBuffer,这里创建了两个FrameBuffer执行多重采样用于消除锯齿,如果没有这个需求,只要创建一个FrameBuffer即可。
- 具体渲染操作
//渲染操作
-(void)renedeOperation {
NSLog(@"renedeOperation");
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0, 1, 0, 1);
}
3. 结束语
Ios在子线程中渲染Opengl重要的是对Layer的操作,获取Layer需要在主线程获取,请注意该点。Ios对Opengl EGL接口封装的挺多,并没有android来的直接。具体代码见: ios 子线程渲染Opengl