iOS:GPUImage库和VBO

3
我正在使用Brad Larson的GPUImage库进行图像处理。到目前为止,这个库非常好用。然而,我正在尝试添加一个允许网格变形的滤镜并遇到了一些问题。具体来说,我想要一个使用VBO渲染四边形的滤镜,以便最终可以动态更改顶点以实现变形效果。
使用VBO的第一步导致了崩溃。
我创建了一个GPUImageFilter的子类,重写了- (void)newFrameReadyAtTime:(CMTime)frameTime方法来通过VBO渲染四边形。请注意:我只是尝试渲染单个四边形而不是整个网格,这样我可以逐个解决问题。
@implementation GPUMeshImageFilter {
    GLuint _positionVBO;
    GLuint _texcoordVBO;
    GLuint _indexVBO;

    BOOL isSetup_;
}

- (void)setupBuffers
{
    static const GLsizeiptr verticesSize = 4 * 2 * sizeof(GLfloat);
    static const GLfloat squareVertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f,  1.0f,
        1.0f,  1.0f,
    };

    static const GLsizeiptr textureSize = 4 * 2 * sizeof(GLfloat);
    static const GLfloat squareTextureCoordinates[] = {
        0.0f, 0.0f,
        1.0f, 0.0f,
        0.0f,  1.0f,
        1.0f,  1.0f,
    };

    static const GLsizeiptr indexSize = 4 * sizeof(GLushort);
    static const GLushort indices[] = {
      0,1,2,3,  
    };

    glGenBuffers(1, &_indexVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexVBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize, indices, GL_STATIC_DRAW);

    glGenBuffers(1, &_positionVBO);
    glBindBuffer(GL_ARRAY_BUFFER, _positionVBO);
    glBufferData(GL_ARRAY_BUFFER, verticesSize, squareVertices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), 0);

    glGenBuffers(1, &_texcoordVBO);
    glBindBuffer(GL_ARRAY_BUFFER, _texcoordVBO);
    glBufferData(GL_ARRAY_BUFFER, textureSize, squareTextureCoordinates, GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), 0);

    NSLog(@"Setup complete");
}

- (void)newFrameReadyAtTime:(CMTime)frameTime;
{
    if (!isSetup_) {
        [self setupBuffers];
        isSetup_ = YES;
    }

    if (self.preventRendering)
    {
        return;
    }

    [GPUImageOpenGLESContext useImageProcessingContext];
    [self setFilterFBO];

    [filterProgram use];

    glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
    glClear(GL_COLOR_BUFFER_BIT);

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, filterSourceTexture);

    glUniform1i(filterInputTextureUniform, 2);  

    if (filterSourceTexture2 != 0)
    {
        glActiveTexture(GL_TEXTURE3);
        glBindTexture(GL_TEXTURE_2D, filterSourceTexture2);

        glUniform1i(filterInputTextureUniform2, 3); 
    }

    NSLog(@"Draw VBO");
    glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);

    [self informTargetsAboutNewFrameAtTime:frameTime];
}

@end

插入这个过滤器后,我看到控制台显示了“设置完成”和“绘制VBO”。但是,在调用目标(在本例中为GPUImageView)后,它在目标的绘图调用处崩溃,该调用使用了glDrawArrays
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

这是包含此行的完整方法。
- (void)newFrameReadyAtTime:(CMTime)frameTime;
{
    [GPUImageOpenGLESContext useImageProcessingContext];
    [self setDisplayFramebuffer];

    [displayProgram use];

    glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    static const GLfloat textureCoordinates[] = {
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,
    };

    glActiveTexture(GL_TEXTURE4);
    glBindTexture(GL_TEXTURE_2D, inputTextureForDisplay);
    glUniform1i(displayInputTextureUniform, 4); 

    glVertexAttribPointer(displayPositionAttribute, 2, GL_FLOAT, 0, 0, imageVertices);
    glVertexAttribPointer(displayTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    [self presentFramebuffer];
}

非常感谢您的帮助,我已经苦苦思索这个问题有一段时间了。

2个回答

2
看起来崩溃的原因是当GPUImageView-newFrameReadyAtTime:执行时,GL_ARRAY_BUFFER仍然绑定在上面。
尝试在-setupBuffers的末尾取消绑定缓冲区(即将其绑定到0)。
glBindBuffer(GL_ARRAY_BUFFER, 0);

这是一个问题的原因是因为 GPUImage 在从一个 GPUImageInput(如GPUImageFilter、GPUImageView)到下一个时使用相同的 OpenGL 上下文。我认为这主要是为了使每个步骤都能输出到一个 OpenGL 纹理,然后直接将该纹理提供给下一个 GPUImageInput。
因此,由于 GL_ARRAY_BUFFER 仍然处于绑定状态,GPUImageView-newFrameReadyAtTime 中的 glVertexAttribPointer 的行为会改变,实际上会尝试在 imageVertices 的偏移量处指向已填充的 VBO,这是无意义的,并且可能导致崩溃。请参见 glVertexAttribPointer 文档

0

我觉得下面的代码看起来不对劲。为什么要启用顶点属性数组4和5?你应该在你打算使用的属性位置上启用数组。

//position vbo
glEnableVertexAttribArray(4);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), 0);

//texcoord vbo
glEnableVertexAttribArray(5);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), 0);

如果你的顶点属性位于位置0,你应该启用attrib 0并设置attrib 0的指针。如果它位于位置4(我怀疑),那么你应该启用attrib 4并设置位置4的指针。我想不出为什么它会像你所拥有的那样不匹配。

你应该通过设置布局属性、在着色器链接之前使用glBindAttribLocation或在链接后使用glGetAttribLocation来获取正确的位置。

如果这不合理,请让我知道。


抱歉,那并不是我想要粘贴的内容。我在尝试一些东西。最初它应该是0和1。现在我正在修复这篇文章。 - MarkPowell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接