RimLightingで出した値をAlpha値として使う(ShaderFrogeを使って解説)

RimLighting(リムライティング)とはオブジェクトの後ろからライトが当たっていてオブジェクトの輪郭線に光が漏れている現象です。


下記はRimLightingで出した値をAlpha値として使い、輪郭以外を透明にしています。今回はこちらを実装と解説していきたいと思います。
f:id:shinobigiken:20170715085456p:plain


Shader "RimLighting" {
	Properties{
		_Color("Color", Color) = (1,1,1,1)
		_MainTex("Albedo (RGB)", 2D) = "white" {}
		//アルファを値を調節するsliderを作っておく
		_DotProduct("Rim effect", Range(-1,1)) = 0.25
	}

	//透明にするのでTransparentに設定
	SubShader{
		Tags{
			"Queue" = "Transparent"
			"IgnoreProjector" = "True"
			"RenderType" = "Transparent"
		}
		LOD 200

		//背面をカリングしないように(陰面消去)Cull Offを指定
		Cull Off

		//このシェーダはライトの影響を受けないのでLambertで十分
		//(Lambertはスペキュラや反射をしない)
		//alpha:fade(この素材は透明で、スクリーンに描かれたものとブレンドする必要があることをシェーダに伝えます)
		//nolighting(ライトの影響を受けない)
		CGPROGRAM
		#pragma surface surf Lambert alpha:fade nolighting

		//propertiesで設定した値の変数宣言
		sampler2D _MainTex;
		fixed4 _Color;
		float _DotProduct;

		//マテリアルが割り当てられているオブジェクトから取得する情報
		//uv座標
		//法線
		//視線ベクトル
		struct Input {
			float2 uv_MainTex;
			float3 worldNormal;
			float3 viewDir;
		};

		void surf(Input IN, inout SurfaceOutput o) {
			//ここはtextureMappingと同じ
			float4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;

			//これはリムライティングの計算方法を使う
			//視線ベクトルと頂点法線の内積を取ると
			//視線ベクトルの正面になる法線との内積の値は1
			//視線ベクトルの直角になる法線との内積の値は0
			//視線ベクトルの後ろ側になる線との内積の値は-1となるので
			//これをabs関数で絶対値にするとオブジェクトの輪郭線だけ黒くなる
			//これを1-で反転させると輪郭線だけ白くなり視線ベクトルの正面は黒くなる
			//それを変数borderに入れる
			float border = 1 - (abs(dot(IN.viewDir, IN.worldNormal)));
			//borderの値にpropertiesで設定した値を乗算して調整出来るようにしてある
			//その調整した値をalphaに入れて
			float alpha = (border * (1 - _DotProduct) + _DotProduct);
			//SurfaceOutputに出力
			o.Alpha = c.a * alpha;
		}
		ENDCG
	}
	FallBack "Diffuse"
}


考え方としては
視線ベクトルと法線ベクトルの角度が直角に近づけば近づくほど
ライティングの係数が大きくなるようにします。


下記でそれが行われています。

float border = 1 - (abs(dot(IN.viewDir, IN.worldNormal)));


以下shaderforgeで解説
視線ベクトルと頂点法線の内積を取ると
視線ベクトルの正面になる法線との内積の値は1
視線ベクトルの直角になる法線との内積の値は0
視線ベクトルの後ろ側になる線との内積の値は-1
となるので
下記のように視線ベクトルから正面の部分は明るく、視線ベクトルと直角になると値は0になるので完全に黒くなる


これをabs関数で絶対値にするとオブジェクトの輪郭線だけ黒くなる
絶対値はマイナスがプラスになるので値が1~0~1となるため
f:id:shinobigiken:20170715085426p:plain


これを1-で反転させると輪郭線だけ白くなり視線ベクトルの正面は黒くなる
f:id:shinobigiken:20170715085441p:plain


この値をアルファの値として使えば
アルファは
非透明が1.0
透明が0.0
なので
白い部分(1.0)が非透明になり
黒い部分(0.0)が透明になるので
結果として
輪郭だけ描画され下記のような結果になる
f:id:shinobigiken:20170715085456p:plain


ShaderForgeで作ると下記のような感じになります
(Blending > BlendMode > AlphaBlendに設定)
f:id:shinobigiken:20170715085846p:plain