Мобильные платформы
GameDev.ru / Мобильные платформы / Форум / iPhone OpenGL ES рендеринг в UIImage

iPhone OpenGL ES рендеринг в UIImage

Поделиться
himuraПользовательwww17 июля 201212:28#0
Предисловие: понимаю, что это форум геймдева и моя проблема к геймдеву не сильно относится, но где как не здесь есть люди, которые отлично разбираются в OpenGL, так что надеюсь на ваше понимание и не закидывание меня камнями)

Здравствуйте, в процессе написания фильтров для картинки (OpenGL ES 2.0 используются  шейдеры), возникла одна проблема, если тестить на симуляторе то текстура в картинку рендерится корректно и отображается с применённым фильтром, но если тестить на девайсе то вообще ничего не отображается.

Инит текстуры:

    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1, &_name);
    glBindTexture(GL_TEXTURE_2D, self.name);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    self.data = (GLubyte *)calloc(1, self.bytes);
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst;
    CGContextRef context = CGBitmapContextCreate(self.data, self.pixelSize.width, self.pixelSize.height, 8, self.pixelSize.width * 4, colorSpace, bitmapInfo);
    CGContextDrawImage(context, CGRectMake(0, 0, self.pixelSize.width, self.pixelSize.height), image.CGImage);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.pixelSize.width, self.pixelSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, self.data);
    glBindTexture(GL_TEXTURE_2D, 0);

Создание фрейм буффера:

    glActiveTexture(GL_TEXTURE1);
    glGenFramebuffers(1, &_buffer);
    glBindFramebuffer(GL_FRAMEBUFFER, self.buffer);
    glBindTexture(GL_TEXTURE_2D, self.texture.name);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.width, self.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self.texture.name, 0);
    
    GLint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE) {
        NSAssert(NO, @"GLBuffer: Failed to make framebuffer object");
    }
    
    glBindTexture(GL_TEXTURE_2D, 0);

Рендеринг:

    [self.program use];
    [self.frameBuffer bind];
    
    glClearColor(0.0, 0.0, 0.0, 0.0);

    glActiveTexture(GL_TEXTURE2);
    [self.texture bind];

    glUniform1i([self uniformForKey:kTextureUniform], 2);
    
    glVertexAttribPointer([self attributeForKey:kPositionAttribute], 2, GL_FLOAT, 0, 0, [self.texture vertices]);
    glEnableVertexAttribArray([self attributeForKey:kPositionAttribute]);
    
    glVertexAttribPointer([self attributeForKey:kCoordinateAttribute], 2, GL_FLOAT, 0, 0, [self.texture coordinates]);
    glEnableVertexAttribArray([self attributeForKey:kCoordinateAttribute]);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    [self.frameBuffer unbind];
    [self.texture unbind];

перевод из текстуры в UIImage:

    [self.frameBuffer bind];
    GLubyte *rawPixels = (GLubyte *)calloc(1, self.texture.bytes);

    glReadPixels(0, 0, self.texture.pixelSize.width, self.texture.pixelSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawPixels);
    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rawPixels, self.texture.bytes, NULL);
    
    NSUInteger bytesPerRow = self.texture.pixelSize.width * 4;
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaLast;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    CGImageRef cgImage = CGImageCreate(self.texture.pixelSize.width, 
                                       self.texture.pixelSize.height, 
                                       8,
                                       32, 
                                       bytesPerRow, 
                                       colorSpace, 
                                       bitmapInfo, 
                                       dataProvider,
                                       NULL, 
                                       NO, 
                                       kCGRenderingIntentDefault);
    
    
    UIImage *image = [UIImage imageWithCGImage:cgImage];
    
    CGImageRelease(cgImage);
    CGDataProviderRelease(dataProvider);
    CGColorSpaceRelease(colorSpace);
    free(rawPixels);
    
    [self.frameBuffer unbind];

