[Omniverse] [Unity] Omniverse Unity Connectorでのマテリアルの表現 (MDL)

  • by

前回はOmniverse Unity ConnectorからのUSDエクスポートにおけるマテリアルでUsdPreviewSurfaceに焦点を絞って説明しました。
今回はMDL(OmniPBR/OmniGlass)を使用します。

以下の環境で確認しました。

Unity : 2022.3.6f1
Omniverse Unity Connector : 201.0.0 beta
Omniverse USD Composer : 2023.2.0 beta

USD ComposerにUSDファイルを持って行く場合、MDLを使用するほうが整合性が取れている点が多いです。

MDLを使用する利点

ここでの説明はOmniverse Unity Connectorの機能の説明ではなく、OmniverseでMDLを使う場合の説明になります。

MDLを使用すると、UsdPreviewSurfaceよりもより柔軟にマテリアルを表現できます。
OmniPBRやOmniGlassなどのプリセットのMDLを使用する、もしくは独自でShader的なものを書くことも可能です。
OmniPBRやOmniGlassは、MaterialのPrimに対して1つのShaderのPrimだけでパラメータを与えています。

UsdPreviewSurfaceよりも可読性を持たせたパラメータ指定ができます。
個人的には、プログラム(PythonやC++)としてUSDファイルを作成する場合でもOmniPBRやOmniGlassを使うほうが実装しやすいように思います。
OmniPBRを使用するときのusdaファイルを見ると、以下のようになります。

def Material "OmniPBR_cyawan"
{
    token outputs:mdl:displacement.connect = </World/Looks/OmniPBR_cyawan/Shader.outputs:out>
    token outputs:mdl:surface.connect = </World/Looks/OmniPBR_cyawan/Shader.outputs:out>
    token outputs:mdl:volume.connect = </World/Looks/OmniPBR_cyawan/Shader.outputs:out>

    def Shader "Shader"
    {
        uniform token info:implementationSource = "sourceAsset"
        uniform asset info:mdl:sourceAsset = @OmniPBR.mdl@
        uniform token info:mdl:sourceAsset:subIdentifier = "OmniPBR"
        asset inputs:ao_texture = @../textures/cyawan/cyawan_mat_occlusion.png@ (
            colorSpace = "raw"
        )
        float inputs:ao_to_diffuse = 1
        asset inputs:diffuse_texture = @../textures/cyawan/cyawan_mat_albedo.png@ (
            colorSpace = "auto"
        )
        asset inputs:normalmap_texture = @../textures/cyawan/cyawan_mat_normal.png@ (
            colorSpace = "raw"
        )
        float inputs:metallic_constant = 0
        float inputs:reflection_roughness_texture_influence = 1
        asset inputs:reflectionroughness_texture = @../textures/cyawan/cyawan_mat_roughness.png@ (
            colorSpace = "raw"
        )
        token outputs:out (
            renderType = "material"
        )
    }
}

Materialの中の1つのShaderにマテリアルのパラメータやテクスチャが内包されているのを確認できます。
UsdPreviewSurfaceで同等のパラメータを指定する場合、複数のShaderが互いに接続(connect)されていて複雑でした。

Omniverseでは以下の方法でMDLを作成し、マテリアルとして使用できます。

OmniPBR

通常のPBRマテリアルを使用する場合はOmniPBRで事足りることも多いです。
Albedoマップに色を乗算するというのも、UsdPreviewSurfaceより分かりやすいです。

この場合は、Albedo MapとColor Tintは乗算合成された表現になります。
usdaファイルでは以下のように記述されます。

def Material "OmniPBR_cyawan"
{
    token outputs:mdl:surface.connect = </World/SampleScene/Looks/OmniPBR_cyawan/Shaders0.outputs:out>

    def Shader "Shaders0"
    {
        uniform token info:implementationSource = "sourceAsset"
        uniform asset info:mdl:sourceAsset = @OmniPBR.mdl@
        uniform token info:mdl:sourceAsset:subIdentifier = "OmniPBR"

        asset inputs:diffuse_texture = @./Materials/OmniPBR_cyawan/cyawan_mat_albedo.png@
        color3f inputs:diffuse_tint = (0.78378, 0.7102, 0.49932)
    }
}

