Unityが提供してくれている、「AR Foundation」はUnityを使ってAR開発ができるパッケージですが、ただ単にARでモデルを表示するだけでは、リッチな表現は実現できません。
ARの表現を一段階上のものにする上で重要なポイントになってくるのは、「いかにARで出現させるオブジェクトを現実になじませるか」でしょう。
オブジェクトを現実になじませる方法はいくつかあるのですが、その一つの方法として「影の描画」があります。ARでオブジェクトを出した際に、オブジェクトを置いた面に影を出力してあげるのです。
影がないと、どこかオブジェクトが現実から浮いたような見た目になってしまいます。下の2つの画像を見比べると違いが顕著でしょう。
今回は、この「影の描画方法」に関して、実装方法とその原理について解説していきたいと思います。
ARでの影の描画方法
それではまず、ARで表示するオブジェクトの足元に影を表示する具体的な実装方法について解説していきます。
手順は以下の3つです。
①影のみを表示させるシェーダーの作成
②影のみを表示させるシェーダーをPlaneに適用
③影を高解像度にして見た目を整える
一つずつ解説していきたいと思います。
影のみを描画するシェーダーの作成
まずは準備として、影のみを描画するシェーダーを作成しましょう。
Assetウィンドウで、Unlit Shaderを作成し、その中に以下を貼り付けましょう。
Shader "Custom/MobileARShadow"
{
SubShader
{
Pass
{
Tags
{
"LightMode" = "ForwardBase" "RenderType"="Opaque" "Queue"="Geometry+1" "ForceNoShadowCasting"="True"
}
LOD 150
Blend Zero SrcColor
ZWrite On
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase
#include "AutoLight.cginc"
struct v2f
{
float4 pos : SV_POSITION;
LIGHTING_COORDS(0,1)
};
v2f vert(appdata_base v) {
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
fixed4 frag(v2f i) : COLOR {
float attenuation = LIGHT_ATTENUATION(i);
return fixed4(1.0,1.0,1.0,1.0) * attenuation;
}
ENDCG
}
}
Fallback "VertexLit"
}
これで、シェーダーの準備は完了です。
影のみを表示させるシェーダーをPlaneに適用
影の描画は、ARで表示するモデルの足元に、影描画用のPlaneを配置することで実現します。
モデルが置かれる仮想の面をUnity上で作成してやり、このプレーンに先ほど作成した、影以外の部分を透明にするシェーダを適用することで、影だけを抜き出し、あたかもモデルが影を落としているかのように見せることができます。
上の画像は、Unityエディタ上でのシェーダー適用前と後の比較ですが、影のみが抜き出されていることがわかります。シェーダーのPlaneへの適用方法ですが、通常通り、Planeに適用するマテリアルから当該のシェーダーを選択してあげれば良いです。
影の低解像度問題の対処法
影を表示した際に、影が粗くガタガタになってしまうという問題が発生してしまうことがあります。これではせっかく表示した影も台無しになってしまいます。
これは、Shadow Mapの解像度が足りないことが原因なので、以下の二つを試してみましょう。
①Project Setting > Quality > Shadow ResolutionをVery High Resolutionに変更する。
②Project Setting > Quality > Shadow Distanceの値を5〜10程度に設定する。
特に、Shadow Distanceの値変更は気付きにくいところです。Shadow Distanceは、どこまで影を描画するかをカメラからの距離で指定するものですが、これを下げることで、Shadow Mapの解像度が上がり、影は精緻に描画されます。
ARで影を表示するシェーダーの解説
さて、それでは影を表示するシェーダーの中身をみていきましょう。ポイントは以下の3つです。
①AutoLight.cgincのインクルード
②LIGHTING_COORDマクロでのシャドウのサンプリング
③LIGHT_ATTENUATIONマクロでの減衰率の計算
AutoLight.cgincのインクルード
AutoLight.cgincは、ライティングシャドウの計算を行うマクロがまとまっているUnityライブラリのファイルです。これを使用することにより、簡単にシャドウの計算をおこなうことができるようになります。
#include "AutoLight.cginc"
また、ShaderがForward Baseパスでコンパイルされるように指定するため、以下を記述する必要があります。
#pragma multi_compile_fwdbase
LIGHTING_COORDマクロでのシャドウのサンプリング
LIGHTING_COORDマクロはサンプリングしたシャドウマップをTEXCOORDに保存するためのマクロです。LIGHTING_COORDマクロに与える引数は、TEXCOORDの番号を指します。今回は、シャドウのサンプリング以外にTEXCOORDを使用していないため(0,1)で良いですが、例えばUVを0番目のTEXCOORDに使用していた場合は、
LIGHTING_COORDS(1,2)
とし、1番目と2番目を使用する必要があります。
また、サンプリングしたシャドウマップは、v2f構造体の中で適切な値に設定し直すことが必要です。
TRANSFER_VERTEX_TO_FRAGMENT(o);
LIGHT_ATTENUATIONマクロでの減衰率の計算
LIGHT_ATTENUATIONマクロは、シャドウマップからサンプリングされる光の減衰率で、float型で返されます。これをシャドウに考慮してあげることで、光の減衰を考慮した影の描画を行うことができます。
float attenuation = LIGHT_ATTENUATION(i);
return fixed4(1.0,1.0,1.0,1.0) * attenuation;
おわりに
Unityの中で、AR Foundationを使用しAR開発を行うときの影の描画方法を、ざっと見てきました。
影を描画するためのシェーダーは多少専門的な内容がありますが、シェーダーの中身を編集することは、ほとんどないと言って良いでしょう。
ARで影を描画して、より高度なAR開発ライフを送っていきましょう。