growCrystalsでやっていること[色つくり]

shader全文はこちらにあります
github.com

六角柱の色に関係したfragment shaderは以下の部分になります。

fixed4 frag (g2f i) : SV_Target
{
    clip(_Crystal-1);
    fixed4 mask = tex2D(_MaskTex,i.uv);
    float cl = (mask.g  < 0.5);
    clip(cl * -1);
    
    float mh = (i.maxh+_Sharpness);
    float ihr = (i.h)/mh;
    
    fixed3 col = lerp(float3(1,1,1) , _Color , saturate( (i.h+_White)/mh) );
    float3 specularCol = 1;
    col.rgb = reflection(i,col,specularCol,5);

    float alpha = 1-ihr;
    alpha = clamp( alpha,_AlphaMin,1);
    return float4(col,alpha);
}

わかりにくいので、色決定以外の部分を消して整理すると以下のものになります。
reflection関数は完全に光周りの話になるので、ここでは解説しません。
こちらを全部解説していきます。

fixed4 frag (g2f i) : SV_Target
{
    float mh = (i.maxh+_Sharpness);
    float ihr = (i.h)/mh;
    
    float3 col = lerp(float3(1,1,1) , _Color , saturate( (i.h+_White)/mh) );
    float3 specularCol = 1;
    col = reflection(i,col,specularCol,5);

    float alpha = 1-ihr;
    alpha = clamp( alpha,_AlphaMin,1);
    return float4(col,alpha);
}

変数の中身と処理の流れ

    float mh = (i.maxh+_Sharpness);
    float ihr = (i.h)/mh;

f:id:tonoshake:20191118122045p:plain
mh はクリスタルの長さを表しています。
i.maxhは六角柱部分の長さ、_Sharpnessは先端部分の長さが入っています。
i.h はfragment shaderで現在処理している場所が生え際からどれくらい離れているかが入っています。

そのためihrには現在処理している場所がクリスタル全体のどれくらいの位置にあるかが入ります(根元が0、先端が1)。

    float3 col = lerp(float3(1,1,1) , _Color , (i.h+_White)/mh);

f:id:tonoshake:20191120124910p:plain
colは白(float3(1,1,1))と_Color(クリスタルの色)を高さに応じて線形補完した色が入ります。
簡単に言えば、根元は白っぽく、先端は設定したクリスタルの色っぽくなります。

lerpは(A,B,どれくらいの割合)という引数をとる関数です。
例えば どれくらいの割合 というところにいれた値が0.5なら、AとBを半分ずつ足したものになります。


上で出てきたコードと違い、今処理している部分(i.h)に_Whiteという値が加算されています。
この_Whiteを大きくすると、(i.h+_White)が大きくなり、全体的により先端に近い場所とみなすことが出来ます。
これの何が嬉しいかというと、全体の高さを上げることで、全体の色をクリスタルに設定した色に近づけることができます。
つまり_Whiteのパラメータは、クリスタルの色の長さを調整するものになります。


saturateというのは、()の中が0より小さいなら0に、1より大きいなら1にするものです。

    float3 specularCol = 1;
    col = reflection(i,col,specularCol,5);

specularColは反射光の色です。
白にしています。
reflectionは反射光の計算用に自分で定義しました。
上で書いた通り、ここでは解説しません。
実装しているのはPhongの反射モデルです。


  float alpha = 1-ihr;
   alpha = clamp( alpha,_AlphaMin,1);
   return float4(col,alpha);
}

上で出した、クリスタル全体のどれくらいの位置にあるかを使って透明具合を決めています。
ここでは0が透明で1が不透明、0.5で半透明になります。
1-ihrとしている意味は、根元の方を不透明にして先端を透明にしたかったからです。
ihrは高さなので、根元が小さく先端が大きくなっています。最大値が1なので、1から引くことで大小を反転させることができます。
次のclamp(alpha,_AlphaMin,1)の部分では、透明度の下限値を設定しています。
clampは(なんらかの値,下限値,上限値)と引数を取り、下限値より下なら下限値に、上限値より上なら上限値に、それ以外は何らかの値を返してくれます。
下限値_AlphaMinは外から設定できる値なので、ここを調整すれば透明度を好きに決められるようになります。

以上のことが、growCrystalの色を決める流れです。