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
после ссылки.
Дайте мне знать, если это не имеет смысла.