web-dev-qa-db-ja.com

GLSLでテクスチャの色相を変更するにはどうすればよいですか?

GLSL(フラグメントシェーダー)を使用して2D OpenGLテクスチャの色相を効率的に変更する方法はありますか?

誰かがそれのためのコードを持っていますか?

PDATE:これは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

Atan内でQでIを切り替えようとしましたが、0°付近でも結果が間違っています

ヒントはありますか?

比較のために必要な場合、これは元の変更されていない画像です。 enter image description here

25
Andrea3000

@awoodlandの言うことは正しいですが、その方法は輝度の変化に問題を引き起こす可能性があると私は信じています。

HSVおよびHLSカラーシステムは、いくつかの理由で問題があります。私は最近これについて色彩科学者と話しました、そして彼の推薦はYIQまたはYCbCr空間に変換し、それに応じて彩度チャネル(I&Q、またはCb&Cr)を調整することでした。 (その方法を学ぶことができます ここ および ここ 。)

これらのスペースの1つに入ると、hue = atan(cr/cb)(cb == 0を監視)を実行することにより、彩度チャネルによって形成される角度から色相を取得できます。これにより、ラジアン単位の値が得られます。色相の回転量を足して回転させるだけです。それが済んだら、chroma = sqrt(cr*cr+cb*cb)で彩度の大きさを計算できます。 RGBに戻るには、Cr = chroma * sin (hue)Cb = chroma * cos (hue)を使用して新しいCbとCr(またはI&Q)を計算します。次に、上記のWebページで説明されているように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;
}
28
user1118321

Andrea3000、ネット上のYIQの例を比較すると、あなたの投稿に出くわしましたが、コードの「更新された」バージョンに問題があると思います。「mat3」の定義が反転/反転されていると確信しています。列/行の順序...(おそらくそれがまだ問題を抱えていた理由です)...

参考:OpenGLマトリックスの順序:「より多くの値の場合、マトリックスは列優先の順序で入力されます。つまり、最初のX値が最初の列、2番目のX値が次の列というように続きます。」参照: http://www.opengl.org/wiki/GLSL_Types

mat2(
float, float,   //first column
float, float);  //second column
4
Joe