Files
UnrealEngine/Engine/Source/Runtime/MovieSceneTracks/Private/Systems/MovieSceneComponentMaterialSystem.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

252 lines
8.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Systems/MovieSceneComponentMaterialSystem.h"
#include "Evaluation/PreAnimatedState/MovieScenePreAnimatedStorageID.inl"
#include "EntitySystem/MovieSceneEntityMutations.h"
#include "Evaluation/PreAnimatedState/MovieScenePreAnimatedStorageID.inl"
#include "Systems/FloatChannelEvaluatorSystem.h"
#include "Systems/MovieSceneHierarchicalBiasSystem.h"
#include "Systems/MovieScenePiecewiseDoubleBlenderSystem.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Tracks/MovieSceneMaterialTrack.h"
#include "Components/PrimitiveComponent.h"
#include "Components/DecalComponent.h"
#include "Components/MeshComponent.h"
#include "Components/VolumetricCloudComponent.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(MovieSceneComponentMaterialSystem)
namespace UE::MovieScene
{
FComponentMaterialAccessor::FComponentMaterialAccessor(const FComponentMaterialKey& InKey)
: Object(InKey.Object.ResolveObjectPtr())
, MaterialInfo(InKey.MaterialInfo)
{}
FComponentMaterialAccessor::FComponentMaterialAccessor(UObject* InObject, const FComponentMaterialInfo& InMaterialInfo)
: Object(InObject)
, MaterialInfo(InMaterialInfo)
{}
FComponentMaterialAccessor::operator bool() const
{
return Object != nullptr;
}
FString FComponentMaterialAccessor::ToString() const
{
return FString::Printf(TEXT("object %s (material info: %s)"), *Object->GetPathName(), *MaterialInfo.ToString());
}
UMaterialInterface* FComponentMaterialAccessor::GetMaterial() const
{
switch (MaterialInfo.MaterialType)
{
case EComponentMaterialType::Empty:
break;
case EComponentMaterialType::IndexedMaterial:
if (UPrimitiveComponent* Component = Cast<UPrimitiveComponent>(Object))
{
UMaterialInterface* Material = nullptr;
if (!MaterialInfo.MaterialSlotName.IsNone())
{
Material = Component->GetMaterialByName(MaterialInfo.MaterialSlotName);
}
if (!Material)
{
Material = Component->GetMaterial(MaterialInfo.MaterialSlotIndex);
}
return Material;
}
break;
case EComponentMaterialType::OverlayMaterial:
if (UMeshComponent* Component = Cast<UMeshComponent>(Object))
{
return Component->GetOverlayMaterial();
}
break;
case EComponentMaterialType::DecalMaterial:
if (UDecalComponent* DecalComponent = Cast<UDecalComponent>(Object))
{
return DecalComponent->GetDecalMaterial();
}
break;
case EComponentMaterialType::VolumetricCloudMaterial:
if (UVolumetricCloudComponent* CloudComponent = Cast<UVolumetricCloudComponent>(Object))
{
return CloudComponent->GetMaterial();
}
break;
default:
break;
}
return nullptr;
}
void FComponentMaterialAccessor::SetMaterial(UMaterialInterface* InMaterial) const
{
switch (MaterialInfo.MaterialType)
{
case EComponentMaterialType::Empty:
break;
case EComponentMaterialType::IndexedMaterial:
if (UPrimitiveComponent* Component = Cast<UPrimitiveComponent>(Object))
{
TArray<FName> MaterialSlots = Component->GetMaterialSlotNames();
if (!MaterialInfo.MaterialSlotName.IsNone() && MaterialSlots.Contains(MaterialInfo.MaterialSlotName))
{
Component->SetMaterialByName(MaterialInfo.MaterialSlotName, InMaterial);
}
else
{
Component->SetMaterial(MaterialInfo.MaterialSlotIndex, InMaterial);
}
}
break;
case EComponentMaterialType::OverlayMaterial:
if (UMeshComponent* Component = Cast<UMeshComponent>(Object))
{
Component->SetOverlayMaterial(InMaterial);
}
break;
case EComponentMaterialType::DecalMaterial:
if (UDecalComponent* DecalComponent = Cast<UDecalComponent>(Object))
{
DecalComponent->SetDecalMaterial(InMaterial);
}
break;
case EComponentMaterialType::VolumetricCloudMaterial:
if (UVolumetricCloudComponent* CloudComponent = Cast<UVolumetricCloudComponent>(Object))
{
CloudComponent->SetMaterial(InMaterial);
}
break;
default:
break;
}
}
UMaterialInstanceDynamic* FComponentMaterialAccessor::CreateDynamicMaterial(UMaterialInterface* InMaterial)
{
auto MakeDynamicMaterial = [this, InMaterial]()
{
TStringBuilder<128> DynamicName;
InMaterial->GetFName().ToString(DynamicName);
DynamicName.Append(TEXT("_Animated"));
FName UniqueDynamicName = MakeUniqueObjectName(Object, UMaterialInstanceDynamic::StaticClass(), DynamicName.ToString());
return UMaterialInstanceDynamic::Create(InMaterial, Object, UniqueDynamicName);
};
// Need to create a new MID, either because the parent has changed, or because one doesn't already exist
switch (MaterialInfo.MaterialType)
{
case EComponentMaterialType::Empty:
break;
case EComponentMaterialType::IndexedMaterial:
if (UPrimitiveComponent* Component = Cast<UPrimitiveComponent>(Object))
{
TArray<FName> MaterialSlots = Component->GetMaterialSlotNames();
UMaterialInstanceDynamic* Result = MakeDynamicMaterial();
if (!MaterialInfo.MaterialSlotName.IsNone() && MaterialSlots.Contains(MaterialInfo.MaterialSlotName))
{
Component->SetMaterialByName(MaterialInfo.MaterialSlotName, Result);
}
else
{
Component->SetMaterial(MaterialInfo.MaterialSlotIndex, Result);
}
return Result;
}
break;
case EComponentMaterialType::OverlayMaterial:
if (UMeshComponent* Component = Cast<UMeshComponent>(Object))
{
UMaterialInstanceDynamic* Result = MakeDynamicMaterial();
Component->SetOverlayMaterial(Result);
return Result;
}
break;
case EComponentMaterialType::DecalMaterial:
if (UDecalComponent* DecalComponent = Cast<UDecalComponent>(Object))
{
return DecalComponent->CreateDynamicMaterialInstance();
}
break;
case EComponentMaterialType::VolumetricCloudMaterial:
if (UVolumetricCloudComponent* CloudComponent = Cast<UVolumetricCloudComponent>(Object))
{
UMaterialInstanceDynamic* Result = MakeDynamicMaterial();
CloudComponent->SetMaterial(Result);
return Result;
}
break;
default:
break;
}
return nullptr;
}
TAutoRegisterPreAnimatedStorageID<FPreAnimatedComponentMaterialSwitcherStorage> FPreAnimatedComponentMaterialSwitcherStorage::StorageID;
TAutoRegisterPreAnimatedStorageID<FPreAnimatedComponentMaterialParameterStorage> FPreAnimatedComponentMaterialParameterStorage::StorageID;
} // namespace UE::MovieScene
UMovieSceneComponentMaterialSystem::UMovieSceneComponentMaterialSystem(const FObjectInitializer& ObjInit)
: Super(ObjInit)
{
using namespace UE::MovieScene;
FBuiltInComponentTypes* BuiltInComponents = FBuiltInComponentTypes::Get();
FMovieSceneTracksComponentTypes* TracksComponents = FMovieSceneTracksComponentTypes::Get();
RelevantComponent = TracksComponents->ComponentMaterialInfo;
Phase = ESystemPhase::Instantiation;
if (HasAnyFlags(RF_ClassDefaultObject))
{
DefineComponentConsumer(GetClass(), BuiltInComponents->ObjectResult);
DefineComponentConsumer(GetClass(), BuiltInComponents->BoundObject);
DefineComponentProducer(GetClass(), TracksComponents->BoundMaterial);
DefineImplicitPrerequisite(UMovieSceneCachePreAnimatedStateSystem::StaticClass(), GetClass());
DefineImplicitPrerequisite(UMovieSceneHierarchicalBiasSystem::StaticClass(), GetClass());
}
}
void UMovieSceneComponentMaterialSystem::OnLink()
{
using namespace UE::MovieScene;
SystemImpl.MaterialSwitcherStorage = Linker->PreAnimatedState.GetOrCreateStorage<FPreAnimatedComponentMaterialSwitcherStorage>();
SystemImpl.MaterialParameterStorage = Linker->PreAnimatedState.GetOrCreateStorage<FPreAnimatedComponentMaterialParameterStorage>();
SystemImpl.OnLink(Linker, FBuiltInComponentTypes::Get()->BoundObject, FMovieSceneTracksComponentTypes::Get()->ComponentMaterialInfo);
}
void UMovieSceneComponentMaterialSystem::OnUnlink()
{
SystemImpl.OnUnlink(Linker);
}
void UMovieSceneComponentMaterialSystem::OnRun(FSystemTaskPrerequisites& InPrerequisites, FSystemSubsequentTasks& Subsequents)
{
using namespace UE::MovieScene;
SystemImpl.OnRun(Linker, FBuiltInComponentTypes::Get()->BoundObject, FMovieSceneTracksComponentTypes::Get()->ComponentMaterialInfo, InPrerequisites, Subsequents);
}
void UMovieSceneComponentMaterialSystem::SavePreAnimatedState(const FPreAnimationParameters& InParameters)
{
using namespace UE::MovieScene;
SystemImpl.SavePreAnimatedState(Linker, FBuiltInComponentTypes::Get()->BoundObject, FMovieSceneTracksComponentTypes::Get()->ComponentMaterialInfo, InParameters);
}