Mutableのメッシュストリーミング環境下において、特定のLODでのみMorph Targetが存在するメッシュを使用した場合、パッケージ版にてMorph Targetが正常に機能しない問題に直面しています。
【詳細な原因】
遠景のLOD(Morphデータを持たないLOD 3/4など)でMutableメッシュの初期生成が行われると、CustomizableObjectInstance.cpp の BuildOrCopyMorphTargetsData 関数内で Context->InstanceUpdateData.RealTimeMorphTargets が空になります。
その結果、USkeletalMesh にMorph Targetが1つも登録されずに生成が完了してしまいます。
その後、カメラが近づいてLOD 0が読み込まれても、SkeletalMeshにMorph Targetが登録されていない状態が続くため、ウェイトを変更しても描画に反映されません。また、ストリーミングされるLODモデルの SectionIndices が空のままになるため、レンダラーが対象セクションを処理しない問題も発生しています。
【提案するHotfix】
この問題を回避するため、以下の2ファイルに修正を加えました(具体的な実装コードは文字数制限のため添付ファイルとしてお送りします)。
1. CustomizableObjectInstance.cpp (BuildOrCopyMorphTargetsData)
InstanceUpdateData からMorphが取得できない場合でも、ModelStreamableBulkData の RealTimeMorphStreamables から直接マスターリストを抽出し、USkeletalMesh に登録するよう変更しました。
ストリーミング時、空のLODモデルに対して SkeletalMesh->GetResourceForRendering()->LODRenderData[LODIndex].RenderSections.Num() を用いて、描画されるすべてのセクションインデックスを強制的に SectionIndices に追加する処理を入れました。
これにより、遠景でスポーンした際にもMorph Target制御が正常に動作することを確認しています。
2. CustomizableObjectSystem.cpp (ReconstructMorphTargets)
上記の修正のみだと、SkeletalRenderGPUSkin.cpp の以下のensureに引っかかります。
ensureAlways(DynamicData->MorphTargetWeights.Num() == LODData.MorphTargetVertexInfoBuffers.GetNumMorphs());
これを防ぐため、ReconstructMorphTargets 関数内で早期リターンする前に OutMorphTargets.SetNum(GlobalNames.Num()); を設定し、GPU配列のサイズがCPU側のマスターリストと必ず一致するように修正しました。
【ご質問】
- 当面はこのHotfixアプローチで運用することを検討していますが、これによりメモリリークやレンダリング不具合など、潜在的な問題を引き起こす可能性はありますでしょうか。
- もし、この問題に対するより適切な解決策(エンジンの設定や既存の修正パッチなど)が既にある場合は、ご教示いただけますと幸いです。
ご確認のほど、よろしくお願いいたします。
[Attachment Removed]
再現手順:
- Morph Targetを持つLODと持たないLODが混在するSkeletal Meshを用意する(例: LOD 0,1,2はMorphあり、LOD 3,4はMorphなし)。
- MutableプラグインおよびMesh Streamingを有効にする。
- パッケージビルドにて、キャラクターをカメラから遠い位置(LOD 3または4の距離)でスポーンさせ、メッシュを初期生成する。
- キャラクターにカメラを近づけ、LOD 0をストリーミングで読み込ませる。
- 該当SkeletalMeshComponentに対してMorph Targetのウェイトを設定しても、メッシュが変形しない。
※エディター上では発生せず、パッケージ版でのみ発生します。
[Attachment Removed]
大変お待たせしております。
本件再現プロジェクトを作ってバグ登録したいと思いますので少々お待ちください。
コードを見るだけでは重大なメモリリークやクラッシュにつながるようには見えませんが、確実なことは申し上げられません。ご自身で動作させてテストを行っていただければ幸いです。
修正に関してはMain(5.8以降)でこの辺りのコードが大きく書き換えられたためそのまま適用することは難しいです、そのためバグ登録後に開発チームによる修正をお待ちいただければ幸いです。
[Attachment Removed]
UE-394214 [Mutable] Morph Targets can be disabled in packaged builds when Mesh Streaming is enabled としてバグ登録させていただきました。数営業日ののちにUnreal Engine Issuesに公開予定です。
[Attachment Removed]
ご確認およびバグ登録のご対応、誠にありがとうございます。
Main(5.8以降)での修正対応となる旨、承知いたしました。
5.7 環境については、現在ローカルでの修正で問題なく動作しております。
もしこの修正に関連して「将来的に別の問題に繋がる可能性がある点」や「5.7 上で修正するにあたり注意・留意すべき情報」などがありましたら、ご共有いただけますと幸いです。
お手数をおかけいたしますが、よろしくお願いいたします。
[Attachment Removed]
恐らく致命的な問題になることは無いと思うのですが、
> 描画されるすべてのセクションインデックスを強制的に SectionIndices に追加する処理を入れました
この部分が本来のセクションインデックスに構築される部分との差になってしまう点が少々気がかりです。
理想的には Subtask_Mutable_PrepareRealTimeMorphData 冒頭での早期リターンで失われてしまうモーフターゲット名などの情報を、
ワークアラウンドと同じようにストリーミング前でもアクセスできる情報から構築する方が望ましいのではないかと思いますが、実際に実現可能かどうかを検証しておりません。
この点に関しては正式な修正をお待ちいただければと思います。
[Attachment Removed]
CL 57717686 にて修正がサブミットされました。修正はUE5.8.4に適用の見込みです。
[Attachment Removed]
修正のご対応および CL のご共有、誠にありがとうございます。
UE5.8.4 にて修正が適用予定となる旨、承知いたしました。
ワークアラウンドに関するアドバイスも含め、迅速にご確認・ご対応いただき大変助かりました。
修正コードについても参考にさせていただきます。
今後ともよろしくお願いいたします。
[Attachment Removed]