OpenGL ES 1.1: Как изменить цвет текстуры без потери яркости? - PullRequest
5 голосов
/ 05 декабря 2010

У меня есть частицы, которые я хочу изменить в коде, поэтому можно использовать любой цвет.Так что у меня есть только одна текстура, которая в основном имеет яркость.

Я использовал glColor4f(1f, 0f, 0f, 1f);, чтобы применить цвет.

Каждый blendfunc, который я пробовал, приблизился к работекак на последнем рисунке ниже.Я все еще хочу сохранить яркость, как на средней картинке.(Это похоже на фильтры Overlay или Soft Light в Photoshop, если цветовой слой был поверх текстурного слоя.)

Есть идеи, как это сделать без программируемых шейдеров?Кроме того, поскольку это частицы, я не хочу, чтобы за ними был черный ящик, я хочу добавить его на сцену.

alt text

Ответы [ 2 ]

9 голосов
/ 07 декабря 2010

Вот решение, которое может быть близко к тому, что вы ищете:

glColor4f(1.0f, 0.0f, 0.0f, 1.0f);

glActiveTexture( GL_TEXTURE0 );
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, spriteTexture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

glActiveTexture( GL_TEXTURE1 );
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, spriteTexture);    
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );

То, что он делает, умножает исходную текстуру на указанный цвет и затем добавляет значения пикселей исходной текстуры сверху:

final_color.rgba = original_color.rgba * color.rgba + original_color.rgba;

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

Если вы хотите сохранить альфа-значение текстуры, вам нужно использовать GL_COMBINE вместо GL_ADD (+ правильно установить GL_COMBINE_RGB и GL_COMBINE_ALPHA).

Вот некоторые результаты использования этой техники на вашей текстуре. alt text

2 голосов
/ 20 марта 2011

нонсенс! Вам не нужно использовать несколько текстур. Просто умножьте свою альфу.

Если вы предварительно умножаете альфа на изображение после того, как загрузите его и до того, как создадите для него текстуру GL, тогда вам понадобится только одна единица текстуры для режима env текстуры GL_ADD.

Если вы работаете на iOS, то библиотеки Apple могут быть предварительно умножены для вас. См. Пример класса Texture2D и найдите флаг kCGImageAlphaPremultipliedLast.

Если вы не используете загрузчик изображений, который поддерживает предварительное умножение, вам придется делать это вручную после загрузки изображения. Псевдокод:

uint8* LoadRGBAImage(const char* pImageFileName) {
    Image* pImage = LoadImageData(pImageFileName);
    if (pImage->eFormat != FORMAT_RGBA)
        return NULL;

    // allocate a buffer to store the pre-multiply result
    // NOTE that in a real scenario you'll want to pad pDstData to a power-of-2
    uint8* pDstData = (uint8*)malloc(pImage->rows * pImage->cols * 4);
    uint8* pSrcData = pImage->pBitmapBytes;
    uint32 bytesPerRow = pImage->cols * 4;

    for (uint32 y = 0; y < pImage->rows; ++y) {
        byte* pSrc = pSrcData + y * bytesPerRow;
        byte* pDst = pDstData + y * bytesPerRow;
        for (uint32 x = 0; x < pImage->cols; ++x) {
            // modulate src rgb channels with alpha channel
            // store result in dst rgb channels
            uint8 srcAlpha = pSrc[3];
            *pDst++ = Modulate(*pSrc++, srcAlpha);
            *pDst++ = Modulate(*pSrc++, srcAlpha);
            *pDst++ = Modulate(*pSrc++, srcAlpha);
            // copy src alpha channel directly to dst alpha channel
            *pDst++ = *pSrc++;
        }
    }

    // don't forget to free() the pointer!
    return pDstData;
}

uint8 Modulate(uint8 u, uint8 uControl) {
    // fixed-point multiply the value u with uControl and return the result
    return ((uint16)u * ((uint16)uControl + 1)) >> 8;
}

Лично я использую libpng и предварительно умножаю вручную.

В любом случае, после предварительного умножения просто свяжите байтовые данные как текстуру RGBA OpenGL. Использование glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); с одним текстурным блоком должно быть все, что вам нужно после этого. Вы должны получить точно (или чертовски близко) к тому, что вы хотите. Возможно, вам придется использовать glBlendFunc (GL_SRC_ALPHA, GL_ONE); а также, если вы действительно хотите, чтобы вещь выглядела блестящей между прочим.

Это немного отличается от метода Ozirus. Он никогда не «уменьшает» значения RGB текстуры путем предварительного умножения, поэтому каналы RGB добавляются слишком сильно и выглядят как размытые / слишком яркие.

Полагаю, что метод предварительного умножения больше похож на Overlay, тогда как метод Ozirus - Soft Light.

Подробнее см .:

http://en.wikipedia.org/wiki/Alpha_compositing

Поиск "предварительно умноженная альфа"

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