USD・MaterialXを使用したインテリアマップシェーダー

INDEX

はじめに

こんにちは。モノリスソフト テクニカルアーティストの廣瀬です。

今回は、USDとMaterialXを使用してインテリアマップシェーダーを作成してみたいと思います。

USD(Universal Scene Description)はオープンソースの共通3Dシーンフォーマットです。
すでに多くのDCCツールやゲームエンジン(Maya・Houdini・Unreal Engineなど)でサポートされています。
USDはFBXやAlembicのようにメッシュデータのやり取りはもちろん、Composition ArcsというPhotoshopのレイヤー合成のようなことを3Dシーンに対して行う強力な機能を有しています。
これにより、3Dシーン同士の合成や必要な値のみの上書き、大量のリファレンス・インスタンス、マテリアルアサイン管理、遅延読み込みなど、効率的に巨大なシーンを構築することが可能となります。

MaterialXはオープンソースの共通シェーダーフォーマットで、各DCCツールやゲームエンジンで共通のシェーダー構築が可能になっています。また、独自のカスタムノードの定義を追加することも可能です。

インテリアマッピングは何もない平らなフェースに疑似的に奥行きのある部屋を描画するためのシェーダーです。シェーダー内で疑似的に部屋の描画を行うことで処理負荷の軽減につながります。
今回インテリアマップシェーダーはUV空間で計算が行われるようにします。

テクスチャは、Cubemapテクスチャの背面を切り落とした形式のものを使用します。

tech_31_02.jpgのサムネイル画像

今回作成したサンプルファイル(monolithtech_roommap.zip 47.3 KB)はこちらです。

DOWNLOAD

USDシーンの構築

今回、USDシーンの構築はHoudiniで行っていきたいと思います。もちろんMayaなどでも行うことができます。

tech_31_03.jpg

ネットワーク全体

まずは、SOP Create LOPでビルの代わりとなる単純なボックス形状のメッシュを作成します。
SOP Create LOPの中に入り、Boxを作成し、各フェースに対してUV展開を行い、法線と接線を定義します。

tech_31_04.jpg

続いて、マテリアルのアサイン情報をMaterial Library LOPで設定します。「mtlxsurfacematerial1」はこの後作成するインテリアマップシェーダーの名前です。
Geometry Pathに「*(ワイルドカード)」を指定して現在操作しているステージ(シーン)上のすべてのプリミティブにマテリアルをアサインします。

インテリアマップシェーダーの構築

続いてMaterial Library LOPの中に入りインテリアマップシェーダーを作成します。

青色のノードはそれぞれ、カメラ位置・部屋のサイズ・部屋の位置オフセット・テクスチャ名で、ユーザーが入力する想定のパラメーターです。

tech_31_05.jpg

シェーディングネットワーク全体

カメラのレイの接平面空間への変換

まず、描画ピクセルのオブジェクトのワールドポジションとカメラの位置の差分からカメラのレイの方向を計算します。
カメラの位置は各レンダラーからの入力を受け取ります。
レイのベクトルをメッシュの法線・接線・従接線を用いて、接平面空間に行列変換を行います。現在MatrealXではTransform Matrixという行列変換用のノードが存在していますが、9つのfloatをmatrix33に変換するノードが存在していないようなので、ベクトルの加算と乗算ノードの組み合わせて行列計算を行っています。その後、接平面空間に変換したレイをノルム1のベクトルに正規化します。

tech_31_06.jpg

レイのヒットした部屋の壁と距離の算出

接平面空間に変換したレイとオブジェクトのUV座標(レイの開始点)を元に、衝突面(Top・Right・Front・Left・Bottom)と距離を計算します。
ノードにすると複雑に見えますが、行っている計算は単純です。

tech_31_07.jpg

まず、UV座標(レイの開始点)と部屋のサイズ・オフセット量から、部屋の割り当て(index)を計算します。

\(\textbf{room}_\textbf{index} = floor(\frac{\textbf{uv} + \textbf{offset}}{\textbf{size}})\)

tech_31_08.jpg

部屋の割り当ての可視化

続いてレイがヒットした部屋の壁とその距離を求めます。
各壁にヒットするまでのレイの距離は以下のように求めることができます。下図は+Xの壁にヒットするまでの距離です。

tech_31_09.jpg

レイが負の方向を向いているときは別途考慮を行う必要があります。

tech_31_10.jpg

そして、各壁にヒットした最短距離をそれぞれ比較し最小値を取ることで、初めにレイがヒットした壁とその距離が求まります。
これらの計算を部屋のサイズを考慮したうえでMaterialXのノードに落とし込んだのが以下となります。

tech_31_11.jpg

