Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Программирование графики > OpenGL и неправильный расчёт альфы


Автор: k.sovailo 03.07.19, 15:49
Добрый день. Сел писать графику на OpenGL < 3.0, то есть без шейдеров, VAO и прочего. Думал, что легче будет, да и хотел бы гарантировать, что программа запустится на любом железе, вплоть до древнего хлама. Ну и наткнулся на проблему. Когда рисуется квадрат с текстурой белого полупрозрачного цвета (т.е. альфа у каждого пикселя = 0.5) поверх белого непрозрачного квадрата, то получается серый.

Настройки каждой текстуры:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
        glGenTextures(1, texture);
        glBindTexture(GL_TEXTURE_2D, *texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
        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_RGBA, bitmapdata.Width, bitmapdata.Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, bitmapdata.Scan0);


И рисование:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
        unsigned int len = drawlist.legth();
        GlBlendEquation glBlendEquation = (GlBlendEquation)glutGetProcAddress("glBlendEquation");
     
        glClear(GL_COLOR_BUFFER_BIT);
        for (int i = 0; i < len; i++)
        {
            glBlendEquation(0x8006);//GL_FUNC_ADD
            glBindTexture(GL_TEXTURE_2D, drawlist[i].texture);
            glBegin(GL_QUADS);
            glBlendEquation(0x8006);//На всякий случай после begin
            
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
            glColor4f(1.0f, 1.0f, 1.0f, drawlist[i].alpha);
     
            glTexCoord2f(0.0f, 0.0f);
            glVertex2fv(&drawlist[i].points[0]);
            glTexCoord2f(1.0f, 0.0f);
            glVertex2fv(&drawlist[i].points[2]);
            glTexCoord2f(1.0f, 1.0f);
            glVertex2fv(&drawlist[i].points[4]);
            glTexCoord2f(0.0f, 1.0f);
            glVertex2fv(&drawlist[i].points[6]);
            glEnd();
     
        }
     
        glBindTexture(GL_TEXTURE_2D, 0);
        glFlush();
        glutSwapBuffers();


Я подумал, что в glBlendEquation оказался GL_MAX, поэтому и сделал костыль, но не помогло. При этом картинки с общей альфой (т.е. альфа каждого пикселя 255, но рисуется поверх полупрозрачного квадрата) оно рисует нормально. Как быть? Пока что вижу только способ переписать всё с шейдерами, а если на какой-то машине не запуститься, то запускать альтернативу, которая будет плохо рисовать всякие туманы и контуры (что в принципе приемлемо, но хотелось бы знать, в чём причина).

На изображении на самом деле рисуется изображение с равномерным градиентом от белого к прозрачному.
____________________.jpg (, : 1094)

Автор: business user 08.07.19, 12:15
Всё правильно работает.
Через толстое-толстое стекло ты смотришь на белый квадрат. Какого цвета он будет?
Тот же квадрат перед тобой, а за ним стекло. Теперь какой цвет?
Раньше так писали
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Автор: k.sovailo 09.07.19, 16:31
Цитата business user @
Какого цвета он будет?

Белый.
Цитата business user @
Теперь какой цвет?

Тоже белый, разве нет? Почему он должен быть не белым? Я смотрю на белую стену сквозь тонкое белое стекло, сквозь толстое белое, без стекла - всё равно всё будет белым?

цвет = альфа текстуры * цвет текстуры + (1 - альфа текстуры) * цвет в буфере
В нашем случае: цвет = А * белый + (1 - А) * белый = 1 * белый = белый

И там стоял glBlendFunc где-то в инициализации, в фрагменты, что я показал, он не вошёл. Но я поставил его ещё пару раз в цикл на всякий случай, результат тот же. Я просто не понимаю логику OpenGL.

Автор: Mikle 10.07.19, 10:41
Я OpenGL не знаю, но в Direct3D будет белый, значит и здесь должно быть так же.
Могу предположить: текстура белого полупрозрачного квадрата, случайно, не из PNG грузится, который premultipled? Если да, до должно быть как-то так:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

Автор: k.sovailo 12.07.19, 10:29
Цитата Mikle @
текстура белого полупрозрачного квадрата, случайно, не из PNG грузится, который premultipled

Точно! Проверил побайтово получившуюся картинку, посмотрел на PixelFormat, и таки да, она premultiplied. Не думал, что LockBits может вернуть не тот PixelFormat, что в картинке, и даже не тот, что ей передают... Кажется, пора искать какую-то библиотеку по открытию изображений.

Добавлено: хотя если представить, что Bitmap при загрузке из файла на самом деле загрузку откладывает, а настоящий формат оно узнаёт только когда его в явном виде просят вытянуть изображение побайтово, то это обретает смысл.

Автор: Mikle 12.07.19, 13:37
Цитата k.sovailo @
Кажется, пора искать какую-то библиотеку по открытию изображений.

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

Автор: k.sovailo 12.07.19, 17:08
Mikle, кстати да, именно фотошоп я и использовал. Я знаю, что такое premultiplied, мне просто надоела ситуация, когда GDI+ (сейчас все изображения загружаются через него) постоянно выдаёт не то, что я прошу.

Автор: Mikle 12.07.19, 17:22
Цитата k.sovailo @
просто надоела ситуация, когда GDI+ (сейчас все изображения загружаются через него) постоянно выдаёт не то, что я прошу.

Ещё раз - файл premultiplied ни чем не отличается от не premultiplied. Само слово "premultiplied" - это свойство изображения, а не файла. Либо поменяй glBlendFunc как я писал выше, чтобы пользоваться premultiplied, либо, если надо именно обычную альфу, сохраняй с помощью GDI+ или с помощь какого-нибудь Paint.net. Фотошоп при сохранении в PNG меняет не просто формат, он меняет сами данные - умножает цвет на альфу.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)