Как изменить цвет текстуры с помощью GLSL? - PullRequest
22 голосов
/ 11 февраля 2012

Есть ли способ эффективно изменить оттенок 2D-текстуры OpenGL с помощью GLSL (фрагментный шейдер)?

У кого-нибудь есть код для этого?

ОБНОВЛЕНИЕ: Этот код является результатом предложения user1118321:

uniform sampler2DRect texture;
const mat3 rgb2yiq = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);
const mat3 yiq2rgb = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.1070, 1.7046);
uniform float hue;

void main() {

vec3 yColor = rgb2yiq * texture2DRect(texture, gl_TexCoord[0].st).rgb; 

float originalHue = atan(yColor.b, yColor.g);
float finalHue = originalHue + hue;

float chroma = sqrt(yColor.b*yColor.b+yColor.g*yColor.g);

vec3 yFinalColor = vec3(yColor.r, chroma * cos(finalHue), chroma * sin(finalHue));
gl_FragColor    = vec4(yiq2rgb*yFinalColor, 1.0);
}

И это результат по сравнению со ссылкой:

enter image description here

Я пытался переключить I с помощью Q внутри atan, но результат неправильный даже при 0 °

У вас есть подсказка?

Если необходимо для сравнения, это оригинальное неизмененное изображение: enter image description here

Ответы [ 2 ]

26 голосов
/ 11 февраля 2012

Хотя то, что @awoodland говорит правильно, этот метод может вызвать проблемы с изменением яркости, я считаю.

Цветовые системы HSV и HLS проблематичны по ряду причин. Я недавно говорил с цветным ученым, и его рекомендация состояла в том, чтобы преобразовать в пространство YIQ или YCbCr и соответствующим образом настроить каналы цветности (I & Q или Cb & Cr). (Вы можете узнать, как это сделать здесь и здесь .)

Оказавшись в одном из этих пространств, вы можете получить оттенок от угла, образованного каналами цветности, выполнив hue = atan(cr/cb) (наблюдая за cb == 0). Это дает вам значение в радианах. Просто поверните его, добавив величину вращения оттенка. Как только вы это сделаете, вы можете рассчитать величину цветности с помощью chroma = sqrt(cr*cr+cb*cb). Чтобы вернуться к RGB, рассчитайте новые Cb и Cr (или I & Q), используя Cr = chroma * sin (hue), Cb = chroma * cos (hue). Затем преобразуйте обратно в RGB, как описано на приведенных выше веб-страницах.

РЕДАКТИРОВАТЬ: Вот решение, которое я протестировал, и, кажется, дает мне те же результаты, что и ваша ссылка Вероятно, вы можете свернуть некоторые из точечных произведений в матричные умножения:

uniform sampler2DRect inputTexture;
uniform float   hueAdjust;
void main ()
{
    const vec4  kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
    const vec4  kRGBToI     = vec4 (0.596, -0.275, -0.321, 0.0);
    const vec4  kRGBToQ     = vec4 (0.212, -0.523, 0.311, 0.0);

    const vec4  kYIQToR   = vec4 (1.0, 0.956, 0.621, 0.0);
    const vec4  kYIQToG   = vec4 (1.0, -0.272, -0.647, 0.0);
    const vec4  kYIQToB   = vec4 (1.0, -1.107, 1.704, 0.0);

    // Sample the input pixel
    vec4    color   = texture2DRect (inputTexture, gl_TexCoord [ 0 ].xy);

    // Convert to YIQ
    float   YPrime  = dot (color, kRGBToYPrime);
    float   I      = dot (color, kRGBToI);
    float   Q      = dot (color, kRGBToQ);

    // Calculate the hue and chroma
    float   hue     = atan (Q, I);
    float   chroma  = sqrt (I * I + Q * Q);

    // Make the user's adjustments
    hue += hueAdjust;

    // Convert back to YIQ
    Q = chroma * sin (hue);
    I = chroma * cos (hue);

    // Convert back to RGB
    vec4    yIQ   = vec4 (YPrime, I, Q, 0.0);
    color.r = dot (yIQ, kYIQToR);
    color.g = dot (yIQ, kYIQToG);
    color.b = dot (yIQ, kYIQToB);

    // Save the result
    gl_FragColor    = color;
}
3 голосов
/ 06 июля 2012

Andrea3000, сравнивая примеры YIQ в сети, я натолкнулся на вашу публикацию, но я думаю, что есть проблема с «обновленной» версией вашего кода… я уверен, что ваши определения «mat3» перевернуты / плюхнулся на порядок столбцов / строк ... (может быть, поэтому у вас все еще были проблемы) ...

FYI: Порядок в матрице OpenGL: «Для большего количества значений матрицы заполняются в основном порядке столбцов. То есть, первые значения X - это первый столбец, вторые значения X - следующий столбец и т. Д.». Смотри: http://www.opengl.org/wiki/GLSL_Types

mat2(
float, float,   //first column
float, float);  //second column
...