代码之家  ›  专栏  ›  技术社区  ›  Stuart

如何在背景图像上绘制(如在GLPaint中),以及使用临时图形?

  •  4
  • Stuart  · 技术社区  · 15 年前

    我正在为iPad编写一个GLPaint风格的绘图应用程序,但是遇到了一个绊脚石。具体来说,我目前正试图实现两件事:

    1) 可以绘制的背景图像。

    2) 绘制临时形状的能力,例如,你可以画一条线,但最终形状只有在手指抬起后才能确定。

    对于背景图像,我理解的想法是将图像绘制到VBO中,并在绘制每一行之前绘制它。这很好,但现在我需要添加绘制临时形状的能力。。。当keagldrawablepropertyretainedback设置为YES(在GLPaint中)时,临时的显然不是临时的!对于临时对象来说,将保留的backing属性设置为NO非常有用,但现在我以前的徒手画线没有保留。

    这里最好的方法是什么?我应该找一个以上的老鹰吗?我发现的所有文档和教程似乎都表明,大多数事情都应该在一个图层上实现。他们还说,保留备份应该总是设置为否。有没有办法在这样的配置中运行我的应用程序?我尝试将每个绘图点存储到一个不断扩展的顶点数组中,以便在每个帧中重新绘制,但由于绘制的精灵数量太多,这不起作用。

    我真的很感谢你的帮助,因为我在网上搜遍了,什么也没找到!

    1 回复  |  直到 14 年前
        1
  •  11
  •   Stuart    13 年前

    我找到了解决这个问题的办法。最好的方法似乎是使用自定义帧缓冲区对象并渲染到纹理。在问这个问题之前,我还没听说过这个,但它看起来是一个非常有用的工具,对于OpenGLer的工具包来说!

    对于那些可能想做类似的事情的人,你的想法是创建一个FBO并附加一个纹理到它(而不是一个渲染缓冲)。然后,可以绑定此FBO并像其他任何FBO一样绘制到它,唯一的区别是图形在屏幕外呈现。然后,要显示纹理,只需绑定主FBO并将纹理绘制到它(使用四边形)。

    所以在我的实现中,我使用了两个不同的FBO,每个FBO都有一个纹理-一个用于“保留”图像(用于徒手画),另一个用于“抓取”图像(用于临时画)。每次渲染帧时,我首先绘制一个背景纹理(在我的例子中,我只是使用了Texture2D类),然后绘制保留的纹理,最后绘制scratch纹理(如果需要)。绘制临时形状时,所有内容都将渲染为“刮痕”纹理,并且在每帧开始时清除该纹理。完成后,scratch纹理将被绘制到保留的纹理。

    下面是一些可能对某些人有用的代码片段:

    1) 创建帧缓冲区(这里我只展示了两个以节省空间!):

    // ---------- DEFAULT FRAMEBUFFER ---------- //
    // Create framebuffer.
    glGenFramebuffersOES(1, &viewFramebuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    
    // Create renderbuffer.
    glGenRenderbuffersOES(1, &viewRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    
    // Get renderbuffer storage and attach to framebuffer.
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable: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);
    
    // Check for completeness.
    status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
    if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
        NSLog(@"Failed to make complete framebuffer object %x", status);
        return NO;
    }
    
    // Unbind framebuffer.
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
    
    
    // ---------- RETAINED FRAMEBUFFER ---------- //
    // Create framebuffer.
    glGenFramebuffersOES(1, &retainedFramebuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, retainedFramebuffer);
    
    // Create the texture.
    glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
    glGenTextures(1, &retainedTexture);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, retainedTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);
    
    // Attach the texture as a renderbuffer.
    glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, retainedTexture, 0);
    
    // Check for completeness.
    status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
    if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
        NSLog(@"Failed to make complete framebuffer object %x", status);
        return NO;
    }
    
    // Unbind framebuffer.
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
    

    2) 绘制到“渲染到纹理”FBO:

    // Ensure that we are drawing to the current context.
    [EAGLContext setCurrentContext:context];
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, retainedFramebuffer);
    glViewport(0, 0, 1024, 1024);
    
    // DRAWING CODE HERE
    

    3) 将各种纹理渲染到主FBO,并呈现:

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glViewport(0, 0, backingWidth, backingHeight);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);       // Clear to white.
    glClear(GL_COLOR_BUFFER_BIT);
    
    
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
    [self drawBackgroundTexture];
    [self drawRetainedTexture];
    [self drawScratchTexture];
    
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    
    
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
    

    例如,使用 [self drawRetainedTexture] 将使用以下代码:

    // Bind the texture.
    glBindTexture(GL_TEXTURE_2D, retainedTexture);
    
    // Destination coords.
    GLfloat retainedVertices[] = {
        0.0,          backingHeight,    0.0,
        backingWidth, backingHeight,    0.0,
        0.0,          0.0,              0.0,
        backingWidth, 0.0,              0.0
    };
    
    // Source coords.
    GLfloat retainedTexCoords[] = {
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0
    };
    
    // Draw the texture.
    glVertexPointer(3, GL_FLOAT, 0, retainedVertices);
    glTexCoordPointer(2, GL_FLOAT, 0, retainedTexCoords);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    // Unbind the texture.
    glBindTexture(GL_TEXTURE_2D, 0);
    

    很多代码,但我希望这能帮助别人。这确实让我难堪了一阵子!

    推荐文章