Albedo Mapの識別名は"inputs:diffuse_texture"、Color Tintの識別名は"inputs:diffuse_tint"です。

またOmniPBRのOpacityを使用した場合の半透明表現では、透過部では屈折率の影響を受けません。
アルファ合成のような表現になります。

OmniPBRの屈折率はデフォルトの1.5が与えられています。パラメータとしては存在しません。
これは透過ではなく、金属での反射の表現などで使用される屈折率です。

OmniGlass

ガラスの表現はOmniGlassを使います。

OmniGlassは透過+屈折を行うマテリアルで使用します。

他にも、SSSを含むよりリッチな表現ができるOmniSurfaceなどを使用できます。
Omniverse Unity ConnectorではOmniPBRとOmniGlassの出力を行います。

Omniverse Unity ConnectorでOmniPBRを使用

Omniverse – Settingsを選択し、Settingsウィンドウを表示します。
Material Typeで"MDL"を選択すると、エクスポート時のマテリアルはOmniPBRかOmniGlassを使用して出力されます。

UnityのURPの場合はShaderとして「Universal Render Pipeline/Lit」を使用すると、大部分のパラメータはエクスポート時にOmniPBRとして反映されます。

ただしUsdPreviewSurfaceと違い、「Universal Render Pipeline/Complex Lit」で存在したClearCoatには対応していません。
これは、OmniPBR/OmniGlassではClearCoatのパラメータが存在しないためです。

UsdPreviewSurfaceとOmniPBRの表現の違い

Omniverse Unity ConnectorからUsdPreviewSurface/OmniPBRでエクスポートした場合、表現力の違いはほとんどありません。
以下は、USDエクスポート時のMaterial Typeを"UsdPreviewSurface"と"MDL"を切り替えて比較してみました。

"UsdPreviewSurface"時はOcclusion Mapが反映されていないように見えます。
パラメータとしては存在する/USDViewでは反映されているため、これはUSD Composer 2023.2.0 betaの問題かもしれません。

UsdPreviewSurfaceとMDL(OmniPBR/OmniGlass)のどちらを使うのがいいか?

出力したUSDファイルをOmniverseで使う場合は、マテリアルとしてOmniPBRを使うほうが調整しやすいです。
互換性のため、他のツールやARKitなどでUSDを扱う場合はUsdPreviewSurfaceを使うようにします。
半透明(ガラス表現)を行う場合はOmniGlassを使うほうが調整しやすいため、MDLを使うのがよさそうです。

OmniPBRでの半透明の表現

Unity上で以下のような瓶をUSDエクスポートします。

半透明にするために、マテリアルのパラメータは以下を指定しました。

  • Surface Type = Transparent
  • Render Face = Both
  • Base Mapのアルファ = 0.1098

これをMaterial Typeで"MDL"を指定してUSDエクスポートしました。
USD Composerで読み込むと以下のようになります。

映り込みが分かりやすいように、Environmentsより背景を変更しました。
USD ComposerのRTXレンダラは、デフォルトで両面表示になります。
そのため、ガラス瓶のような両面が必須な表現はそのまま反映されます。

この段階では、透過時の屈折が存在しないためのっぺりしています。
Built-In/URPでは、MDLとしてエクスポートする場合はOmniPBRを使用します。
そのため、半透明は意図した表現が難しいかもしれません。

HDRPの場合

UnityのHDRP時は、USDエクスポート時に特定のパラメータ指定でOmniGlassを使用することができます。

以下のように"HDRP/Lit"のガラス瓶のマテリアルを指定しました。

  • Surface TypeでTransparentを指定。

  • Base Mapのアルファ値を0.0にする

  • Refraction ModelでNone以外を選択

この条件を満たすと、USDエクスポート時にTransparent表現はOmniGlassで出力されます。
このとき、以下のパラメータがOmniGlassに反映されます。

  • Metallic
  • Smooothhess
  • Index Of Refraction
  • Transmittance Color

"Transmittance Color"がGlassの色に相当します。
このとき、Base Mapの色は使われていません。

USDエクスポートして、USD Composerにインポートしました。
背景とライトを調整すると、以下のようになりました。