最短距離の可視化

部屋の壁のUV座標の算出

これまで求めたレイの方向・オフセットされたUV座標・レイがヒットした壁と距離を用いて部屋の壁のUV座標を求めることができます。

\(\textbf{room}_\textbf{uv} = \textbf{ray}_\textbf{orig} + \textbf{ray}_\textbf{dir} * ray_{hit}\)

その後、各部屋の壁ごとに任意のCubemapに適合するようにUVの反転とオフセットを行います。

tech_31_12.jpg

部屋の壁のUVの可視化

テクスチャサンプリング

最後に、求めたUV情報を元にテスクチャサンプリングを行い終了です。

tech_31_13.jpg

テクスチャサンプリング

部屋の壁の法線の算出

これまでに求めた壁の法線方向と接平面空間の転置行列を乗算すれば、ワールド空間での法線を求めることができます。

tech_31_14.jpg

USDシーンの書き出し

これでUSDの書き出し準備が整いましたので、実際にシーンを書き出していきます。

USD ROP LOPノードを作成し、書き出し先のパスを設定し「Save to Disc」をクリックします。

tech_31_15.jpg

書き出されたUSDファイルの中身を確認するとメッシュの頂点座標・UV・法線の情報が書き込まれているのが確認できます。

tech_31_16.jpg

メッシュ情報

また、MaterialXのシェーディングネットワークも全て書き出されていることが確認できます。

tech_31_17.jpg

シェーダーの構成情報

MayaでのUSDシーンの読み込み

先ほど書き出したUSDファイルをMayaで読み込んでみます。
「Create」>「Universal Scene Description (USD)」>「Stage From File...」から先ほど書き出したファイルを読み込みます。

tech_31_18.jpg

USD専用ノードとしてUSDシーンが読み込まれます。

USDのメッシュ上で右クリックをし「Edit as Maya Data」を選択することで、いつもMayaで操作している状態のメッシュとして読み込むことができます。
そして、編集を行った結果は、「Merge Maya Edits to USD」でUSDへマージすることができます。
このように、編集したい対象だけをMayaのデータとして読み込むことで、シーン全体の状況をビューポートで確認しながら軽い状態で編集を行うことが可能となります。
また、特定のプリミティブだけを編集を行いUSDに結果をマージすることで、複数人での分業も効率的に行うことができます。
編集を行ったUSDは当然Houdiniなど別のアプリケーションで読み込むことができます。

tech_31_19.jpg

Edit as Maya Data

tech_31_20.jpg

Merge Maya Edits to USD

tech_31_21.jpg

マージを行った結果

続いて、読み込まれたシェーディングネットワークを確認してみます。
アウトライナの対象マテリアル上(mtlxsurfacematerial1)で右クリックし「Show in LookdevX」をクリックします。

tech_31_22.jpg

すると、「LookdevX Graph Editor」(最新のハイパーシェードのようなもの)が起動しmtlxsurfacematerial1ノードが表示されます。
ダブルクリックでノードの中に入るとHoudiniで構築したインテリアマップのシェーディングネットワークが構築されているのが確認できます。

tech_31_23.jpg

LookdevX Graph Editor

tech_31_24.jpg

読み込まれたインテリアマップのネットワーク

tech_31_25.jpg

読み込まれたインテリアマップのネットワーク

Arnoldからのカメラ座標を受け取るために「campos」ノードに「kma_rayimport1」ノードの代わりに「space_transform」ノードをつなぎます。
「space_transform」ノードのFromをcameraに設定します。

tech_31_26.jpg

ライトを追加しArnoldレンダリングを実行するとインテリアマップが正常に動作していることが確認できます。

tech_31_27.jpg

MayaのArnoldでレンダリングされたインテリアマップ

まとめ

今回はUSDとMaterialXを使ってメッシュとマテリアルのDCCツール間での読み込みを行ってみました。
近年USDを中心としてこのような共通フォーマットの開発が急速に進んでおり、ひと昔前では大変だったツール間のデータのやり取りが効率的に行えるようになってきています。また、このようなフォーマットを積極的に使用していくことで、ツールに依存しない柔軟なパイプラインの構築を行うことができると思います。

この記事が、これからUSDを触られる方や、パイプラインの開発に携わる方、またパイプラインを使う側の方にも参考になれば幸いです。

執筆者:廣瀬

映像業界を経てモノリスソフトへ入社。 以来、テクニカルアーティストとして主にエフェクト関連の業務を担当。 好きな食べものはソフトクリーム。

ABOUT

モノリスソフト開発スタッフが日々取り組んでいる技術研究やノウハウをご紹介

RECRUIT採用情報