[Omniverse] マテリアルでUnlit風の表現を行う

  • by

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に割り当て)。

今回はここまでです。