ライトマップとグローバルイルミネーション

はじめに

ベイクドライトマップは、DirectionalLightPointLightSpotLight などのライトからの直接照明を、ライトによってキャストされる影も含めて、事前に生成することができます。実行時に、フラグメントシェーダで適切な計算を行い、シャドウの場合はコストのかかるシャドウマップをリアルタイムで生成する代わりに、事前に生成されたイメージマップをサンプリングします。

注意: Qt 6.4 現在、ライトマップベイクは初期のテクニカルプレビューの状態です。機能、品質、API の変更は将来のリリースで行われる可能性があります。

ライトマップは Model ごとに生成されます。Modelが複数のサブメッシュを持ち、複数のマテリアルと関連している場合でも、モデル全体に対して生成されるライトマップ画像は1つになります。

ライトマップはレイトレーシングを使用して生成され、その性質上、適切なオクルージョン(「光は壁を伝わらない」)を提供し、おそらくライティングとシャドウマッピングのためのリアルタイム技術よりもリアルな影を提供します。

さらに重要なのは、ライトマップは間接照明の焼き付けを可能にし、グローバルイルミネーションのソリューションを提供することです。これは、シーン内の他のサーフェスから反射された光線を考慮に入れます。

以下は簡単な例です。このシーンには、4つのRectangleと1つのSphereモデルがあり、DirectionLightが下を向いていて、PointLight 。Rectangleモデルは0度と90度回転しています。DirectionalLight'の方向に対してすべて平行か垂直であるため、リアルタイムのライティング計算の限界を誇張しています。

右側では、5つのモデルすべてに対してライトマップをベイクした後、ライトマップを有効にしてシーンをレンダリングしています。どちらのライトも完全にベイクされた状態に設定されています。つまり、直接照明と間接照明の両方がベイクされています。間接照明は256samples 、最大3bounces 。その結果、ライトマップはノイズ除去された。これにより、かなりリアルな画像が得られます。

リアルタイム照明

"Simple scene with sphere, rectangles, and two lights"

完全にベイクされたライティング

"The same scene with both lights set to fully baked"

以下は、ライトマップの結果がどのように達成されたかを示すスニペットです。違いはusedInBakedLighting,bakeMode,bakedLightmap プロパティにあります。この例では、lightmapBaseResolution プロパティを使用してライトマップのサイズを縮小し、ディスクスペースを節約してアプリケーションのロード時間を短縮しています。

DirectionalLight {
    bakeMode: Light.BakeModeAll

    eulerRotation.x: -90
    brightness: 0.5
    castsShadow: true
    shadowFactor: 75
}
PointLight {
    bakeMode: Light.BakeModeAll

    y: 200
    z: 100
    color: "#d9c62b"
    castsShadow: true
    shadowFactor: 75
}
Model {
    usedInBakedLighting: true
    lightmapBaseResolution: 256
    bakedLightmap: BakedLightmap {
        enabled: true
        key: "sphere1"
    }

    source: "#Sphere"
    materials: PrincipledMaterial { }
    y: 100
}
Model {
    usedInBakedLighting: true
    lightmapBaseResolution: 256
    bakedLightmap: BakedLightmap {
        enabled: true
        key: "rect1"
    }

    source: "#Rectangle"
    materials: PrincipledMaterial { }
    eulerRotation.x: -90
    scale: Qt.vector3d(10, 10, 10)
}

// ... three additional Rectangle models, with rotations 0, 90, and -90

上記の例では、完全にベイクされたライトを使用しました。ライトは、ダイレクトライティングとシャドウマッピングをリアルタイムで実行しながら、間接照明にのみベイクドライティングを使用するように設定することもできます。下のシーンには5つのポイントライトがあり、右のスクリーンショットではそのすべてがBakeModeIndirect に設定されています。ダイレクトライティングとシャドウは同じに見えますが、右の画像はグローバルイルミネーションが追加されているため、かなり良く見えます。

リアルタイム・ライティング

"Scene with Sponza and Suzanne models and 5 point lights"

ベイクされた間接照明を追加した状態

"Same scene with baked indirect but real-time direct lighting"

ライトマップで作業する際の重要な考慮事項

ベイクド・ライティングに寄与するライトは、bakeMode プロパティが BakeModeIndirect または BakeModeAll に設定されています。後者は、その特定のライトの直接寄与と間接寄与の両方がライトマップから来ていることを示します。直接寄与には、常にシャドウも含まれます。一方、ライトマップを使用する意図が、特定のライトに対してシーンに間接照明を追加するだけで、リアルタイムで直接照明を計算する(シャドウマッピングを実行する)場合は、ライトは代わりにBakeModeIndirectを使用する必要があります。