Естественно все что нужно делается в EAGLContext, шейдеры компилятся корректно, фрейм буффер также создается корректно. Есть только одно НО, если в коде рендеринга после glClearColor() поставить glClear(GL_COLOR_BUFFER_BIT), то картинки не видно и на симуляторе. Заранее спасибо

RudovПостоялецwww17 июля 201213:54#1
himura
На айфоне не пробовал OGL прогать. Но исходя из опыта проверь:

1) Нужен ли тебе буфер глубины?
2)
> Есть только одно НО, если в коде рендеринга после glClearColor() поставить
> glClear(GL_COLOR_BUFFER_BIT), то картинки не видно и на симуляторе.
В общем-то это делать обязательно!
3) glEnable(GL_TEXTURE_2D) ?
4) точно ли в шейдере ты используешь туже текстуру, GL_TEXTURE2?

himuraПользовательwww17 июля 201214:02#2
1) буффер глубины не нужен.
2) тогда странно если я добавляю эту строчку в код, даже на симуляторе айфона не видно результатов рендеринга, а если её нет, то всё ок, этот момент мне не понятен
3) не знаю как в других версиях GL, но в ES glEnable делать не нужно.
4) да в шейдере используется, таже текстура
RudovПостоялецwww17 июля 201214:12#3
Ну тогда ХЗ - специфики OGL ES не знаю
nightblazeПостоялецwww17 июля 201214:43#4
Не специалист в OGL, но знаю точно что при программировании не надо опираться на симулятор. На нем многое (в плане OGL) происходит не так, как на устройстве (например сглаживание на симуляторе есть, а на устройстве нет). Замечательная книга по OpenGL ES 2.0 (может чем-то поможет). Можно легко найти электронный вариант.
himuraПользовательwww17 июля 201215:04#5
за книжку спасибо, посмотрю мб что-нибудь найду) Больше всего меня смущает, что на девайсе ничего абсолютно нет,  даже если glClearColor(0.0, 0.0, 0.0, 1.0) и glClear(GL_COLOR_BUFFER_BIT) поидее должен быть хотябы что-то черноё, но даже этого нет
RudovПостоялецwww17 июля 201216:11#6
на ошибки проверил? точно их нету?
himuraПользовательwww17 июля 201216:20#7
Могу сказать что шейдеры компилятся и линкуются правильно, фрейм буффер и текстура создаются и биндятся тоже корректно, в самих шейдерах ошибки тоже нет. А вообще если смотреть на симулятор то к картинке шейдер применяется корректно, но вот токо на девайсе этого не видно)
RudovПостоялецwww17 июля 201216:54#8
Я имел в виду glGetError...
Очень похоже на то что фрэймбуффер не работает: попробуй что-нибудь простое вывести, типо фон одного цвета и треугольник другого цвета в центре.
himuraПользовательwww17 июля 201217:13#9
при создании фрейм буффера, glGetError ничо не поймал, а вот когда я рендерю текстуру, то он ловит glError: 0x0500 (дето закрался баг с фрейм буффером видимо), так что спасибо за наводку, буду гуглить)

update: Пофиксил то, всё что смог найти с помощью glGetError(), но ситуация не изменилась, как не было на айфоне видно картинки, так и не видно щас

RudovПостоялецwww17 июля 201219:44#10
Локализуй ошибку: для начала проверь что твой фрэймбуффер работает как надо - закрась его разным цветом в glClearColor и потом проверь что UIImage закрашен правильно. Ну и далее проверяй каждую часть вывода по отдельности.

Added: и кстати какого размера у тебя текстура фрэймбуфера и на каком девайсе проверяешь?

himuraПользовательwww18 июля 201211:12#11
текстура 256х256, тестил на 3GS c 5.0,  на 4-м c 4.3 и на 4S с 5.1

/ Форум / Мобильные платформы / Общее

Тема в архиве.

2001—2017 © GameDev.ru — Разработка игр