iOS: библиотека GPUImage и VBO

Я использую замечательную библиотеку Брэда Ларсона для обработки изображений. Пока это было здорово. Тем не менее, я пытаюсь добавить фильтр, чтобы разрешить деформацию сетки, и столкнулся с небольшим количеством проблем. В частности, я хочу иметь фильтр, который использует VBO для рендеринга Quad, чтобы я мог в конечном итоге динамически изменять вершины для деформации.

Первый шаг использования 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

Подключив этот фильтр, я вижу: "Настройка завершена" и "Draw 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 ответа

Решение

Вероятно, сбой происходит потому, что GL_ARRAY_BUFFER все еще связан, когда GPUImageView-newFrameReadyAtTime: выполняет.

Попробуйте открепить буфер (т.е. связать его с 0) в конце -setupBuffers:

glBindBuffer(GL_ARRAY_BUFFER, 0);

Причина в том, что проблема в том, что GPUImage использует тот же контекст OpenGL из одного GPUImageInput (например GPUImageFilter, GPUImageView) к следующему. Я верю в основном для того, чтобы каждый шаг мог выводить текстуру OpenGL, а затем иметь эту текстуру, непосредственно доступную для следующего GPUImageInput,

Потому, что GL_ARRAY_BUFFER по-прежнему связано поведение glVertexAttribPointer внутри GPUImageView-newFrameReadyAtTime изменения, эффективно пытаясь указать displayPositionAttribute атрибут заполненного VBO со смещением imageVertices, что бессмысленно и может вызвать сбой. Смотрите документацию по glVertexAttribPointer.

Этот код ниже выглядит не совсем правильно для меня. Почему вы включаете массив атрибутов вершин 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 после ссылки.

Дайте мне знать, если это не имеет смысла.

Другие вопросы по тегам