Как загрузить PNG альфа с какао? - PullRequest
1 голос
/ 29 октября 2009

Я разрабатываю приложение для iPhone OpenGL, и мне нужно использовать некоторые текстуры с прозрачностью. Я сохранил изображения в формате PNG. У меня уже есть весь код для загрузки PNG как текстур OpenGL и их рендеринга. Это работает нормально для всех изображений, которые не имеют прозрачности (все альфа-значения равны 1,0). Однако теперь, когда я пытаюсь загрузить и использовать некоторые PNG-файлы, которые имеют прозрачность (варьирующие альфа-значения), моя текстура испорчена, как будто она загружает данные неправильно или что-то в этом роде.

Я почти уверен, что это связано с загрузкой кода, который использует некоторые API-интерфейсы Cocoa. Я выложу здесь соответствующий код.

Каков наилучший способ загрузки PNG или любого формата изображения, поддерживающего прозрачность, на OSX / iPhone? Этот метод чувствует себя окольным. Визуализация его в CGContext и получение данных кажется странным.

* ЗАГРУЗКА *

CGImageRef CGImageRef_load(const char *filename) {
    NSString *path = [NSString stringWithFormat:@"%@/%s",
                      [[NSBundle mainBundle] resourcePath],
                      filename];
    UIImage *img = [UIImage imageWithContentsOfFile:path];
    if(img) return [img CGImage];
    return NULL;
}

unsigned char* CGImageRef_data(CGImageRef image) {
    NSInteger width = CGImageGetWidth(image);
    NSInteger height = CGImageGetHeight(image);
    unsigned char *data = (unsigned char*)malloc(width*height*4);

    CGContextRef context = CGBitmapContextCreate(data,
                                                 width, height,
                                                 8, width * 4,
                                                 CGImageGetColorSpace(image),
                                                 kCGImageAlphaPremultipliedLast);

    CGContextDrawImage(context,
                       CGRectMake(0.0, 0.0, (float)width, (float)height),
                       image);
    CGContextRelease(context);

    return data;
}

* ЗАГРУЗКА *

(define (image-opengl-upload data width height)
  (let ((tex (alloc-opengl-image)))
    (glBindTexture GL_TEXTURE_2D tex)
    (glTexEnvi GL_TEXTURE_ENV GL_TEXTURE_ENV_MODE GL_DECAL)
    (glTexImage2D GL_TEXTURE_2D
                  0
                  GL_RGBA
                  width
                  height
                  0
                  GL_RGBA
                  GL_UNSIGNED_BYTE
                  (->void-array data))
    (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)    
    (glBindTexture GL_TEXTURE_2D 0)
    tex))

Ответы [ 4 ]

2 голосов
/ 29 октября 2009

Чтобы быть явным ...

Наиболее распространенная проблема с загрузкой текстур с использованием Core Image заключается в том, что он настаивает на преобразовании данных в предварительно умноженный альфа-формат. В случае PNG, включенных в комплект, это фактически делается на этапе предварительной обработки в процессе сборки. Несоблюдение этого требования приводит к темным полосам вокруг смешанных объектов.

Чтобы принять это во внимание, используйте glBlendMode(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) вместо glBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). Если вы хотите использовать альфа-каналы для чего-то другого, чем обычное смешивание, ваш единственный вариант - переключиться на другой формат и загрузчик (как предложено, но по другим причинам).

ETA: проблема предварительного умножения также существует в Mac OS X, но предварительная обработка зависит от iPhone.

1 голос
/ 29 октября 2009

Перед началом рендеринга поверхность Core Graphics должна быть очищена от всех нулей, поэтому я рекомендую использовать calloc вместо malloc или добавить memset после malloc.

Кроме того, я не уверен, что вы хотите, чтобы ваш TexEnv был установлен на GL_DECAL . Возможно, вы захотите оставить значение по умолчанию ( GL_MODULATE ).

Если вы не хотите использовать Core Graphics для декодирования изображений в формате PNG, я рекомендую вместо этого загрузить файл PVR. PVR - это чрезвычайно простой формат файла. Приложение под названием PVRTexTool входит в состав Imagination SDK, что позволяет легко преобразовывать PNG в PVR. SDK также включает в себя некоторый пример кода, который показывает, как анализировать их формат файла.

1 голос
/ 29 октября 2009

Я ничего не знаю об OpenGL, но Какао абстрагирует эту функциональность с помощью NSImage / UIImage.

0 голосов
/ 01 декабря 2010

Вы можете использовать PVR, но будут некоторые артефакты сжатия, поэтому я бы рекомендовал их только для текстур 3D-объектов или текстур, которые не требуют определенного уровня детализации, который PVR не может предложить, особенно с градиентами.

...