-->

Shader "UI/Rainbow"
{
Properties
{
_HueBlendRate("Hue Blend Rate", Range(0.1, 5)) = 3 //RGBの重ね具合、虹色のグラデーションに影響
_OverrideRate("Override Rate", Range(0, 1)) = 1 //元々のピクセルの色にどれだけ虹色を被せるか
_HueOffset("Hue Offset", float) = 0 //虹色の移動値
[Space]
//虹色の混合の仕方、ToShinyはHueBlendRateが高いほど真っ白に近づく。ToDarkは逆で真っ黒に近づく。
[KeywordEnum(ToShiny, ToDark)] _HUETYPE("HueType", Int) = 0
//虹色の染め上げ方。
[KeywordEnum(Circle1, Circle2, Vertical, Horizontal)] _GRADATIONTYPE("GradationType", Int) = 0
}
SubShader
{
Tags
{
"RenderPipeline" = "UniversalPipeline"
"Queue" = "Transparent"
}
Cull Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
//後述のSRGBToLinearで必要なライブラリ
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
half4 color : COLOR;
half2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : POSITION;
half4 color : COLOR;
half2 uv : TEXCOORD0;
};
//uGUI Image > Source Imageにアタッチされた画像を参照する
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
//アタッチされたSpriteのサイズを取得(x=1.0/width, y=1.0/height, z=width, w=height)
float4 _MainTex_TexelSize;
//SRP Batcherを適用、動的に変更される数値はこの中に定義
CBUFFER_START(UnityPerMaterial)
half _HueBlendRate, _OverrideRate, _HueOffset;
CBUFFER_END
#pragma multi_compile _HUETYPE_TOSHINY _HUETYPE_TODARK
#pragma multi_compile _GRADATIONTYPE_CIRCLE1 _GRADATIONTYPE_CIRCLE2 _GRADATIONTYPE_VERTICAL _GRADATIONTYPE_HORIZONTAL
//渡された0~1の範囲の1次元変数をRGBの3次元変数に変換する
//taken from: http://www.chilliant.com/rgb2hsv.html
half3 HUEtoRGB(in float H)
{
float R = abs(H * 6 - 3) - 1;
float G = 2 - abs(H * 6 - 2);
float B = 2 - abs(H * 6 - 4);
half3 rgb = saturate(float3(R, G, B));
//URPのリニア空間用に色を変換
return SRGBToLinear(rgb);
}
Varyings vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.uv;
output.color = input.color;
return output;
}
half4 frag (Varyings input) : SV_Target
{
//オリジナルの色を保存しておく
half4 originalColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
//これから編集する色にコピー
half4 rainbowColor = originalColor;
//originalColorの方は、Imageのインスペクターのカラー値を反映させる
originalColor *= input.color;
//_HueOffsetの最小値を0にする
half hueOffset = max(0, _HueOffset);
half3 hueColor;
#ifdef _GRADATIONTYPE_CIRCLE1 //中心から回転するように虹色グラデーションが広がる
//円周率の2倍を作っておく(以下2πと表記)、radian値の計算では2πがdegree値でいう360°になる
float pi2 = 6.283184;
//x, y軸の座標を0~1の範囲から-0.5~0.5の範囲に修正する(画像中央を原点とさせるため)
half2 uvFixedCenter = input.uv.xy - 0.5;
//atan2で中心点から対象座標への角度を取得する、返ってくる値は-2πから2πの範囲
//-2πと2πは回転方向が違うだけでどちらも同じ一周を表す、-360°と360°が同じ角度であるのと一緒
float rad = atan2(uvFixedCenter.y, uvFixedCenter.x);
//hueOffsetの値分だけ算出した角度をずらす
rad += hueOffset;
//fracを使い1で割った余りを算出して0~0.999..の循環パターンにし、同時にマイナス値はプラスに変換
float h1 = frac((rad / pi2));
hueColor = HUEtoRGB(h1) / _HueBlendRate;
#elif _GRADATIONTYPE_CIRCLE2 //中心から外側に広がるように虹色グラデーションが広がる
//x, y軸の座標を0~1の範囲から-0.5~0.5の範囲に修正する(画像中央を原点とさせるため)
half2 uvFixedCenter = input.uv.xy - 0.5;
//画像の縦横の短い方を取得
half minScreen = min(_MainTex_TexelSize.z, _MainTex_TexelSize.w);
//x軸とy軸の座標を補正、画像の縦横比を適切に掛けることで正円にする
uvFixedCenter.x = uvFixedCenter.x * (minScreen / _MainTex_TexelSize.w);
uvFixedCenter.y = uvFixedCenter.y * (minScreen / _MainTex_TexelSize.z);
//-0.5も+0.5も中心点からの距離という意味では同じなので絶対値にする
uvFixedCenter = abs(uvFixedCenter);
//lengthで中心からの直線距離を計算
float dist = length(uvFixedCenter);
//hueOffsetの値分だけ算出した距離をずらす
dist += hueOffset;
//結果を1で割った余りを算出することで、0~0.999..の循環パターンにする
dist %= 1;
hueColor = HUEtoRGB(dist) / _HueBlendRate;
#elif _GRADATIONTYPE_VERTICAL //y軸に沿って虹色グラデーションに染める
hueColor = (HUEtoRGB((input.uv.y + hueOffset) % 1) / _HueBlendRate);
#elif _GRADATIONTYPE_HORIZONTAL //x軸に沿って虹色グラデーションに染める
hueColor = (HUEtoRGB((input.uv.x + hueOffset) % 1) / _HueBlendRate);
#endif
#ifdef _HUETYPE_TOSHINY
//光り輝くように虹色を混合、この際にmaxで0除算を防ぐ
rainbowColor.xyz = rainbowColor.xyz / max(0.01, hueColor);
#elif _HUETYPE_TODARK
//光を抑えて虹色を混合
rainbowColor.xyz = rainbowColor.xyz * hueColor * 10;
#endif
//各色の最大値である1を超えないようにsaturateで収める
rainbowColor.xyz = saturate(rainbowColor.xyz);
//_OverrideRateに応じて虹色画像の重ね具合を決める
half4 resultColor = lerp(originalColor, rainbowColor, _OverrideRate);
return resultColor;
}
ENDHLSL
}
}
}

