シェーダーでスムーズなトランジションを行う
こういうのをシェーダーを使って実装します。続きからどうぞ。
まず思いつくのはclip
で描画をカットする方法です。上下左右の4方向に対応する場合、例えば以下のようにできます。
// 切れ目あり if (_X > 0) { clip(-_X + IN.texcoord.x); } else { clip(_X - IN.texcoord.x + 1); } if (_Y > 0) { clip(-_Y + IN.texcoord.y); } else { clip(_Y - IN.texcoord.y + 1); }
結果は次のようになります。
これはこれでナシではないですが、最初の画像のように境目がなめらかだとより見栄えが良くなりそうです。
というわけで、改善したのが下のコードです。
// なめらか if (_X > 0) { tex.a *= 1 - saturate(_X * (_Sharpness + 1) - IN.texcoord.x * _Sharpness); } else { tex.a *= saturate((1 + _X) * (_Sharpness + 1) - (IN.texcoord.x) * _Sharpness); } if (_Y > 0) { tex.a *= 1 - saturate(_Y * (_Sharpness + 1) - IN.texcoord.y * _Sharpness); } else { tex.a *= saturate((1 + _Y) * (_Sharpness + 1) - (IN.texcoord.y) * _Sharpness); }
なぜこれでうまくいくのかはわかりません。ガチャガチャいじってたら上手くいきました。(誰か理屈を教えてください)
これで完成です。シェーダー全体のコードを以下に載せます。Particle/Alpha Blend.shader
をベースにしています。
(Category
なんていうキーワードがいつのまにか追加されてたんですね。5.5からでしょうか。)
Shader "Custom/Transition" { Properties { _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5) _MainTex ("Particle Texture", 2D) = "white" {} _X("X", Range(-1, 1)) = 0 _Y("Y", Range(-1, 1)) = 0 _Sharpness("Sharpness", Range(0, 16)) = 2 [Toggle] _Smoothed("Smoothed Edge", Float) = 1 } Category { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB Cull Off Lighting Off ZWrite Off SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_particles #pragma multi_compile_fog #pragma multi_compile SMOOTHED_EDGE CUT_EDGE #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST; fixed4 _TintColor; float _X; float _Y; float _Sharpness; float _Smoothed; struct appdata_t { float4 vertex : POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_FOG_COORDS(1) UNITY_VERTEX_OUTPUT_STEREO }; v2f vert (appdata_t v) { v2f o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.vertex = UnityObjectToClipPos(v.vertex); o.color = v.color * _TintColor; o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f IN) : SV_Target { fixed4 tex = tex2D(_MainTex, IN.texcoord) * IN.color; if (_Smoothed > 0) { // なめらか if (_X > 0) { tex.a *= 1 - saturate(_X * (_Sharpness + 1) - IN.texcoord.x * _Sharpness); } else { tex.a *= saturate((1 + _X) * (_Sharpness + 1) - (IN.texcoord.x) * _Sharpness); } if (_Y > 0) { tex.a *= 1 - saturate(_Y * (_Sharpness + 1) - IN.texcoord.y * _Sharpness); } else { tex.a *= saturate((1 + _Y) * (_Sharpness + 1) - (IN.texcoord.y) * _Sharpness); } } else { // 切れ目あり if (_X > 0) { clip(-_X + IN.texcoord.x); } else { clip(_X - IN.texcoord.x + 1); } if (_Y > 0) { clip(-_Y + IN.texcoord.y); } else { clip(_Y - IN.texcoord.y + 1); } } return tex; } ENDCG } } } }
このシェーダをアタッチしたマテリアルのインスペクタのSmoothed Edge
のチェックをオンオフすることで切り替えられます。
確認用にif
文盛り盛りなので、使う場合は適宜削ってください。