土屋つかさの技術ブログは今か無しか

土屋つかさが主にプログラミングについて語るブログです。

#unity 疑似環境マップでARでモデルを風景に馴染ませたい

 この記事は"シェーダーアドベントカレンダー2019"の7日目の記事になります(遅刻して申し訳ありません!><)

 今回は以前から試してみたいと思っていた、超簡単偽環境マップの作成に挑戦してみたいと思います。まあ失敗してもそれはそれで経験ということで。

 覚えている方も多いと思いますが、新型MacProの発表時に、ARで実世界にMacProを表示させる面白いサービスがありました(以下これをMacProARと呼びます)。
www.apple.com
 iPhoneでこのページの"See Mac Pro in AR"をタップするとAR表示モードに切り替わり、MacProを配置できます。
f:id:t_tutiya:20191213110146p:plain
 このサービスで土屋がよく出来てると感じているのは、配置したMacProに対して環境マッピングを適用して、より風景に溶け込むようにしている点です。
 たとえばこの写真。Mac Proの筐体(もちろん3Dモデルです。Mac1台も持ってない)をよく見ると、下の部分にうっすら青い色が載っているのがわかるでしょうか? これは奥にある青いフォルダの色が周辺光(環境光)として映り込んでいるのです。また上部のハンドル(なのこれ?)にも赤い物が映り込んでいます。
f:id:t_tutiya:20191213235901j:plain
 わかりやすいのはロゴの部分。向かい側の赤表紙の本を反射しています。
f:id:t_tutiya:20191213235940j:plain
 もちろん、iPhoneに周囲360度を撮影する機能なんてありません。MacProARでは起動時に一度カメラに写った風景を保存し、その画像をベースに、擬似的な環境マップを生成していると推測できます。

 「これをやりたい!」というのが本記事の趣旨です。MacProARがどのような環境マップを構築しているのかはわかりませんが、今回はシンプル(≒乱暴)な方法で行きたいと思います。

アプローチ

 そんな難しくないです。MacProARも似たような方法を使っていると思います(調べてないので違うかもですが)。

 Unityにおける環境マップには「SkyBoxシェーダーを適用したマテリアル」を使用します。このマテリアルにはキューブマップテクスチャを設定します。キューブマップの上下左右前後ろの6面が、各方向からの周辺光として扱われるわけです。ですから、カメラに映った風景をどうにかしてキューブマップテクスチャにしてやればいいわけです。

 キューブマップテクスチャは、画像自体は通常の2D画像になります(※立方体の各面に1枚ずつテクスチャを設定する方法もありましたが、現在は非推奨です)。1枚の画像をどのように6面に張り付けるかについては3つ方式(計6通り)がありまして、Inspectorで方式を指定したり、画像の縦横比率からUnityが自動で決定したりします。

風景写真をキューブマップテクスチャにする

 自室で撮ったこの写真を使います。赤と青の本を置いているのは、ピーキーな色の方が変化が分かりやすいかなと思ったからです。
f:id:t_tutiya:20191213000242j:plain
 キューブマップのマッピング方式は"LatLong(Latitude-Longitude)"にします。これは、設定された画像を下記のように補正して立方体の各面に適用します。
f:id:t_tutiya:20191213110246p:plain
(画像はUnity - Manual: Cubemapsより)
 さっきほどの画像をLatLong形式に当てはめるにはどうすればいいでしょうか? こうします。
f:id:t_tutiya:20191213110217p:plain
 見ての通り、左右反転した画像を2分割して、左右に横にくっつけただけです。どうせ疑似だし、こんなんでもなんとなくいけるんじゃないか? と期待。
f:id:t_tutiya:20191213110228p:plain
 展開図を重ねるとこんな感じになります。単に反転画像を横に並べるのではなく2分割したのは、風景の方向(Z+)と風景の位置を合わせたかったからです(ただし、カメラを回転させるのでも同じ効果になります)。

実際にやってみた

 実機での作業は簡単です。コードも書きません(期待してたらごめんなさい)。

1・テクスチャの準備

・テクスチャをProjectウィンドウにドラッグ&ドロップ。
・Texture Shapeを"Cube"に変更し、Mappingを"Latitude-Longitude Layout(Cylindrical)"に変更
f:id:t_tutiya:20191213110602p:plain

2・マテリアルの準備

・マテリアルを新規作成
・シェーダーをSkybox/CubeMapに変更し、CubeMap(HDR)にインポートした画像を設定
f:id:t_tutiya:20191213110548p:plain
・LightingウィンドウのSkybox Materialに作成したマテリアルを設定。
f:id:t_tutiya:20191213110544p:plain

3・オブジェクトの配置

・球体オブジェクトを新規作成し、マテリアルインスペクタのMetaricとSmoothnessをいい感じにいじる。
f:id:t_tutiya:20191213110557p:plain
f:id:t_tutiya:20191213110552p:plain
 環境光が反映されているのがわかると思います。

6・完成!

せっかくなので元の画像を背景に配置し、光源方向も調整してみます。背景画像はUnlitシェーダーを適用して、環境マップの影響を受けないようにしています。
f:id:t_tutiya:20191213110540p:plain
……正直、思ったほど馴染みませんでした(爆)。

終わりに

 実際にやるまで気づきかなったのですが、このアプローチだとディレクショナルライトの方向をどう推定するのかに工夫が必要でした(今回は目測による手作業)。
 実空間にモデルをAR表示させるアプリは沢山あるかと思いますが、アプリが環境光を考慮していない場合、モデルだけが実風景から浮いて見えてしまいます。グレーディングで画面全体の色調を合わせたり、今回のようなアプローチで、より自然に見えるAR表現を目指してみてはいかがでしょうか。

補足

  • 当初はオブジェクトに環境マップを直接設定したかったのですが、やり方がわからんかった。あれ? できないんだっけ?
  • オブジェクトからドロップシャドウさせるとより馴染むかと思います。MacProARでは、多分半透明のテクスチャで決め打ちの影を描いているように見えました。
  • まさかとは思うけどこの手法、Appleが特許取ってたりしないよね?
  • これシェーダーと直接関係なくね?