2014-01-07 7 views
11

Ich versuche, CoreImage-Filter auf meine Vollbild-Renderausgabe anzuwenden, aber sieht aus, als würde ich etwas verpassen, weil ich schwarzen Bildschirm als Ausgabe bekomme.Anwenden von CIFilter auf OpenGL render-to-textur

Zuerst zeichne ich ganze Szene zu einer Textur. Dann erstelle ich CoreImage aus dieser Textur, die ich schließlich zeichne und präsentiere. Aber alles, was ich bekomme, ist schwarzer Bildschirm. Ich habe folgende Apple-Führungslinien auf Textur Zeichnung und die Integration von Coreimage mit OpenGLES: WWDC2012 511 und https://developer.apple.com/library/ios/documentation/3ddrawing/conceptual/opengles_programmingguide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html

Hier ist relevant Code:

Renderer:

@interface Renderer() { 
    EAGLContext* _context; 
    GLuint _defaultFramebuffer, _drawFramebuffer, _depthRenderbuffer, _colorRenderbuffer, _drawTexture; 
    GLint _backingWidth, _backingHeight; 
    CIImage *_coreImage; 
    CIFilter *_coreFilter; 
    CIContext *_coreContext; 
} 

Initialisierungsmethode:

- (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; 
} 

Alloc-Speicher bei jeder Änderung der Schichtgröße (bei Init- und bei Orientierungsänderung):

- (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 
} 

Draw-Methode:

- (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]; 
} 

Hinweis, nach Szene zeichnen, _drawTexture enthält gerenderte Szene. Ich überprüfe das mit Xcode-Debug-Tools (Capture OpenGL ES-Frame).

EDIT: Wenn ich versuche, CImage aus einer anderen Textur dann _drawTexture zu erstellen, wird es korrekt angezeigt. Mein Verdacht ist, dass _drawTexture möglicherweise nicht bereit oder irgendwie gesperrt ist, wenn CIContext versucht, es durch CImage rendern zu lassen.

EDIT2: Ich habe auch versucht, mit nur Ansichtsfenster Löschen aller Zeichencode ersetzt:

glViewport(0, 0, _backingWidth, _backingHeight); 
    glClearColor(0, 0.8, 0, 1); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

Ergebnis noch schwarz ist. Es deutet darauf hin, dass das Problem etwas mit der Zeichenstruktur oder dem Framebuffer sein könnte.

+0

Warum in aller Welt würde dies abgelehnt werden? –

+1

Das ist interessant. Normalerweise würde ich sagen, dies liegt daran, dass der Core Image-Kontext nicht mit dem gleichen OpenGL ES-Kontext erstellt wurde wie Ihr Rendering, aber hier scheint er richtig eingerichtet zu sein. Wenn Sie einen Passthrough-Shader verwenden und mit der gerenderten Textur ein Quad auf den Bildschirm zeichnen, können Sie dann überprüfen, ob die Szene richtig in die Textur gerendert wird? Schließlich, wenn Sie nicht mit Core Image verheiratet waren, habe ich ein kleines Projekt hier: https://github.com/BradLarson/GPUImage, das auch diese Art von GPU-Seitennachbearbeitung kann. Sehen Sie sich die CubeExample-Beispielanwendung an, die Ihren Vorstellungen entspricht. –

+0

Ok, ich habe ein Quad mit _drawTexture gerendert und es ist schwarz. Es sieht so aus, als ob etwas mit dieser Textur oder mit dem Rendering nicht stimmt. Vielleicht vermisse ich etwas mit Render-to-Texture. Diff ist nur, dass ich eine Textur als GL_COLOR_ATTACHEMNT0 an Stelle des Render-Puffers anhefte. –

Antwort

5

Ich endlich gefunden, was falsch ist. Nicht-Leistung von 2 Texturen auf iOS müssen lineare Filterung haben und an Randwickel klemmen:

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); 

Meine Texturgröße gleiche wie Bildschirm hatte, aber ich habe nicht diese vier params gesetzt.

Für zukünftige Generationen: Code oben ist ein perfektes Beispiel für die Verbindung von OpenGL ES und CoreImage. Stellen Sie sicher, dass Sie Ihre Textur richtig initialisieren!