icon
KOKI

GLSLでカラーランプを実装する

2020/09/14

blender の Shader の ColorRamp ノードみたいなのが必要になったので、glsl で実装する方法を考える。 colorramp node

  • 区切りの数が増えても簡単に対応できるようにする。
  • if 文を使わない。

この二つを目標に頑張る。

※この記事中のスクリプトはすべて MIT ライセンスです。

区切りが二つしかない場合

colorRanpUnit()
vec3 colorRanpUnit(
        float x,
        float start_edge, vec3 start_col,
        float end_edge, vec3 end_col
    ){
    float value = (clamp(x, start_edge, end_edge)-start_edge)/(end_edge-start_edge);
    return mix(start_col, end_col, value);
}

引数は

  • x が入力値
  • 左側の区切りの色と位置が、start_col と start_edge
  • 右側の区切りの色と位置が、end_col と end_edge

オフセットを計算してclamp()で 0.0~1.0 の間に丸めています。 start_edge>end_edgeだとうまく表示されないので注意

colorRanp(gl_FragCoord.x/resolution.x,
    0.2, vec3(1, 0, 0),
    0.8, vec3(0, 0, 1)
);

colorramp2

区切りが 3 つの場合

colorRanp()
vec3 colorRanp(
        float x,
        float first_edge, vec3 first_col,
        float second_edge, vec3 second_col,
        float third_edge, vec3 third_col
    ){
    vec3 col;
    col = colorRanpUnit(x, first_edge, first_col, second_edge, second_col);    col = colorRanpUnit(x, second_edge, col, third_edge, third_col);
    return col;
}

前述したcolorRanpUnit()を呼び出すcolorRanp()を定義する。 ハイライトした 8 行目の第三引数がsecond_colではなく、colという点に注意。

vec3 col = colorRanp(gl_FragCoord.x/resolution.x,
    0.2, vec3(1, 0, 0),
    0.5, vec3(0, 0, 1),
    0.8, vec3(0, 1, 0)
);

colorramp2

区切りが 4 つ以上の場合

区切りが 4 つ以上の場合は、

colorRanp()
vec3 colorRanp(
        float x,
        float first_edge, vec3 first_col,
        float second_edge, vec3 second_col,
        float third_edge, vec3 third_col,
        float fourth_edge, vec3 fourth_col
    ){
    vec3 col;
    col = colorRanpUnit(x, first_edge, first_col, second_edge, second_col);
    col = colorRanpUnit(x, second_edge, col, third_edge, third_col);
    col = colorRanpUnit(x, third_edge, col, fourth_edge, fourth_col);
    return col;
}

このように引数と呼び出し回数を増やす。 あまりに多い場合は配列、for 文にしたほうが管理しやすいかも。

よりスムースに

colorRampUnit()の返り値の部分を

colorRanpUnit()
vec3 colorRanpUnit(
        float x,
        float start_edge, vec3 start_col,
        float end_edge, vec3 end_col
    ){
    float value = smoothstep(start_edge, end_edge, x);    return mix(start_col, end_col, value);
}

このように書き換えることでよりスムースな補間ができる。 というかこちらのほうが実装もシンプルで綺麗なのでこちらを使ったほうが良い。

vec3 col = colorRanp(gl_FragCoord.x/resolution.x,
    0.2, vec3(1, 0, 0),
    0.5, vec3(0, 0, 1),
    0.8, vec3(0, 1, 0)
);

colorramp2

目次
© NAGASHIMA Koki 2022