【问题标题】:Asynchronous texture loading and sharegroups in OpenGL ES 2.0 and iOSOpenGL ES 2.0 和 iOS 中的异步纹理加载和共享组
【发布时间】:2013-06-25 15:48:27
【问题描述】:

我正在尝试创建一个 GLKView,在其中添加立方体并绘制它们。问题是,每个立方体都是 NSObject 类型,并且有自己的顶点和纹理缓冲区,但我想在单个上下文中绘制它们。为了做到这一点,我关注了一些 WWDC 视频并创建了两个上下文,一个用于渲染,一个用于纹理加载,并且我将两者放在同一个共享组中。代码方面,我在这方面所做的是向我的 GLKView 添加一个名为 renderContext 的属性,我希望在其中绘制所有立方体,并且我还设置了一个 loaderContext 属性,我想在其中加载纹理。但是,什么都没有画出来,我什么也看不到,有时我会崩溃和 GL ERROR 0x0500。它曾经可以正常工作,并且模型视图矩阵应该正确设置和一切。异步加载和两个共享上下文的引入导致了问题...

代码如下:

这是 GLKView:容器(包含立方体)

- (void)setupGL {

    self.renderContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    self.loaderContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:self.renderContext.sharegroup];

    glGenFramebuffers(1, &defaultFrameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFrameBuffer);

    glGenRenderbuffers(1, &depthBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.bounds.size.width, self.bounds.size.height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);

    glEnable(GL_DEPTH_TEST);

}



- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {


    self.opaque = NO;

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    [EAGLContext setCurrentContext:self.renderContext];

    for(Cube *cube in self.cubes){

        [cube draw];

    }


}

每个单独的立方体都是这样设置的:

-(id)init {


    self = [super init];
    if(self){        

        self.effect = [[GLKBaseEffect alloc]init];
        self.effect.transform.projectionMatrix = GLKMatrix4MakePerspective(45.0f,0.95f, 0.1f, 2.0f);
        self.effect.transform.projectionMatrix = GLKMatrix4Translate(self.effect.transform.projectionMatrix, 0, 0.0, 0.0);
        self.effect.transform.modelviewMatrix = GLKMatrix4Translate(self.effect.transform.modelviewMatrix,0,0,-1.3);


        glGenBuffers(1, &vertexArray);
        glBindBuffer(GL_ARRAY_BUFFER, vertexArray);
        glEnableVertexAttribArray(GLKVertexAttribPosition);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
        glVertexAttribPointer(GLKVertexAttribPosition,3,GL_FLOAT,GL_FALSE,0,0);

        glGenBuffers(1, &texArray);
        glBindBuffer(GL_ARRAY_BUFFER, texArray);
        glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
        glBufferData(GL_ARRAY_BUFFER, sizeof(TexCoords), TexCoords, GL_STATIC_DRAW);
        glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0,0);


    }

    return self;




}

并且有draw方法:

-(void)draw{


    [self.effect prepareToDraw];

    self.effect.texture2d0.enabled = YES;


    for(int i=0;i<6;i++){

        if(i==0)glBindTexture(GL_TEXTURE_2D, frontTexture.name);
        if(i==1)glBindTexture(GL_TEXTURE_2D, rightTexture.name);
        if(i==2)glBindTexture(GL_TEXTURE_2D, backTexture.name);
        if(i==3)glBindTexture(GL_TEXTURE_2D, leftTexture.name);
        if(i==4)glBindTexture(GL_TEXTURE_2D, bottomTexture.name);
        if(i==5)glBindTexture(GL_TEXTURE_2D, topTexture.name);
        glDrawArrays(GL_TRIANGLES, i*6, 6);
    }



}

这是我尝试异步加载纹理的方法:

注意:GLKView(容器)是每个单独立方体的父级,我检索其 loaderContext,它位于 renderContext 的共享组中,所以应该正确绘制纹理,对吗?

-(void)loadTextureForTexture:(GLKTextureInfo*)texN withView:(CubeView *)cV{

    __block GLKTextureInfo *texName = texN;

    EAGLContext *loaderContext = self.parent.loaderContext;
    self.textureLoader = [[GLKTextureLoader alloc]initWithSharegroup:loaderContext.sharegroup];
    [EAGLContext setCurrentContext:loaderContext];

    NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:GLKTextureLoaderOriginBottomLeft];

    dispatch_queue_t loaderQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t mainQueue = dispatch_get_main_queue();



    [self.textureLoader textureWithCGImage:[self imageWithView:cV].CGImage options:options queue:loaderQueue completionHandler:^(GLKTextureInfo *tex, NSError *err){

        texName = tex;

        if(err)
            NSLog(@"%@", err);
        else
            NSLog(@"no error");

        dispatch_async(mainQueue, ^{

            [self display];

        });

    }];
}

【问题讨论】:

    标签: iphone ios asynchronous opengl-es-2.0


    【解决方案1】:

    看起来你做的上下文管理比必要的多:

    • GLKTextureLoader 只需要知道在哪个EAGLSharegroup 中创建其纹理。您不必代表它创建EAGLContext,并且您在代码中创建的那个已经没有被传递到任何GLKTextureLoader 方法。
    • 您不应该手动管理当前的EAGLContext——事实上,GLKView 的文档特别提到您不应该从绘图方法内部更改当前上下文。

    这样做的最终结果是,除了从现有上下文中提取 EAGLSharegroup 以创建 GLKTextureLoader 之外,您应该没有新的上下文管理代码。

    此外,加载纹理的结果似乎永远不会超出loadTextureForTexture:withView:。您的texN 变量不会通过引用传递给函数,因此texName 仅对loadTextureForTexture:withView: 和您的纹理加载完成块可见。一旦loadTextureForTexture:withView: 返回并调用完成块,数据就消失了。似乎应该有某种CubeView setter 需要用您收到的GLKTextureInfo * 调用。

    【讨论】:

    • 非常感谢 Pivot,这对我帮助很大!!!但是,异步绘图仍然存在问题。如果我异步调用-display 方法,应用程序崩溃,如果我同步调用,它可以工作。
    • 你是如何尝试触发异步显示的?看来您应该在主队列的视图上异步调用 setNeedsDisplay
    • setNeedsDisplay 在 GLKView 中究竟做了什么?当我调用 display 时,我完全按照您在上面的代码中看到的那样做。我实际上是在容器(GLKView)上调用-display,它基本上遍历所有立方体(NSObjects)并将它们绘制在GLKView的委托方法中,即- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
    • 您是在对主线程/调度队列进行这些调用吗?在主线程外与UIViews(包括GLKView)交互是不安全的。
    • 我决定不继续使用 Apple 的 GLKit 类,因为它们仍然有很多 bug,它们简直吓坏了我。到目前为止,它引起了很多问题,所以我想我应该在没有它的情况下推出它。它现在工作得很好。但无论如何还是谢谢你,我希望这个答案能帮助其他人。祝你有美好的一天:-)
    【解决方案2】:

    我在您的代码中看到的第一个问题是渲染缓冲区没有颜色附件,因此您只能获得不会绘制任何内容的深度输出。

    glGenRenderbuffers(1, &colorBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, self.bounds.size.width, self.bounds.size.height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT, GL_RENDERBUFFER, colorBuffer);
    

    【讨论】:

    • 首先感谢您的回答。我相对确定没有颜色缓冲区不是问题的罪魁祸首,因为它以前在没有颜色缓冲区的情况下也能正常工作。如果我的代码是正确的,我会看到纹理,或者,在没有纹理的情况下,黑色立方体......但我什么都没有看到,这非常奇怪......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    相关资源
    最近更新 更多