iphone - 我如何绘制(如在 GLPaint 中)到背景图像上,并使用临时绘图?

标签 iphone ios ipad opengl-es drawing

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

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

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

对于背景图像,我的理解是将图像绘制到 VBO 中,并在每次画线之前绘制它。这很好,但现在我需要添加绘制临时形状的能力......将 kEAGLDrawablePropertyRetainedBacking 设置为 YES(如在 GLPaint 中)临时形状显然不是临时的!将保留的后备属性设置为 NO 对于临时对象非常有效,但现在我以前的手绘线条没有保留。

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

我真的很感激任何关于这方面的帮助,因为我在网上搜索了一无所获!

最佳答案

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

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

因此,在我的实现中,我使用了两个不同的 FBO,每个 FBO 都附有纹理 - 一个用于“保留”图像(用于手绘),另一个用于“草稿”图像(用于临时绘图)。每次渲染一帧时,我首先绘制一个背景纹理(在我的例子中,我只使用了 Texture2D 类),然后绘制保留的纹理,如果需要,最后绘制划痕纹理。绘制临时形状时,所有内容都会渲染到划痕纹理,并在每一帧开始时清除。完成后,将划痕纹理绘制到保留的纹理上。

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

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

很多代码,但我希望对某些人有所帮助。这确实让我难住了一段时间!

关于iphone - 我如何绘制(如在 GLPaint 中)到背景图像上,并使用临时绘图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4168562/

相关文章:

objective-c - UIPageViewController 和景观

iphone - 将选项添加到 Settings.bundle 中的 PSMultiValueSpecifier

iphone - 如何等待位置管理器获取当前位置?

iphone - 根据状态修改 UIButtons 层

ios - 在 UITableView 中编程静态单元格

iOS 应用镜像 "Screen Saver"

iphone - 检测 iOS 5 上的铃声(静音按钮)位置?

iphone - 对象界面布局?

ios - 如何为高分辨率(iPhone 4视网膜)屏幕配置新的XCode iOS项目?

ios - 为 swift 开发的 ios 应用程序检索存储为 PFFile 的视频文件