【Unity】セルシェーディング不具合修正と調整【Shader】

前回から調整して ハイライトの表示位置の制御と リムライトを髪の毛のみに落ちるようにし、アウトラインを調整してます。

前回
調整後

彩度バグ修正

前回の トゥーンから 彩度・明度 を調整する部分が不具合がありました。
彩度が 0 の色(白から黒の間)を濃くするために加算すると 青みかかっていました。

この部分を

// hsvに変換し彩度・明度を調整する
float3 hsv = rgb2hsv( sample);
hsv.y = min( hsv.y + toon, 1.0); // 彩度変更
hsv.z = max( hsv.z - toon, 0.0); // 明度変更
float4 color = float4( hsv2rgb( hsv), 1);
return color;

こう変更する。

// hsvに変換し彩度・明度を調整する
float3 hsv = rgb2hsv( sample);
hsv.y = min( hsv.y + toon * pow( hsv.y, log(_SaturationBias)/log(0.5)), 1.0); // 彩度変更
hsv.z = max( hsv.z - toon, 0.0); // 明度変更
float4 color = float4( hsv2rgb( hsv), 1);
return color;

Shader(HLSL), 手続き的にテクスチャ生成など行うとき使用頻度の高い関数
こちらのサイト様を参考に二次関数 bias関数 を使って 彩度 が 0に近ければ変化しないようにし、 _SaturationBias で微調整するようにしました。

ハイライトの変更

ハイライト部分
加算に変更
ハイライトマスク変更
だいぶ限定した部分のみハイライトを出しています。

ハイライトマスク
Pass
{
	Blend One One // 加算

	CGPROGRAM

	#pragma vertex vert
	#pragma fragment frag

	struct appdata
	{
		float4 vertex : POSITION;
		float3 normal : NORMAL;
		float4 uv : TEXCOORD0;
	};

	struct v2f
	{
		float4 vertex : SV_POSITION;
		float4 vertexW : TEXCOORD0;
		float3 normal : TEXCOORD1;
		float2 uv : TEXCOORD2;
	};

	float4 _HighlightMask_ST;

	v2f vert( appdata v)
	{
		v2f o = (v2f)0;
		o.vertex = UnityObjectToClipPos( v.vertex);
		o.vertexW = mul( unity_ObjectToWorld, v.vertex);
		o.normal = UnityObjectToWorldNormal( v.normal);
		o.uv = float2( v.uv * _HighlightMask_ST.xy + _HighlightMask_ST.zw);

		return o;
	}

	float _Spec1Power;
	sampler2D _HighlightMask;

	half4 frag( v2f i) : SV_Target
	{
		// ハイライトマップを見て描画の有無を判定する
		half4 cutoff = tex2D( _HighlightMask, i.uv);
		if( cutoff.r < 0.5)
		{
			discard; // 中止
		}

		// ハイライト計算
		float3 L = normalize( _WorldSpaceLightPos0.xyz);
		float3 V = normalize( _WorldSpaceCameraPos - i.vertexW.xyz);
		float3 N = i.normal;
		float specular = pow( max( 0.0, dot( reflect(-L, N), V)), _Spec1Power);
		if( specular < 0.5)
		{
			discard; // 中止
		}

		return half4( 0.2, 0.2, 0.2, 1);
	}

	ENDCG
}//Pass

リムライトの変更

リムライトもマスクを参照してとりあえず髪の毛だけに落ちるようにしました。

Pass
{
	Blend OneMinusDstColor One // スクリーン / 比較(明)

	CGPROGRAM

	#pragma vertex vert
	#pragma fragment frag

	struct appdata
	{
		float4 vertex : POSITION;
		float3 normal : NORMAL;
		float4 uv : TEXCOORD0;
	};

	struct v2f
	{
		float4 vertex : SV_POSITION;
		float4 vertexW : TEXCOORD0;
		float3 normal : TEXCOORD1;
		float2 uv : TEXCOORD2;
	};

	sampler2D _RimMask;
	float4 _RimMask_ST;

	v2f vert( appdata v)
	{
		v2f o = (v2f)0;
		o.vertex = UnityObjectToClipPos( v.vertex);
		o.vertexW = mul( unity_ObjectToWorld, v.vertex);
		o.normal = UnityObjectToWorldNormal( v.normal);
		o.uv = float2( v.uv * _RimMask_ST.xy + _RimMask_ST.zw);

		return o;
	}

	float _RimBias;

	half4 frag( v2f i) : SV_Target
	{
		// リムライトマスクを見て描画の有無を判定する
		half4 cutoff = tex2D( _RimMask, i.uv);
		if( cutoff.r < 0.5)
		{
			discard; // 中止
		}

		float3 V = normalize( _WorldSpaceCameraPos - i.vertexW.xyz);
		float rim = 1 - saturate( dot( i.normal, normalize( V)));
		rim = pow( rim, log( _RimBias) / log( 0.5));

		return float4( rim, rim, rim, 1);
	}

	ENDCG
}//Pass

だいぶ落ち着いた絵になったと思います。

Tags:

Add a Comment

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