Как загрузить текстуру OpenGL из ARGB NSImage без излишеств? - PullRequest
2 голосов
/ 10 февраля 2011

Я пишу приложение для Mac OS> = 10.6, которое создает текстуры OpenGL из изображений, загруженных с диска.

Сначала я загружаю изображение в NSImage.Затем я получаю NSBitmapImageRep из изображения и загружаю данные пикселей в текстуру, используя glTexImage2D.

Для изображений RGB или RGBA, он работает отлично.Я могу передать либо 3 байта / пиксель RGB, либо 4 байта RGBA и создать 4-байтовую / пиксельную RGBA-текстуру.

Однако мне только что тестер отправил мне изображение JPEG (снято наCanon EOS 50D, не уверен, как он был импортирован), который, кажется, имеет порядок следования байтов ARGB.

Я нашел сообщение в этой теме: (http://www.cocoabuilder.com/archive/cocoa/12782-coregraphics-over-opengl.html) Это предполагает, что я указываю параметр формата GL_BGRA для glTexImage2Dи тип GL_UNSIGNED_INT_8_8_8_8_REV.

Это кажется логичным и кажется, что оно должно работать, но это не так. Я получаю разные, но все же неправильные, значения цвета.

Я написал "swizzling "(ручной байт-обмен) код, который перетасовывает данные изображений ARGB в новый буфер RGBA, но этот побайтовый переход будет медленным для больших изображений.

Я также хотел бы понятькак сделать так, чтобы это работало «правильно».

В чем заключается хитрость загрузки данных ARGB в текстуру RGBA OpenGL?

Мой текущий вызов xxx выглядит следующим образом:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newWidth, newHeight, 0, format, GL_UNSIGNED_BYTE, pixelBuffer);

где либо RGBили RGBA.

Я пытался использовать:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newWidth, newHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);

Когда мой репортер сообщает, что он в "альфа-первом" порядке.

В качестве второго вопроса яТакже мы читаем, что «родной» формат большинства видеокарт - GL_BGRA, поэтому создание текстуры в этом формате приводит к более быстрому рисованию текстуры.Скорость рисования текстур важнее, чем скорость загрузки текстур, поэтому «перебор» данных в формате BGRA заранее стоил бы того.Я попытался попросить OpenGL создать текстуру BGRA, указав «внутренний формат» GL_RGBA, но в результате получилось полностью черное изображение.Моя интерпретация документов заставляет меня ожидать, что glTexImage2D будет байт-своп данных, когда он читает их, если исходный и внутренний форматы отличаются, но вместо этого я получаю ошибку OpenGL 0x500 (GL_INVALID_ENUM), когда я пытаюсь указать «internalformat»GL_RGBA.Чего мне не хватает?

Ответы [ 3 ]

4 голосов
/ 10 февраля 2011

Я не знаю, как загрузить данные ARGB непосредственно в текстуру, но есть лучший обходной путь, чем простое использование процессора.Вместо этого вы можете сделать это очень эффективно на GPU:

  1. Загрузите данные ARGB во временную текстуру RGBA.
  2. Нарисуйте полноэкранный квад с этой текстурой, одновременно визуализируя в цельтекстуры, используя простой пиксельный шейдер.
  3. Продолжайте загружать другие ресурсы, не нужно останавливать конвейер GPU.

Пример пиксельного шейдера:

#version 130
uniform sampler2DRect unit_in;
void main() {
    gl_FragColor = texture( unit_in, gl_FragCoord.xy ).gbar;
}
1 голос
/ 28 января 2015

Этот вопрос старый, но в случае, если кто-то еще ищет его, я нашел не совсем безопасное, но эффективное решение.Проблема в том, что каждое 32-битное значение RGBA имеет A в качестве первого байта, а не последнего.

NBitmapImageRep.bitmapData дает вам указатель на тот первый байт, который вы даете OpenGL в качестве указателя на его пиксели.Просто добавьте 1 к этому указателю, и вы укажете на значения RGB в правильном порядке, с A следующего пикселя в конце.

Проблемы с этим заключаются в том, что последний пиксель будет принимать значение Aодин байт за конец изображения, и все значения A равны одному пикселю.Но, как и спрашивающий, я получаю это при загрузке JPG, так что альфа все равно не имеет значения.Похоже, это не вызывает проблем, но я бы не стал утверждать, что это «безопасно».

1 голос
/ 10 февраля 2011

Вы визуализируете это с OpenGL, верно? Если вы хотите сделать это простым способом, вы можете сделать так, чтобы ваш пиксельный шейдер отображал цвета в реальном времени. Для видеокарты это не проблема, они предназначены для более сложных вещей:).

Вы можете использовать шейдер так:

uniform sampler2D image;
void main()
{
    gl_FragColor = texture2D(image, gl_FragCoord.xy).gbar;
}

Если вы не знаете о шейдерах, прочитайте этот текст здесь: http://www.lighthouse3d.com/opengl/glsl/

...