USDのマテリアルでは、Unlit(シェーディングせず/ライトの影響を受けずにDiffuseColor/DiffuseColorMapをそのまま表示)機能はありません。
そのため、glTFやfbxなどからUSDにコンバートしてくる場合はEmissiveColorでUnlit風の表現を行う場合が多いかもしれません。
以下の用途でUSDをUnlit風にしているのを確認しています。
- フォトグラメトリの3Dモデル (Sketchfab上など)
- トゥーン調のシェーディング
- 上記をAR(AR Quick Look/Appleの環境)で表示する場合
Omniverseの場合は物理的に忠実に光源や発光を表現するため、Unlitはできなくてもいいかもしれませんが、
やはり使う箇所は出てくるかなとは思います。
そこで、今回はOmniverseでのUnlit風の表現はどのように行うか?について書いていきます。
OmniverseでUnlit風の表現を行うには ?
対象形状のマテリアルとして「OmniSurfaceLite」を割り当てます。
「OmniSurfaceLite」は、「OmniSurface」からTransmissionやSubsurface、Sheen、Thin Filmを除いたものです。
今回はマテリアルの「Emission」だけ使用するため、OmniSurfaceLiteで十分です。
OmniSurfaceLiteを割り当てた直後は以下のような感じ。
BlenderのSuzanneさんを持ってきました。
OmniSurfaceLiteでEmissionのみを有効にする
OmniSurfaceLiteのパラメータで、「Base」と「Specular」の「Weight」を0にします。
これにより、ライティングされていても真っ黒になります。
「Emission」の「Weight」を1.0にします。
真っ白になりました。
これは、Emissionの「Color」の値が反映されています。
Colorを薄緑に変更しました。
以下のようになりました。
Colorで指定した色よりも明るくなるのは、「Omniverseでは色はリニアで指定する必要があるから」です。
Omniverseがというよりも、USD自身が色についてはリニアで指定する必要があります。
テクスチャの場合は、sRGBやrawなどのColor Spaceの指定ができます。
sRGBを指定したらテクスチャと同じ色で反映されることになります。
内部的にsRGBからリニア変換されレンダリングはリニアで統一されます。最終的なレンダリングが終わったあとに全体がsRGBに変換されます。
Emission Colorをリニアに変換
EmissionのColorのRGBをリニアに変換します。
計算式を入れる必要がありますが、Pythonで書くと以下のような計算になります。
※ 厳密にはsRGBとGamma2.2は異なるため、これは近似と考えてください。
import math
gamma = 2.2
RValue = 0.49045
GValue = 0.72587
BValue = 0.49886
RValue2 = math.pow(RValue, 1.0 / (1.0 / gamma))
GValue2 = math.pow(GValue, 1.0 / (1.0 / gamma))
BValue2 = math.pow(BValue, 1.0 / (1.0 / gamma))
print("R = " + format(RValue2, '.4f'))
print("G = " + format(GValue2, '.4f'))
print("B = " + format(BValue2, '.4f'))
RGB(0.49045, 0.72587, 0.49886)をリニアの値に変換すると、RGB(0.2086, 0.4942, 0.2165)となります。
この値をEmissionのColorに入れると以下のようになりました。
ただし、厳密にはGamma2.2とsRGBとの違い、Post Processingにより色は完全一致ではありません。
Emission Color Mapを指定
「Emission」の「Color Image」にテクスチャを指定します。
また、「Color Image Color Space」を「sRGB」に変更しました。
これで、テクスチャ色をそのまま表現となりました。
左下のテクスチャを割り当てています。
なお、Unlitの場合はDiffuseColorMap(AlbedoMap)のみ使用し、Roughness/Metallic/NormalMapは未使用となります。
わずかな色の差が気になるため、Post ProcessingのTone Mappingを調整してみましょう。
Post Processingの「Tone Mapping」で「Linear」にします。
これで、Post Processingがかかっていない状態でレンダリングされます。
これでオリジナルの色合いに近づきました。
defaultLightを無効にすると以下のようになります。
Emissionを使用しているため、発光するマテリアルになってます(そのため「Unlit風」)。
UsdPreviewSurfaceやOmniPBRでこの表現ができる ?
マテリアルでOmniSurfaceを使った場合はOKですが、UsdPreviewSurfaceやOmniPBR、独自MDLの場合はEmission/Emissive Colorで色を指定しても暗すぎる結果になります。
これは間違っているわけではなくて、Omniverse側の光源の単位が影響していると思われます。
OmniSurfaceの「Emission Mode」が参考になります。
https://docs.omniverse.nvidia.com/app_create/prod_materials-and-rendering/materials.html?highlight=material#omnisurfacebase-emission-mode
この計算については、後々ブログで解読してみようと思います。
もうちょっと映えるサンプルで確認
もうちょっと映えるサンプルとして、フォトグラメトリから得られた3Dモデルとテクスチャを使用してみます。
以下、光源なし、Unlit風の表現です。
フォトグラメトリのテクスチャをそのまま反映しています(OmniSurfaceLiteのEmissionに割り当て)。
今回はここまでです。