Неправильные цвета отображаются при загрузке 32-битного png с использованием stb_image и использованием GL_UNSIGNED_INT_8_8_8_8 в качестве параметра типа glTexImage2D
Я только учусь, как текстурировать в OpenGL, и меня немного смущают некоторые результаты, которые я получаю.
Я использую stb_image, чтобы загрузить следующее изображение png шахматной доски:
Когда я сохранил изображение PNG, я явно решил сохранить его как 32-битный. Это привело бы меня к мысли, что каждый компонент (RGBA) будет храниться как 8 битов в общей сложности 32 бита - размер целого числа без знака. Однако, используя следующий код:
unsigned char * texture_data =
stbi_load("resources/graphics-scene/tut/textures/checker.png", &w, &h, nullptr, 4);
// ...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0,
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture_data);
выходы:
Если я вместо этого использую GL_UNSIGNED_BYTE для параметра типа, я получаю правильные результаты.
Кроме того, если это помогает, я также попробовал следующее изображение:
который дает
GL_UNSIGNED_BYTE дает правильный результат и в этом случае.
Я не уверен, что это случай, когда я неправильно понял glTexImage2D или stb_image (конвертирует ли он загруженные данные в 8-битные? Это мне кажется маловероятным).
РЕДАКТИРОВАТЬ: я только что нашел соответствующий пост (уже искал некоторые, но не повезло). Однако ответ ( /questions/35483548/chto-oznachaet-glunsignedbyte-dlya-glteximage2d/35483556#35483556) меня смущает. Если это так - то, что параметр типа указывает, сколько байтов на компонент - тогда, что именно означают такие вещи, как GL_UNSIGNED_BYTE_3_3_2 и GL_UNSIGNED_INT_8_8_8_8???
1 ответ
Если это так - то, что параметр типа указывает, сколько байтов на компонент - тогда, что именно означают такие вещи, как GL_UNSIGNED_BYTE_3_3_2 и GL_UNSIGNED_INT_8_8_8_8???
Это делает оба, в зависимости от того, что является фактическим типом.
Если тип передачи пикселей - это просто тип данных, то он определяет размер данных для каждого компонента. Если в нем есть числа, то тип определяет размер данных на пиксель; числа указывают размеры отдельных компонентов в этом типе данных.
GL_UNSIGNED_INT_8_8_8_8
означает, что OpenGL будет интерпретировать каждый пиксель как целое число без знака. Первый компонент будет старшими 8 битами, следующий будет следующими 8 битами и так далее.
Однако, из-за чего ваша проблема заключается в том, что STB-изображение не работает с целыми числами без знака. Каждый пиксель записывается в виде 4 отдельных байтов в порядке RGBA. В основном это делает это:
GLubyte arr[4] = {red, green, blue, alpha};
Теперь, это может звучать как то же самое. Но это не так. Причина, почему это связано с порядком байтов.
Когда вы делаете это в C/C++:
GLuint foo = 0;
foo |= (red << 24);
foo |= (green << 16);
foo |= (blue << 8);
foo |= (alpha << 0);
Типы данных OpenGL требуют GLuint
быть целым без знака целым размером 32 бита. И при условии, что red
, green
, blue
, а также alpha
являются все GLubyte
s (8-битные целые числа без знака), C / C++ говорит, что это упакует red
бит в старший 8-битный байт, green
в следующий и так далее. Стандарты C и C++ требуют, чтобы это работало.
Однако стандарты C и C++ не требуют, чтобы это работало:
GLubyte *ptr = (GLubyte*)&foo;
ptr[0] == ((foo >> 24) & 0xFF);
То есть первый байт памяти, на который указывает foo
не должен быть red
составная часть.
В порядке байтов с прямым порядком байтов младший байт 32-разрядного целого числа сохраняется первым, а не последним.
Когда OpenGL видит GL_UNSIGNED_INT
это означает, что эти четыре байта будут интерпретироваться точно так же, как ваш процессор. Так GL_UNSIGNED_INT_8_8_8_8
будет делать эквивалент foo
выше. Первый байт памяти, который он видит, будет интерпретироваться на машине с прямым порядком байтов как младший, а не старший.
STB-изображение не выводится GL_UNSIGNED_INT_8_8_8_8
, Каждый пиксель обрабатывается как массив из 4 байтов, например arr
выше. Следовательно, вы должны сообщить OpenGL, что именно так хранятся ваши данные. Итак, вы говорите, что каждый компонент - один байт. Который является то, что GL_UNSIGNED_BYTE
делает.