从另一个View返回后,OpenGL绘制黑屏

时间:2011-11-24 00:47:05

标签: iphone ios uiview opengl-es uikit

我整天都在苦苦寻找答案。

问题:

我有OpenGL视图,我在IB中创建它,初始化所有缓冲区并在displayLink中设置其渲染循环。它很棒,一切都很好。但后来我尝试在根控制器中使用此openGL视图创建另一个控制器并使用以下方式显示它:

[self presentModalViewController:newPage animated:YES];

它显示得很好,就像我想要的那样。它也很好用,没有发现任何问题。它也是从IB发起的。但是一旦我使用

[self dismissModalViewControllerAnimated:YES];

动画确实发生了,视图确实发生了变化,但是当它下降时,它背后留下“垃圾”(黑色背景中的部分视图),之前的openGL视图保持黑色。我尝试删除并重新创建displayLink,但没有运气。我试图再次破坏/创建帧缓冲区,我确实设法让它工作一次,但它花了很长时间,因为我从视图创建它,我不知道这是否是正确的方法。为了使它更容易,这是我的代码的一些部分:

- (BOOL)createFrameBuffer
{
    glGenFramebuffersOES(1, &viewFramebuffer);
    glGenRenderbuffersOES(1, &viewRenderbuffer);

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);



    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);

    if (YES) 
    {
        glGenRenderbuffersOES(1, &depthRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
    }

    if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) 
    {
        NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
        return NO;
    }

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);

    return YES;
    }

    }

    - (void)destroyFrameBuffer
    glDeleteFramebuffersOES(1, &viewFramebuffer);
    viewFramebuffer = 0;
    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
    viewRenderbuffer = 0;

    if(depthRenderbuffer) 
    {
        glDeleteRenderbuffersOES(1, &depthRenderbuffer);
        depthRenderbuffer = 0;
    }

    - (void)layoutSubviews


    [EAGLContext setCurrentContext:context];

    [self draw:nil];

内部init是我的主要init方法。

 - (id)internalInit
{    

        CAEAGLLayer* eaglLayer = (CAEAGLLayer*) super.layer;
        eaglLayer.opaque = YES;


        context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];

        if (!context || ![EAGLContext setCurrentContext:context]) {
            [self release];
            return nil;
        }

    [self createFrameBuffer];

    [self setupView:self];

        [self drawView: nil];

        CADisplayLink* displayLink;
        displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(draw:)];
        [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [displayLink setFrameInterval:1];

    return self;
}

setupView:方法基本上创建视口,设置视锥,所有必要的变量和状态。没什么特别的。

提前感谢您花费的所有时间和任何时间。

3 个答案:

答案 0 :(得分:2)

在我完成一些优化之后我发生了同样的效果,但事实证明,在解除游戏中心视图或完成播放MPPlayer电影之后,问题就出现了。

当您获得LayoutSubviews(在顶部窗口消失后将会获得)时,从apple的opengl模板中,您应该销毁并重新创建帧缓冲区

- (void)layoutSubviews
{
    // The framebuffer will be re-created at the beginning of the next setFramebuffer method call.
    [self deleteFramebuffer];
}

之后的功能[(EAGLView *)self.view setFramebuffer];应该调用再次创建帧缓冲区,原始模板实际上是在每个帧上调用它,但是你只需要在它被销毁后调用它一次。 (我在那里放了一个叫做第一个的var)

我只是把例程放在这里:

- (void)setFramebuffer
{
    if (context)
    {
        [EAGLContext setCurrentContext:context];

        if (!defaultFramebuffer)
            [self createFramebuffer];

        glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
        first = FALSE;

    }
}

- (void)createFramebuffer
{
if (context && !defaultFramebuffer)
{
    NSLog(@"Create Frame Buffer");

    [EAGLContext setCurrentContext:context];

    // Create default framebuffer object.
    glGenFramebuffersOES(1, &defaultFramebuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);

    // Create color render buffer and allocate backing store.
    glGenRenderbuffersOES(1, &colorRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);

    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer *)self.layer];
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &framebufferWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &framebufferHeight);

    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);

    // Need a depth buffer
    glGenRenderbuffersOES(1, &depthRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
    glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,  framebufferWidth, framebufferHeight);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
        NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER_OES));
}

}

因此在从displaylink调用的函数上调用此setFramebuffer。我在MPPlayer游戏中心的完成通知中首先将var重置为FALSE。

如果找不到问题,请尝试调试在EAGL对象级别调用的内容,NSLog在那里查看每个函数,看看是否有任何奇怪的事情发生缓冲区或绑定。

答案 1 :(得分:0)

“EAGLView在出现或重新出现时是黑色”的另一个可能的解释是,您的[EAGLView renderbufferStorage:fromDrawable:]方法未在主线程上调用。从后台调用此方法将导致通常有效但偶尔会变黑的情况。可能不是这里所说的确切问题的原因,但足够晦涩,以至于它可能对绝望的google在将来绊倒这个页面时有用。

答案 2 :(得分:0)

我有同样的问题,因为glDepthMask(FALSE)用于背景框架绘制以将其保存到图像,然后没有返回正常渲染。希望它有所帮助。

感谢。