なお、OmniGlassを使用する場合にRoughnessは"RTX-Intaractive(Path Tracing)"でないと反映されません。
"RTX-Intaractive(Path Tracing)"では以下のようになりました。

影もより自然になりました。

Unity(HDRP)でより自然な透過+屈折を行うには?

ここでの指定は、Omniverse Unity ConnectorのUSDエクスポート/インポートには影響しません。
あくまでUnity Editor上の表現の話になります。

Unity 2022(HDRP)の初期状態では、DX11が使用されます。
屈折が絡む場合は、レイトレーシングを行わないと表現で気になる点が出てきます。
以下のような3つのガラスを使った形状を考えてみます。

これは、以下の3つのマテリアルの指定を行ってIORを反映しました。

  • Surface TypeでTransparentを指定。
  • Base Mapのアルファ値を0.0にする
  • Refraction ModelでSphereを選択

しかし、屈折は不自然です。
HDRPでの屈折の場合、メッシュに対してレイトレーシングすると仮定したときに1回のIn+1回のOutとなる形状(球など)とならない表現は難しいようでした。
そのため、HDRPのレイトレを使うようにしました。
これはDX12に切り替える必要があります。

HDRPでレイトレーシングを使用

  • Edit – Project Settingsを選択し、Project Settingsウィンドウを表示。
    Playerを選択し、Other Settings – Graphics APIs for Windowsに"Direct3D12"を追加します。

    "Direct3D12"が先頭になるように順番を入れ替えるようにしてください。
  • Window – Rendering – HDRP Wizardを選択。
    HDRP + DXRタブを選択し、「Fix」ボタンがある場合はクリックしていきます。
    途中でUnity Editorの再起動を促される場合があるため、これは指示に従います。

    全部で緑色のチェックが付けばOKです。
    なおHDRP + DXRを使用するには、
    https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@14.0/manual/Ray-Tracing-Getting-Started.html
    より、レイトレーシングが使用できるGPUであるかどうかチェックする必要があります。
  • Unity Editorのキャプションで<DX12>が表示されているのを確認。
  • Hierarchyウィンドウで右クリックし、Volume – Global Volumeを選択。
    GameObject名を"RayTracing"に変更しました。
  • "RayTracing"のInspectorウィンドウを表示。
    Profileを作成します。これはファイルになり、ここにこのボリュームの設定が保存されます。

    一番下の「Add Override」ボタンをクリックし、Ray Tracingの"Ray Tracing Settings"と"Recursive Rendering"を追加します。
    それぞれの左上に薄っすらと見える"ALL"をクリックすると、すべての項目がOnになります。
    "Recursive Rendering"のStateを"Enabled"に変更します。

これで、シーンでレイトレーシングを使用する準備が整いました。
このときUnityのレンダリングのすべてがレイトレーシングされるわけではなく、機能ごとにレイトレーシングを使うか個別に指定していくことになります。

  • ライトの影
  • マテリアルの透過処理

などがレイトレーシングの対象です。
今回はマテリアルの透過処理でレイトレーシングを有効にします。
IORを使用しているマテリアルで"Recursive Rendering (Preview)"をOnにします。

これで、以下のように自然な透過+屈折表現になりました。

全ての形状に同じ処理を行いました。

透過の最大数はデフォルト4のため、RayTracing用に作成されたボリュームのパラメータを調整します。
"Recursive Rendering (Preview)"のMax Depthパラメータで調整できます。

4から6に変更しました。

これで、Unity Editorで透過+屈折のガラス表現もいい感じになりました。

USDエクスポートし、USD Composerに持って行く

USDエクスポートを行います。
このとき、Unity Editor側のOmniverse-SettingsでMaterial Typeは"MDL"を選択するようにしてください。

USDファイルのエクスポート後はUSD Composer側の作業になります。
USD Composer側でインポートし、背景(DomeLight)の変更/ライトの調整を行いました。
また、Post ProcessingでTone Mapping OperatorでIrayを選択し、Crash Blacksを0.03に変更しました。

RTX-Real-Timeでは以下のようになりました。

RTX-Interactive (Path-Tracing)ではより自然になりました。

以上で、UnityでOmniverse Unity Connectorを使用してMDL(OmniPBR, OmniGlass)のマテリアルを渡すことを確認できました。