From 9943959e76b43632736fcde3a873cd8683299688 Mon Sep 17 00:00:00 2001 From: luchu1993 Date: Sat, 20 Jun 2026 10:22:51 +0800 Subject: [PATCH] Fix model material access with empty entries Allow model instance material APIs to fall back to asset material slots when instance entries have not been initialized yet. Lazily initialize entries before writing material overrides so imported prefab StaticModel instances can call GetMaterial and SetMaterial without assertion failures.\n\nFixes #3801. --- Source/Engine/Level/Actors/AnimatedModel.cpp | 4 ++-- Source/Engine/Level/Actors/ModelInstanceActor.cpp | 7 +++++++ Source/Engine/Level/Actors/SplineModel.cpp | 4 ++-- Source/Engine/Level/Actors/StaticModel.cpp | 8 ++++---- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index ba3a2025d..2f878f3d6 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -1317,8 +1317,8 @@ MaterialBase* AnimatedModel::GetMaterial(int32 entryIndex) SkinnedModel->WaitForLoaded(); else return nullptr; - CHECK_RETURN(entryIndex >= 0 && entryIndex < Entries.Count(), nullptr); - MaterialBase* material = Entries[entryIndex].Material.Get(); + CHECK_RETURN(entryIndex >= 0 && entryIndex < SkinnedModel->MaterialSlots.Count(), nullptr); + MaterialBase* material = entryIndex < Entries.Count() ? Entries[entryIndex].Material.Get() : nullptr; if (!material) { material = SkinnedModel->MaterialSlots[entryIndex].Material.Get(); diff --git a/Source/Engine/Level/Actors/ModelInstanceActor.cpp b/Source/Engine/Level/Actors/ModelInstanceActor.cpp index b8dc3af1a..985e59a71 100644 --- a/Source/Engine/Level/Actors/ModelInstanceActor.cpp +++ b/Source/Engine/Level/Actors/ModelInstanceActor.cpp @@ -39,6 +39,9 @@ void ModelInstanceActor::SetMaterial(int32 entryIndex, MaterialBase* material) WaitForModelLoad(); if (Entries.Count() == 0 && !material) return; + const int32 slotsCount = GetMaterialSlots().Length(); + if (Entries.Count() != slotsCount) + Entries.Setup(slotsCount); CHECK(entryIndex >= 0 && entryIndex < Entries.Count()); if (Entries[entryIndex].Material == material) return; @@ -50,6 +53,10 @@ void ModelInstanceActor::SetMaterial(int32 entryIndex, MaterialBase* material) MaterialInstance* ModelInstanceActor::CreateAndSetVirtualMaterialInstance(int32 entryIndex) { WaitForModelLoad(); + const int32 slotsCount = GetMaterialSlots().Length(); + CHECK_RETURN(entryIndex >= 0 && entryIndex < slotsCount, nullptr); + if (Entries.Count() != slotsCount) + Entries.Setup(slotsCount); MaterialBase* material = GetMaterial(entryIndex); CHECK_RETURN(material && !material->WaitForLoaded(), nullptr); MaterialInstance* result = material->CreateVirtualInstance(); diff --git a/Source/Engine/Level/Actors/SplineModel.cpp b/Source/Engine/Level/Actors/SplineModel.cpp index fdda6941e..5352bf56d 100644 --- a/Source/Engine/Level/Actors/SplineModel.cpp +++ b/Source/Engine/Level/Actors/SplineModel.cpp @@ -356,8 +356,8 @@ MaterialBase* SplineModel::GetMaterial(int32 entryIndex) Model->WaitForLoaded(); else return nullptr; - CHECK_RETURN(entryIndex >= 0 && entryIndex < Entries.Count(), nullptr); - MaterialBase* material = Entries[entryIndex].Material.Get(); + CHECK_RETURN(entryIndex >= 0 && entryIndex < Model->MaterialSlots.Count(), nullptr); + MaterialBase* material = entryIndex < Entries.Count() ? Entries[entryIndex].Material.Get() : nullptr; if (!material) { material = Model->MaterialSlots[entryIndex].Material.Get(); diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index 82976b54c..4ffe1ea6f 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -128,7 +128,7 @@ MaterialBase* StaticModel::GetMaterial(int32 meshIndex, int32 lodIndex) const Math::IsInRange(meshIndex, 0, model->LODs[lodIndex].Meshes.Count())); const auto& mesh = model->LODs[lodIndex].Meshes[meshIndex]; const auto materialSlotIndex = mesh.GetMaterialSlotIndex(); - MaterialBase* material = Entries[materialSlotIndex].Material.Get(); + MaterialBase* material = materialSlotIndex < Entries.Count() ? Entries[materialSlotIndex].Material.Get() : nullptr; return material ? material : model->MaterialSlots[materialSlotIndex].Material.Get(); } @@ -586,9 +586,9 @@ MaterialBase* StaticModel::GetMaterial(int32 entryIndex) { if (!Model || Model->WaitForLoaded()) return nullptr; - CHECK_RETURN(entryIndex >= 0 && entryIndex < Entries.Count(), nullptr); - MaterialBase* material = Entries[entryIndex].Material.Get(); - if (!material && entryIndex < Model->MaterialSlots.Count()) + CHECK_RETURN(entryIndex >= 0 && entryIndex < Model->MaterialSlots.Count(), nullptr); + MaterialBase* material = entryIndex < Entries.Count() ? Entries[entryIndex].Material.Get() : nullptr; + if (!material) { material = Model->MaterialSlots[entryIndex].Material.Get(); if (!material)