【Unity】続・ポケモン剣盾のディゾルブ処理を再現してみる【ディザリング】

前回

はじめに

あらためて、ポケモンをプレーしてみるともう少し高度な処理をしているようで、画面の中心かカメラの距離かわかりませんが、中心からアルファー値が減少しているようでした。中心が一番透明で、放射状に不透明になっている。

対応

ということで対応してみました。

実際のポケモンの動画を探してみましたが、なかなか見つからないのでこれで正しいのか不明です。

中心からアルファー値が変化しているのがわかります。

シェーダー

Shader "Neko/Dissolve"
{
	Properties
	{
		_MainTex("Main Texture", 2D) = "white" {}
		[NoScaleOffset]_GradationMap( "Gradation Map", 2D) = "white" {}
		_Alpha( "Alpha", Range(0.0, 1.0)) = 1.0
	}//Properties
	CGINCLUDE
	#include "UnityCG.cginc"
	ENDCG

	SubShader
	{
		Tags { "RenderType"="Opaque" }

		Pass
		{
			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float4 _MainTex_TexelSize;

			struct appdata
			{
				float4 vertex : POSITION;
				float4 texcoord : TEXCOORD0;
			};

			struct v2f
			{
				float2 texcoord : TEXCOORD0;
				UNITY_VPOS_TYPE vpos : VPOS;
				float2 aspect_scale : TEXCOORD2;
			};

			v2f vert( appdata v, out float4 vertex : SV_POSITION)
			{
				v2f o = (v2f)0;
				vertex = UnityObjectToClipPos( v.vertex);
				o.texcoord = float2( v.texcoord * _MainTex_ST.xy + _MainTex_ST.zw);

				// アスペクト算出
				float4 projectionSpaceUpperRight = float4(1, 1, UNITY_NEAR_CLIP_VALUE, _ProjectionParams.y);
				float4 viewSpaceUpperRight = mul( unity_CameraInvProjection, projectionSpaceUpperRight);
				float aspect = viewSpaceUpperRight.x / viewSpaceUpperRight.y;
				o.aspect_scale = float2( aspect, 1);
				return o;
			}

			sampler2D _GradationMap;
			float4 _GradationMap_ST;
			float4 _GradationMap_TexelSize;
			float _Alpha;

			half4 frag( v2f i) : SV_Target
			{
				if( _Alpha == 1)
				{
					// 不透明なら問答無用でレンダリング
					return tex2D( _MainTex, i.texcoord);
				}
				float _CellSize = _GradationMap_TexelSize.w;

				// 画面中心からの距離でアルファをオフセットする
				float2 pos = i.vpos.xy / _ScreenParams.xy * i.aspect_scale;
				float dist = distance( pos , 0.5*i.aspect_scale);
				float value = min( _Alpha + dist, 1);
				float2 localuv = fmod( i.vpos.xy, _CellSize) / _GradationMap_TexelSize.zw;
				float alpha = floor( value * 32.0) / 32.0;
				localuv.x += alpha;

				float3 gradation = tex2D( _GradationMap, localuv).rgb;
				if( gradation.r < 0.5)
				{
					discard; // 中止
				}
				return tex2D( _MainTex, i.texcoord);
			}

			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}//Shader

例のごとくライトやトゥーンは省いています。

先に頂点シェーダーでアスペクト値を算出して、ピクセルシェーダーで中心からの距離を算出する際にx値を補正してきれいな円になるようにしています。

あとは距離でアルファーにオフセットしています。

ポケモン剣盾はもう少し高度な計算で円ではなく球で距離をとっているのではないでしょうか?アルファに距離感を感じました。

最大のメリットは不透明なパスで半透明的な表現ができることです。
アルファエラーや、描画順番を気にせずにすみますね。

まぁ、この題材はこれで終了です。

この作品はユニティちゃんライセンス条項の元に提供されています
One Comment

Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です