注意: ライトマップは一般的に言って、トランスフォーム、ジオメトリ、マテリアルに関して静的なモデルに適しています。これは、ベイクされたライティングに参加するライトにも当てはまります。

例えば、eulerRotation プロパティをアニメートすることによってモデルを回転させるシーンは、そのモデルにライトマップを適用するとき、視覚的に正しくない結果をもたらします。事前に生成されたライトマップは、オブジェクトの単一の回転状態しかキャプチャしないため、その特定のModelのレンダリング結果は不正確になります。別の例を挙げると、モデルのサブメッシュの1つのマテリアルが、時間(アニメーション)またはユーザーインタラクションに基づいて、baseColor プロパティを動的に変更する場合も同様です。ライトマップは、与えられた1つのマテリアルbaseColor しかキャプチャできません。ライトも同様です。たとえば、DirectionalLight 、時間とともに回転したり、明るさや色などを変えたりするものは、ベイクド・ライティングには適していません。

注意: 一方、ライトマッピングをいつ使用するかは、常にデザイナーの選択です。特にBakeModeIndirect 、ライトマップされたシーン内のオブジェクトの一部がダイナミックな動作を採用していても、その結果が視覚的に満足できるシーンがある可能性があります。

ライトマッピングは、複雑なエンジンとツール機能です。エンジンのレンダリングパイプラインのいくつかの部分を置き換え、再実装します。ライトマップをベイクする際には、根本的に異なるレンダリングモデルで動作しますが、同じシーン構造、アセットデータ、エンジンデータ構造を消費し、相互運用します。レイトレーシングに基づく結果は、多くの場合、リアルタイムの代替案を、時には大幅に凌駕しますが、その代償として、関係するモデルやライトの強制的な静的性などの制限や、時にはライトマッピングに特有の品質やレンダリングアーチファクトの問題が生じます。

実際には、どのタイプのライティングをいつ使うかは、デザイナーの芸術的な選択になります。bakeMode また、複雑で大規模なシーンでは、シーンの特定のセクションに適していると判断されるものや、どのようなモデル、マテリアル、ダイナミックなビヘイビアが存在するかに応じて、3つすべての異なるライトを利用することも大いにありえます。ライトマッピングは、どのシーンやアプリケーションでも有効にできる単純なオン/オフの切り替えスイッチではなく、与えられたシーンのライティングニーズを慎重に評価することを前提とした強力な機能であり、多くの場合、シーンのコンテンツとビヘイビアをそれに応じて設計し、最終的なアプローチと関連する設定を決定する前に、さまざまなライトマップのベイクとクオリティ設定を検討し、テストするテストアンドチューンのループと組み合わせる必要があります。

注意: ライトマップは両面サーフェスをサポートしていません。リアルタイムライティングでは、Material.NoCullingcull mode を持つマテリアルは、フラグメントの向きに基づいて法線を自動的に反転します。ライトマップのベイクはビュー空間では動作しないため、これはライトマップのオプションではありません。したがって、これに依存するようなモデルにはベイクドライティングを避けてください。

ライトマップのベイク

ライトマップのベイクに関連するプロパティとタイプは、直接照明と間接照明をキャプチャし、アプリケーションの後続の実行でレンダラーが使用できるイメージマップを生成するオフラインプロセスを意味します:

Qt 6.4 では、ライトマップのベイク処理は手動でトリガーする必要があります。コマンドライン引数--bake-lightmaps が存在するか、環境変数QT_QUICK3D_BAKE_LIGHTMAPS1 (またはその他のゼロ以外の値)に設定されている場合、エンジンはベイクモードで動作し、ベイクが完了するとアプリケーションを終了します。デバッグ出力に出力されるメッセージを確認することで、ベイク処理の手順を追うことができます。その結果、カレントディレクトリに.exr ファイルが書き込まれます。ファイル名にはそれぞれqlm_ というプレフィックスが付き、その後にBakedLightmap::key からのユニークキーが続きます。

