フラグメントシェーダを使うとどうしてもRGB!白・黒!みたいな色味になりがちなので、
色の操り方について、考えたので、そのまとめです。
#1.RGBではなくHSBを使う
極座標とHSB変換 - 2 #glsl pic.twitter.com/oRpdsOi7v3
— null (@null_tokyo) January 8, 2019
gl_FragColor
に渡す色は vec4(r, g, b, a)
なのでどうしてもRGBに寄りがちになります。
色をHSBで考えてから、RGBに変換して渡すと、狙った色を出しやすいです。
HSBはHue(色相)、Saturation(彩度)、Brightness(彩度)の略です。
全て、0~1の間で指定をします。色相環はは0が赤で0~1で一周します。
作例は極座標を使って、角度ごとに色相環を変化させた例です。
コードはHSB変換の例です。
// Function from Iñigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix(vec3(1.0), rgb, c.y);
}
void main() {
vec3 hsb = vec3(0.0, 0.5, 0.8);
vec3 color = hsb2rgb(hsb);
gl_FragColor = vec4(color, 1.0);
}
コードは以下を参考にしています
https://www.shadertoy.com/view/MsS3Wc
2.mix関数を使う
#glsl pic.twitter.com/3mdRSrhN0c
— null (@null_tokyo) January 23, 2019
こちらの色味を作る際に使用した例です。
色自体は薄い波打った円形を複数描いています。色は元々は白黒(0.0 ~ 1.0)です。
0.0 ~ 1.0の間の数値を渡すと、その数値に合わせてvec3型で色を返してくれます。
vec3 customColor(float d) {
vec3 gray = vec3(0.9254, 0.8657, 0.8914); //グレー
vec3 c = vec3(0.7210, 0.9118, 0.9083); //シアン
vec3 m = vec3(0.9180, 0.2236, 0.9688); //マゼンタ
vec3 y = vec3(1.0000, 0.9961, 0.3530); //イエロー
vec3 color = mix(gray, y, smoothstep(0.0, 0.8, d));
color = mix(color, m, smoothstep(0.0, 0.9, d));
color = mix(color, c, smoothstep(0.0, 1.0, d));
return color;
}
ポイントは mix()
です。
mix(x, y, a)
はxからyの間のある点aの値を取得することができます。(線形補間)
線形補間についてはこちら
https://qiita.com/niusounds/items/c4af702b06582590c82e
またaに渡す値を調節するのもポイントです。
smoothstep()で1を返す部分を微妙にずらすことで色の違いを出やすくしています。
//グレーとイエローを混ぜる
vec3 color = mix(gray, y, smoothstep(0.0, 0.8, d));
//さらにマゼンタを混ぜる
color = mix(color, m, smoothstep(0.0, 0.9, d));
//さらにさらにシアンを混ぜる
color = mix(color, c, smoothstep(0.0, 1.0, d));
この場合、色の混ぜる順番や、0 ~ 1の比率をいじることでいろんなタイプの色を出せるので、自分の好みの色に調整してみてください。
3.step関数を使う
step()
を使って色の出現率を操り、似たような色の組み合わせを引き出す方法です。
Algorithmic Color Spiral - 2 #glsl pic.twitter.com/OdbZ5NHXcv
— null (@null_tokyo) January 9, 2019
HSBの出る確率を調整してカラーパターンを作ります。
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix(vec3(1.0), rgb, c.y);
}
vec3 customColor(vec2 st, vec2 m) {
float r = snoise(st + m);
float h = 1.0 + step(0.5, r) + step(0.7, r) + step(0.8, r);
float s = 1.0 + step(0.1, r) + step(0.1, r) + step(0.2, r);
float b = 1.0 + step(0.1, r) + step(0.1, r) + step(0.2, r);
vec3 color = vec3(fract(h/4.0 + (1.0 + m.y)*0.5), fract(s/4.0 + (1.0 + m.x)*0.5), b/6.0+0.4);
return hsb2rgb(color);
}
コードのポイントはここです。
// rは0.0~1.0
float h = 1.0 + step(0.5, r) + step(0.7, r) + step(0.8, r); //1.0~4.0の数になる
float s = 1.0 + step(0.1, r) + step(0.1, r) + step(0.2, r);
float b = 1.0 + step(0.1, r) + step(0.1, r) + step(0.2, r);
各ブロック0.0~1.0の数字を持っています。
step(a,x)閾値(a)以下の場合0、それ以上の場合は1を返します。
上記の式では1にstep()を3回足しているので、最大の数値は4.0になります。
閾値を色々と調整してあげることで、色の出現率を調整することができます。
vec3 color = vec3(h/4.0, s/4.0, b/4.0);
return hsb2rgb(color);
色として使う際は4で割ってあげると0~1の値になります。
さらに調整したい場合はfract()を使って小数点の部分だけとってあげれば調整が可能です。
例えば、マウスのx座標で変更したい際は以下のようにします。
vec3 color = vec3(fract(h/4.0 + mouse.x), s/4.0, b/4.0);
return hsb2rgb(color);
マウスの位置によって色相が変わるけど、彩度・明度は変わらないので、雰囲気の似た別の色が出るようになります。
おわりに
最近書いたコードの中で、色にまつわるものをまとめてみました。
他にもいい例や、効率のいいやり方などあればぜひ教えてください。