2012-02-10 19 views
21

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

誰かにコードがありますか?

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

Q内のatanしかし結果は間違っても約0°

何かヒント?

比較のために必要であれば

が、これはオリジナルの無修正画像です:何@awoodland言うことは正しいです enter image description here

+5

それは(1,1,1)ベクトルの周りのトリプルRGBの回転だ - あなたの色相シフトが一定である場合は、シェーダ – Flexo

+0

で行列の乗算としてそれを表現することができ、あなたはスキップすることができますatan、sqrt、sin、およびcosです。あなたがしているのは、それらを極座標に変換し、角度に加え、変換することです。この計算は2x2回転行列で行うことができます。 yiq空間で他の計算を行う必要がない場合は、変換全体を事前に計算することができます。あなたのrgb2yiqに2次元回転(3x3にパディング)とyiq2rgbを掛け合わせると、プロセス全体を行う1つの大きな3x3行列が得られます。 @Flexoのように、(1,1,1)ベクトルのまわりを回転するだけです。 –

答えて

23

ますが、その方法は、輝度の変化に問題が発生する可能性があり、私は信じています。

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

したら、それらのスペースの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; 
} 
+0

ありがとう、私はちょうどそれを実装しましたが、正しく動作していないようです..実際に色相の変更を与えるが、Photoshopの色相調整(例えば)とはまったく異なります。私はそれをYIQに変換することを決めました。なぜなら、YCbCrでは最悪の結果が出ていたからです。したがって、私は '色相= atan2(Q、I)'、 '彩度= sqrt(I * I + Q * Q)'、 'I =彩度* sin(色相)'、 'Q = chorma * cos ) '。それが正しいか?何か不足していますか? – Andrea3000

+0

それは私にとって正しいようです。結果は何ですか? (色相が間違っているのか、輝度と彩度が乱れているのでしょうか?) 'atan2()'呼び出しでIとQを逆にすると結果はもっと見えますか?もしあなたがコードをいくつか投稿したなら、あなたのためにそれを再確認することができます。 – user1118321

+0

ご注意いただきありがとうございます。コードと結果のスナップショットで質問を更新しました。 – Andrea3000

3

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

FYI: : "より多くの値の場合、行列は列の大きな順序で塗りつぶされます。つまり、最初のX値は最初の列、2番目のX値は次の列です。参照:http://www.opengl.org/wiki/GLSL_Types

mat2(
float, float, //first column 
float, float); //second column 
関連する問題