ライトマップされたシーンの準備には、主に以下の手順が必要です:

  • ライトマップを使用するモデルと、ライトマップに貢献するモデルを特定する。ライトマップされたシーンの一部であるモデルは、Model::usedInBakedLighting を true に設定します。ライトマップされる(つまり、ライトマップがベイクされる)モデルは、さらにModel::bakedLightmap を有効なBakedLightmap オブジェクトに設定する必要があります。(これは、Qtが永続的なディスクストレージでモデルデータを識別するためにキーを必要とするためです)静的なジオメトリ、トランスフォーム、マテリアルを持つモデルだけが、ランタイムにライトマップされたときに正しい結果を持つことが保証されます。最も一般的なのは、位置、回転、スケールが動的に変化したり、アニメーションしたりするなど、時間の経過とともに静的でないワールドトランスフォームにつながるものは、モデルの参加資格を失うということです。しかし、特に間接照明のベイクにのみ寄与し、それ自体はライトマップされないモデルの場合、芸術的なニーズがこれを上書きすることがあります。このようなモデルの場合、ダイナミックトランスフォームを使用することが、視覚的に許容されることがよくありますが、これは常にモデルと問題のシーンに依存します。
  • どのライトがどの程度寄与すべきかを特定します。Light::bakeMode には、3つのオプションがあります:
    • デフォルトのLight.BakeModeDisabledは、事実上、すべてのライトマッピングの目的でライトを無視します。
    • Light.BakeModeIndirectは、シーンにグローバルイルミネーション(間接照明)のレベルを持たせることが唯一の目的であり、他の方法でライトのレンダリング結果に影響を与えない場合、多くの場合、「安全な」選択です。このモードでは、レンダラーは、ディフューズ、スペキュラ、スカイ/環境寄与、シャドウマッピングを含むすべてのライティングを、標準的なリアルタイム技術を使ってこのライトに対して実行し続けます。ただし、ライトはプリベイクされたデータを使用して間接照明に寄与し、標準のリアルタイム照明計算では手を付けられないサーフェスを照らす可能性があります。
    • Light.BakeModeAllは、与えられたシーンに何が適切かについてのデザイナーの評価に基づいて、特定のライトにのみ使用されるオプションです。このモードでは、シャドウを含め、ライトからのすべての寄与がベイクされます。Qt 6.4 では、スペキュラライティングはベイクされたライティングの一部としてサポートされていません。一方、レイトレースされ、ベイクされたシャドウが生成され、ライトに対して適切なオクルージョンがあります(例えば、「壁を通り抜ける」ことはありません)。さらに、BakeModeIndirectと同様に間接照明もベイクされます。
  • ベイクモードでシーン(アプリケーション)を実行し、ライトマップが正常に生成されていることを確認します。Qt 6.4では、アプリケーションはライトマップされたシーンが最初に表示されるように構成されるか、qml ツールのようなQMLビューアで当該シーンを読み込むことができます。ベイクが完了すると、その進行状況はコンソール/デバッグ出力で追うことができ、アプリケーションは終了します。
  • シーン(アプリケーション)を普通に実行し、ライトマップがロードされた状態でどのように見えるかを確認します。その後、チューニングを開始します:
    • モデルによっては、lightmapBaseResolution をデフォルトの1024から、もっと小さくする意味があります。これは特に、ビルトインのプリミティブや、ジオメトリが単純なものに当てはまります。これにより、ライトマップが小さくなり、ベイク時間が短縮されます。初めてベイクするときは、デフォルトで十分です。
    • Lightmapperオブジェクトは、合理的なデフォルト値を持つ数多くの設定を公開していますが、設計者の期待に合うようにこれらのいくつかを調整する必要がある可能性は低くありません。例えば、samplesbounces は間接照明の質に影響するように変更でき、indirectLightFactor は間接照明の寄与をより顕著にすることができます。アーティファクト、特にシャドウ周辺が発生する場合は、bias を微調整できます。
    • 生成されたライトマップのノイズ除去は不可欠です。間接照明はパストレーシングを使用して計算され、samples の数によってノイズの多い画像が生成されます。サンプル数を増やすとノイズは減りますが、ライトマップの生成に必要な時間が長くなります。サンプル数に関係なく、.exrファイルとして保存された32ビットRGBA浮動小数点画像である生成されたライトマップに対してノイズ除去を実行することは、ほとんどの場合意味があります。

Qt 6.5では、DebugView を使ってインタラクティブにランタイム・ソリューションを提供します。 ツール(Tools)の下にボタンがあり、それを押すとベイク処理が開始されます。現在の処理を示すウィンドウがポップアップします。キャンセルするには、キャンセルボタンを押すか、このウィンドウを閉じる。完了すると、loadPrefixを使用して、可能であれば既存の.exrファイルを上書きしようとしますが、そうでなければカレントディレクトリに書き込まれます。今のところ、デノイジングは、ランタイム・ソリューションを使用している場合でも、まだ手動プロセスである。

デノイジング

以下は、コーネルボックスのシーンの例です。まず、256samples と最大 3bounces でベイクされたライトマップを使ってレンダリングします。2番目の例では、生成された画像ファイルをOpen Image Denoiseライブラリを使用してノイズ除去にかけました。結果はかなり良くなり、ノイズはほとんどなくなりました。

オリジナル

"Cornell box scene with one point light, fully baked lightmap"

ノイズ除去済み

"Cornell box scene with the lightmaps denoised"

Qt Quick 3Dで生成されたqlm_*.exr 画像で動作する、OIDN用のシンプルなQtベースのコマンドラインラッパーは、https://git.qt.io/laagocs/qlmdenoiser。現在はソースからビルドする必要があり、ビルド済みのバイナリはありません。

