如何在背景图像和临时图纸上绘制(如在GLPaint中)? [英] How can I draw (as in GLPaint) onto a background image, and with temporary drawings?

查看:104
本文介绍了如何在背景图像和临时图纸上绘制(如在GLPaint中)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing a GLPaint-esque drawing application for the iPad, however I have hit a stumbling block. Specifically, I am trying to implement two things at the moment:

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

1) A background image that can be drawn onto.

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



2) The ability to draw temporary shapes, e.g. you might draw a line, but the final shape would only be committed once the finger has lifted.

对于背景图片,我理解的想法是将图像绘制成VBO并将其绘制正确在每一线画之前。这很好,但是现在我需要添加绘制临时形状的能力...将kEAGLDrawablePropertyRetainedBacking设置为YES(如在GLPaint中),临时显然不是临时的!将保留的后备属性设置为NO对于临时对象非常有效,但现在我的先前写意线不会保留。

For the background image, I understand the idea is to draw the image into a VBO and draw it right before every line drawing. This is fine, but now I need to add the ability to draw temporary shapes... with kEAGLDrawablePropertyRetainedBacking set to YES (as in GLPaint) the temporary are obviously not temporary! Turning the retained backing property to NO works great for the temporary objects, but now my previous freehand lines aren't kept.

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

What is the best approach here? Should I be looking to use more than one EAGLLayer? All the documentation and tutorials I've found seem to suggest that most things should be possible with a single layer. They also say that retained backing should pretty much always be set to NO. Is there a way to work my application in such a configuration? I tried storing every drawing point into a continually expanding vertex array to be redrawn each frame, but due to the sheer number of sprites being drawn this isn't working.

I我真的很感激这方面的任何帮助,因为我在网上搜索并没有发现任何东西!

I would really appreciate any help on this one, as I've scoured online and found nothing!

推荐答案

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

I've since found the solution to this problem. The best way appears to be to use custom framebuffer objects and render-to-texture. I hadn't heard of this before asking the question, but it looks like an incredibly useful tool for the OpenGLer's toolkit!

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

For those that may be wanting to do something similar, the idea is that you create a FBO and attach a texture to it (instead of a renderbuffer). You can then bind this FBO and draw to it like any other, the only difference being that the drawings are rendered off-screen. Then all you need to do to display the texture is to bind the main FBO and draw the texture to it (using a quad).

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

So for my implementation, I used two different FBOs with a texture attached to each - one for the "retained" image (for freehand drawing), and the other for the "scratch" image (for temporary drawings). Each time a frame is rendered, I first draw a background texture (in my case I just used the Texture2D class), then draw the retained texture, and finally the scratch texture if required. When drawing a temporary shape everything is rendered to the scratch texture, and this is cleared at the start of every frame. Once it is finished, the scratch texture is drawn to the retained texture.

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

Here are a few snippets of code that might be of use to somebody:

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

1) Create the framebuffers (I have only shown a couple here to save space!):

// ---------- 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:

2) Draw to the render-to-texture 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,现在:

3) Render the various textures to the main FBO, and present:

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]绘制保留纹理的图纸将使用以下代码:

For example, drawing drawing the retained texture using [self drawRetainedTexture] would use the following code:

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

很多代码,但我希望能帮到别人。它肯定让我难过了一会儿!

A lot of code, but I hope that helps somebody. It certainly had me stumped for a while!

这篇关于如何在背景图像和临时图纸上绘制(如在GLPaint中)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