在iOS上使用OpenGLES进行多个绘图协作

时间:2014-12-18 23:57:28

标签: ios opengl-es concurrency collaboration

我正在开发一个配置:

的应用
  • 对存储100点的数组A进行硬编码
  • 用户可以在屏幕上用手指绘制自由泳。

现在我使用OpenGLES绘制。在一段时间内有两个动作:

  • 用户绘图
  • 从阵列A自动绘图

我的意思是当用户用手指在屏幕上绘图时,代码会自动通过数组A将其点绘制到屏幕上。

我配置了两个名为:vboId和vboId_1的缓冲区来绑定每个动作的点,vboId将用户绑定绘图中的顶点,vboId_1将绑定来自数组A的顶点。以下是绘图代码(假设openGLES的所有初始化)上下文,帧缓冲区,渲染缓冲区等都准备好了)

- (void)renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end isOwner:(BOOL)owner {
    static GLfloat*     vertexBuffer = NULL;
    static NSUInteger   vertexMax = 64;
    NSUInteger          vertexCount = 0,
                        count,
                        i;

    [EAGLContext setCurrentContext:context];
    glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);

    // Convert locations from Points to Pixels
    CGFloat scale = self.contentScaleFactor;
    start.x *= scale;
    start.y *= scale;
    end.x *= scale;
    end.y *= scale;

    // Allocate vertex array buffer
    if(vertexBuffer == NULL)
        vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));

    // Add points to the buffer so there are drawing points every X pixels
    count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / kBrushPixelStep), 1);
    for(i = 0; i < count; ++i) {
        if(vertexCount == vertexMax) {
            vertexMax = 2 * vertexMax;
            vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
        }

        vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
        vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
        vertexCount += 1;
    }

    // Draw
    if (drawing_by_user) {
        // Draw vertex from user
        glBindBuffer(GL_ARRAY_BUFFER, vboId);
        glBufferData(GL_ARRAY_BUFFER, vertexCount*2*sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW);

        glEnableVertexAttribArray(ATTRIB_VERTEX);
        glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, 0);

        glBindTexture(GL_TEXTURE_2D, brushTexture.id);

        glUseProgram(program[PROGRAM_POINT_USER].id);
        glDrawArrays(GL_POINTS, 0, (int)vertexCount);
    } else {
        // draw vertex automatically
        glBindBuffer(GL_ARRAY_BUFFER, vboId_1);
        glBufferData(GL_ARRAY_BUFFER, vertexCount*2*sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW);

        glEnableVertexAttribArray(ATTRIB_VERTEX);
        glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, 0);

        glBindTexture(GL_TEXTURE_2D, brushTexture.id);

        glUseProgram(program[PROGRAM_POINT_AUTO].id);
        glDrawArrays(GL_POINTS, 0, (int)vertexCount);
    }


    // Display the buffer
    glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER];
}

实际上这个代码有效,2个动作发生了,但它不喜欢我的期望。在绘图时,有时它会卡住,泄漏,丢失一些点,不平滑,并使用户体验不好。

如果只是按用户绘制或从数组A中绘制就可以了,那就顺利了

我想我不能同时将2个动作绑定到帧缓冲区和渲染缓冲区,并发或者我必须用更高的机制来实现

更新1: 我意识到问题似乎是由于应用程序无法在阵列A上自动绘制点时接收到触摸事件。我的意思是在数组A上绘制点时无法识别某些函数touchBegan,touchMove和touchEnd。

这很奇怪,如果只是绘制其中一个,它有效,我看不出差异,只绘制其中一个也做这些动作(绑定缓冲区,渲染缓冲区......) ,绘制它们仍然使用这些功能。为什么不触发这些触摸事件。

任何人都可以帮助我

1 个答案:

答案 0 :(得分:1)

首先,我建议您阅读有关在iOS应用程序中使用OpenGL ES的文档。例如,

因为你从touchesBegan调用了EAGLContext -presentRenderbuffer:等等。这是非常低效的方式。

来自Apple文档“A GLKit View Controller动画OpenGL ES内容”

  

默认情况下,GLKView对象根据需要呈现其内容。也就是说,使用OpenGL ES绘制的一个关键优势是它能够使用图形处理硬件来连续复杂场景的动画 - 诸如游戏和模拟之类的应用很少呈现静态图像。对于这些情况,GLKit框架提供了一个视图控制器类,它维护它管理的GLKView对象的动画循环。这个循环遵循游戏和模拟中常见的设计模式,有两个阶段:更新和显示。图3-2显示了动画循环的简化示例。

Figure 3-2 animation loop

通常使用OpenGL ES的应用程序使用类似于此GLKit文档的动画循环。在更新阶段,更新3D对象的位置,3D模型的运动,计算下一个线的点,某种东西。在显示阶段,该应用程序使用OpenGL ES API渲染3D对象,3D模型,线条等类型的东西。

所以您可能需要实现以下内容。

  • 在触摸事件中,将触摸位置保持在内存中。不要渲染任何东西,此时不要使用OpenGL ES API。
  • 在更新阶段,确定要渲染的点,用户触摸的位置,或者数组中用于自动绘制的位置。然后准备顶点数据。你根本不需要计时器。
  • 在绘制阶段,使用OpenGL ES API渲染线条。您可以找到一种减少渲染时间的方法,例如,保留渲染缓冲区等等。
  • 在绘制阶段结束时,调用EAGLContext -presentRenderbuffer:。如果您使用GLKit或某种框架,则会从框架中自动调用它。你不需要打电话。