ライトマップUV

ライトマップ UV 座標は、通常のテクスチャリングと同じ UV データを使用しません。ライトマップを使用してレンダリングする場合、ライトマップをサンプリングするときにUV0とUV1のどちらのデータもレンダラーによって使用されません。その代わりに、メッシュに追加の専用UVチャンネルがあり、ライトマップの目的に適した方法でレイアウトされたUVチャートを含みます。これは、オーバーラップを避け、適切な場所にパディングを持つことを含みます。通常のUVデータにはそのような要件はなく、複数の頂点に同じUとV座標を使いたい場合も大いにあり得ます。

適切なUVセットを生成するプロセスは、ライトマップUVアンラップと呼ばれます。Qtは、ライトマップをベイクするときも、シーンを普通にレンダリングするときも、常に実行(ロード)時にこれを実行することができます。

実行時にライトマップモデルのライトマップUVデータを生成しないようにしてメッシュのロード時間を改善するために、2つのオプションがあります:

  • ライトマップUVデータが利用できないモデルの場合、ライトマップベイクプロセスは、.exr イメージと同様に、BakedLightmap::key に基づいて生成された名前の、qlm_*.mesh ファイルのセットも出力します。アプリケーションが希望する場合、これらの余分な.mesh ファイルを.exr アセットと一緒に送信できます。その場合、これらのメッシュファイルは通常のモデルデータの代わりに使用され、ライトマッピングに関連するデータはすぐに利用できるようになります。ただし、これは完全にオプションです。qlm_key.meshが実行時に見つからない場合、UVアンラッピングはアプリケーションに対して透過的に実行時に行われます。
  • あるいは、バルサムツールは、アセットインポート時にライトマップUVデータを事前に生成するオプションを提供しています。つまり、モデルの.mesh ファイルには最初から必要なデータが含まれており、ライトマップベイク時に余分なメッシュが生成されないので、アプリケーションに余分なアセットを同梱する必要がありません(もちろん、ライトマップイメージは別です)。これを行うには、--generateLightmapUV を balsam に渡します。

ライトマップのテクスチャサイズ

すべてのサブメッシュを含む各モデルに対して、ライトマップベイクプロセスはライトマップUV生成フェーズで適切なライトマップテクスチャサイズを決定します。これは品質、パフォーマンス、リソース使用量(ディスクとメモリの両方)に影響します。

デフォルトは多くの場合適切で、特に中〜高複雑度のモデルでは調整の必要はありません。

しかし、非常に単純なモデルの場合、手動でサイズを小さくすることが望ましい場合があります。ライトマップのサイズを小さくしても、視覚的に見栄えの良い結果を得られる可能性がある一方、アセット(ライトマップ画像)のサイズを小さくすると、ディスク容量とメモリの両方を節約できるからです。これを行うには、lightmapBaseResolution を適切な小さい数値に設定します。一般的な選択肢は256、512、1024ですが、128を最小として他の数字でもかまいません。実際のライトマップの幅と高さは異なりますが、指定したサイズとほぼ同じになります。

この値を変更するときは、必ずライトマップをリベイクし、変更したライトマップサイズの影響を評価するために結果を目視で確認する必要があります。

ランタイムでのライトマップの使用

プリベイクされたライトマップをランタイムで使用する場合に関連するプロパティとタイプです:

ベイクが正常に完了すると、(コマンドライン引数や環境変数を設定せずに)アプリケーションを通常どおりに実行すると、生成されたライトマップ画像を拾って正しくレンダリングできるようになります。必要であれば、アプリケーションはライトマップを別の場所に置いたり、Qt Resource System を経由して実行可能ファイルの一部として送信することができます。これは、BakedLightmap::loadPrefix プロパティによって有効になります。

上記の球と4つの長方形のサンプルコードを例にとると、ベイク処理によって5つの.exr ファイル(qlm_sphere1.exr,qlm_rect1.exr,qml_rect2.exr など)と、リストファイルqlm_list.txt が生成されます。これは、複数のファイルを一度に処理するノイズ除去ユーティリティの入力として便利ですが、それ以外の実行時には使用されません。アプリケーションは、.exr ファイルを出荷する必要があります。これは、エンジンが、コンポーネントを含むディレクトリと同じディレクトリか、loadPrefix で指定された場所のいずれかで見つけられるようにするためです。

読み込みルールは、qlm_sphere1.meshqlm_rect1.mesh のようなオプションの.mesh ファイルにも適用されます。シーンの読み込み時間を短縮したい場合は、.exr ライトマップ画像の隣に.mesh ファイルを配置する必要があります。

Qt Quick 3D - Baked Lightmap Exampleも参照してください

©2024 The Qt Company Ltd. 本書に含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。