Странные результаты с использованием glTexImage2D - PullRequest
5 голосов
/ 09 июля 2011

Я пытался выяснить, как работает glTexImage2D, и увидел некоторые странные результаты из довольно четкого кода. Мой код просто рисует грубый круг в массив без знака длиной 256 * 256, а затем отправляет эти данные в текстуру. Однако отображаемая текстура становится вариациями красного и оранжевого, независимо от того, какие комбинации я выбираю в цикле создания изображения:

unsigned* data = new unsigned[256*256];
for (int y = 0; y < 256; ++y)
    for (int x = 0; x < 256; ++x)
        if ((x - 100)*(x - 100) + (y - 156)*(y - 156) < 75*75)
            data[256*y + x] = ((156 << 24) | (256 << 16) | (156 << 8) | (200 << 0));
        else
            data[256*y + x] = 0;  // I'd expect this to be transparent and the above to be slightly transparent and green, but it's red somehow.

glBindTexture(GL_TEXTURE_2D, texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)data);

Опции OpenGL:

    glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE);
//glEnable(GL_BLEND);
//glDisable(GL_CULL_FACE);

glGenTextures(1, &leaf[0]);
    createLeaf(leaf[0]);  // createLeaf(GLuint& texid) is posted entirely above

Остальная часть кода не делает ничего, кроме отображения текстуры на одном квадре в окне. (x64 win7)

Редактировать: Я точно попробовал решение Рикарда, и у меня все еще есть фиолетовый круг.

Ответы [ 2 ]

14 голосов
/ 10 июля 2011
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)data);

Сначала положительные вещи. Вы используете размер внутреннего формата (GL_RGBA8, а не GL_RGBA). Это очень хорошо; продолжай делать это. Вы четко понимаете разницу между внутренним форматом (GL_RGBA8) и форматом передачи пикселей (GL_RGBA). Это тоже хорошо.

Проблема заключается в следующем. Вы сказали OpenGL, что ваши данные представляют собой поток неподписанных байтов. Но это , а не поток байтов без знака; это поток беззнаковых целых чисел . Вот как вы объявили data, вот как вы заполнили data. Так почему ты лжешь OpenGL?

Проблема с вашими цветами. Это одно из ваших значений цвета:

 ((156 << 24) | (256 << 16) | (156 << 8) | (200 << 0))

Во-первых, 256 не является допустимым цветом. 256 в шестнадцатеричном формате - это 0x100, то есть два байта, а не один.

Целое число без знака, которое вы получите из этого:

 0x9D009CC8

Если предполагается, что это цвета RGBA в указанном порядке, то красный - 0x9D, зеленый - 0x00, синий - 0x9C, а альфа - 0xC8.

Теперь, поскольку вы, вероятно, работаете на компьютере с прямым порядком байтов, эти 4 байта хранятся в перевернутом виде, например:

 0xC89C009D

Когда вы говорите OpenGL притвориться, что это байтовый массив (а это не так), вы теряете преобразование с прямым порядком байтов. Таким образом, OpenGL видит байтовый массив, начинающийся с 0xC8, так что это красное значение. И так далее.

Вам нужно сообщить OpenGL, что вы на самом деле делаете: вы храните четыре 8-разрядных значения без знака в одном 32-разрядном целом числе без знака. Для этого используйте следующее:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (GLvoid*)data);

GL_UNSIGNED_INT_8_8_8_8 говорит, что вы передаете OpenGL массив беззнаковых 32-битных целых чисел (которыми вы являетесь). Первые 8 битов 32-разрядного целого числа - красные, вторые - зеленые, третьи - синие, а четвертые - альфа.

Итак, чтобы полностью исправить ваш код, вам нужно:

GLuint* data = new GLuint[256*256]; //Use OpenGL's types
for (int y = 0; y < 256; ++y)
    for (int x = 0; x < 256; ++x)
        if ((x - 100)*(x - 100) + (y - 156)*(y - 156) < 75*75)
            data[256*y + x] = ((0x9C << 24) | (0xFF << 16) | (0x9C << 8) | (0xC8 << 0));
        else
            data[256*y + x] = 0;  // I'd expect this to be transparent and the above to be slightly transparent and green, but it's red somehow.

glBindTexture(GL_TEXTURE_2D, texid);
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_BASE_LEVEL, 0);  //Always set the base and max mipmap levels of a texture.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (GLvoid*)data);

// Я бы ожидал, что он будет прозрачным, а вышеприведенный будет слегка прозрачным и зеленым, но каким-то образом красным.

Альфа не означает прозрачный ; это вообще ничего не значит, если вы не придете этому смысла. Альфа представляет прозрачность, только если вы используете смешивание и устанавливаете режим смешивания, который заставляет низкий альфа сделать вещи прозрачными. В противном случае это вообще ничего не значит.

2 голосов
/ 09 июля 2011

Если бы я делал то же самое, что и вы, я бы использовал массив беззнаковых символов вместо unsigned int с четырехкратной длиной.

unsigned char* data = new unsigned char[256*256*4];
for (int y = 0; y < 256; ++y)
    for (int x = 0; x < 256; ++x)
        if ((x - 100)*(x - 100) + (y - 156)*(y - 156) < 75*75){
            data[(256*y + x)*4+0] = 156;
            data[(256*y + x)*4+1] = 256;
            data[(256*y + x)*4+2] = 156;
            data[(256*y + x)*4+3] = 200;
        }else{
            data[(256*y + x)*4+0] = 0;
            data[(256*y + x)*4+1] = 0;
            data[(256*y + x)*4+2] = 0;
            data[(256*y + x)*4+3] = 0;
        }

glBindTexture(GL_TEXTURE_2D, texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)data);

Но ваш код мне подходит, и я не уверен, изменится ли приведенный выше код. Если результат тот же, то попробуйте изменить GL_RGBA8 на GL_RGBA. И что такое вариабельный тип texid. Я всегда вызывал glBindTexture с помощью GLuint с помощью refrense (& texid), но если ваш texid является указателем на GLuint (GLuint * texid;), тогда я думаю, что эта часть в порядке. (Правка: Просто поймите, что я не прав в последней части я думал о glGenTexture, а не о glBindTexture)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...