9943959e76
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.
108 lines
3.1 KiB
C++
108 lines
3.1 KiB
C++
// Copyright (c) Wojciech Figat. All rights reserved.
|
|
|
|
#include "ModelInstanceActor.h"
|
|
#include "Engine/Content/Assets/MaterialInstance.h"
|
|
#include "Engine/Level/Scene/SceneRendering.h"
|
|
|
|
ModelInstanceActor::ModelInstanceActor(const SpawnParams& params)
|
|
: Actor(params)
|
|
{
|
|
}
|
|
|
|
String ModelInstanceActor::MeshReference::ToString() const
|
|
{
|
|
return String::Format(TEXT("Actor={},LOD={},Mesh={}"), Actor ? Actor->GetNamePath() : String::Empty, LODIndex, MeshIndex);
|
|
}
|
|
|
|
MeshBase* ModelInstanceActor::MeshReference::Get() const
|
|
{
|
|
auto actor = Actor.Get();
|
|
return actor ? actor->GetMesh(*this) : nullptr;
|
|
}
|
|
|
|
void ModelInstanceActor::SetEntries(const Array<ModelInstanceEntry>& value)
|
|
{
|
|
WaitForModelLoad();
|
|
bool anyChanged = false;
|
|
Entries.Resize(value.Count());
|
|
for (int32 i = 0; i < value.Count(); i++)
|
|
{
|
|
anyChanged |= Entries[i] != value[i];
|
|
Entries[i] = value[i];
|
|
}
|
|
if (anyChanged && _sceneRenderingKey != -1)
|
|
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Visual);
|
|
}
|
|
|
|
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;
|
|
Entries[entryIndex].Material = material;
|
|
if (_sceneRenderingKey != -1)
|
|
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Visual);
|
|
}
|
|
|
|
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();
|
|
Entries[entryIndex].Material = result;
|
|
if (_sceneRenderingKey != -1)
|
|
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Visual);
|
|
return result;
|
|
}
|
|
|
|
void ModelInstanceActor::WaitForModelLoad()
|
|
{
|
|
}
|
|
|
|
void ModelInstanceActor::OnLayerChanged()
|
|
{
|
|
if (_sceneRenderingKey != -1)
|
|
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::Layer);
|
|
}
|
|
|
|
void ModelInstanceActor::OnStaticFlagsChanged()
|
|
{
|
|
if (_sceneRenderingKey != -1)
|
|
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, ISceneRenderingListener::StaticFlags);
|
|
}
|
|
|
|
void ModelInstanceActor::OnTransformChanged()
|
|
{
|
|
// Base
|
|
Actor::OnTransformChanged();
|
|
|
|
UpdateBounds();
|
|
}
|
|
|
|
void ModelInstanceActor::OnEnable()
|
|
{
|
|
GetSceneRendering()->AddActor(this, _sceneRenderingKey);
|
|
|
|
// Base
|
|
Actor::OnEnable();
|
|
}
|
|
|
|
void ModelInstanceActor::OnDisable()
|
|
{
|
|
// Base
|
|
Actor::OnDisable();
|
|
|
|
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey);
|
|
}
|