我正在尝试在我的全屏渲染输出上应用CoreImage滤镜,但看起来我错过了一些东西,因为我将黑屏作为输出.
首先,我将整个场景绘制为纹理.然后我从那个纹理创建CoreImage,我最终绘制并呈现.但我得到的只是黑屏.我正在关注绘制纹理并将CoreImage与OpenGLES集成的Apple指南:WWDC2012 511和https://developer.apple.com/library/ios/documentation/3ddrawing/conceptual/opengles_programmingguide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html
这是相关代码:
渲染:
@interface Renderer () { EAGLContext* _context; GLuint _defaultFramebuffer, _drawFramebuffer, _depthRenderbuffer, _colorRenderbuffer, _drawTexture; GLint _backingWidth, _backingHeight; CIImage *_coreImage; CIFilter *_coreFilter; CIContext *_coreContext; }
初始化方法:
- (BOOL)initOpenGL { _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; if (!_context) return NO; [EAGLContext setCurrentContext:_context]; glGenFramebuffers(1, &_defaultFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, _defaultFramebuffer); glGenRenderbuffers(1, &_colorRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderbuffer); glGenFramebuffers(1, &_drawFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, _drawFramebuffer); glGenTextures(1, &_drawTexture); glBindTexture(GL_TEXTURE_2D, _drawTexture); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _drawTexture, 0); glGenRenderbuffers(1, &_depthRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderbuffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderbuffer); _coreFilter = [CIFilter filterWithName:@"CIColorInvert"]; [_coreFilter setDefaults]; NSDictionary *opts = @{ kCIContextWorkingColorSpace : [NSNull null] }; _coreContext = [CIContext contextWithEAGLContext:_context options:opts]; return YES; }
每当图层大小更改时(在初始化和方向更改时)都会记录内存:
- (void)resizeFromLayer:(CAEAGLLayer *)layer { layer.contentsScale = 1; glBindFramebuffer(GL_FRAMEBUFFER, _defaultFramebuffer); glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer]; glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth); glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight); // glCheckFramebufferStatus ... SUCCESS glBindFramebuffer(GL_FRAMEBUFFER, _drawFramebuffer); glBindTexture(GL_TEXTURE_2D, _drawTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _backingWidth, _backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _backingWidth, _backingHeight); // glCheckFramebufferStatus ... SUCCESS }
绘制方法:
- (void)render:(Scene *)scene { [EAGLContext setCurrentContext:_context]; glBindFramebuffer(GL_FRAMEBUFFER, _drawFramebuffer); // Draw using GLKit, custom shaders, drawArrays, drawElements // Now rendered scene is in _drawTexture glBindFramebuffer(GL_FRAMEBUFFER, _defaultFramebuffer); glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); // Create CIImage with our render-to-texture texture _coreImage = [CIImage imageWithTexture:_drawTexture size:CGSizeMake(_backingWidth, _backingHeight) flipped:NO colorSpace:nil]; // Ignore filtering for now; Draw CIImage to current render buffer [_coreContext drawImage:_coreImage inRect:CGRectMake(0, 0, _backingWidth, _backingHeight) fromRect:CGRectMake(0, 0, _backingWidth, _backingHeight)]; // Present [_context presentRenderbuffer:GL_RENDERBUFFER]; }
注意,绘制场景后,_drawTexture包含渲染场景.我使用Xcode调试工具(Capture OpenGL ES框架)进行检查.
编辑:如果我尝试从其他纹理创建CIImage然后_drawTexture,它会正确显示它.我的怀疑是,当CIContext尝试通过CIImage渲染时,_drawTexture可能还没有准备好或以某种方式被锁定.
EDIT2:我还尝试用视口清除替换所有绘图代码:
glViewport(0, 0, _backingWidth, _backingHeight); glClearColor(0, 0.8, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
结果仍然是黑色的.它表明问题可能是绘制纹理或帧缓冲.
我终于发现了什么是错的.iOS上2个纹理的非强大功能必须具有线性过滤和夹到边缘包装:
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);
我的纹理大小与屏幕相同,但我没有设置这四个参数.
对于后代:上面的代码是OpenGL ES和CoreImage互连的完美有效示例.只需确保正确初始化纹理!