Files
UnrealEngine/Engine/Plugins/Animation/ControlRig/Source/ControlRigEditor/Private/ControlRigThumbnailRenderer.cpp
2025-05-18 13:04:45 +08:00

197 lines
6.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ControlRigThumbnailRenderer.h"
#include "Materials/Material.h"
#include "ThumbnailHelpers.h"
#include "Engine/StaticMesh.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/SkeletalMesh.h"
#include "Engine/Texture2D.h"
#include "TextureResource.h"
#include "Animation/SkeletalMeshActor.h"
#include "Components/SkeletalMeshComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "ControlRig.h"
#include "CanvasTypes.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(ControlRigThumbnailRenderer)
UControlRigThumbnailRenderer::UControlRigThumbnailRenderer(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
RigBlueprint = nullptr;
}
bool UControlRigThumbnailRenderer::CanVisualizeAsset(UObject* Object)
{
if (UControlRigBlueprint* InRigBlueprint = Cast<UControlRigBlueprint>(Object))
{
if(InRigBlueprint->GetRigModuleIcon())
{
return true;
}
USkeletalMesh* SkeletalMesh = InRigBlueprint->PreviewSkeletalMesh.Get();
int32 MissingMeshCount = 0;
for(const TSoftObjectPtr<UControlRigShapeLibrary>& ShapeLibrary : InRigBlueprint->ShapeLibraries)
{
if (ShapeLibrary.IsValid())
{
InRigBlueprint->Hierarchy->ForEach<FRigControlElement>([&](FRigControlElement* ControlElement) -> bool
{
if (const FControlRigShapeDefinition* ShapeDef = ShapeLibrary->GetShapeByName(ControlElement->Settings.ShapeName))
{
UStaticMesh* StaticMesh = ShapeDef->StaticMesh.Get();
if (StaticMesh == nullptr) // not yet loaded
{
MissingMeshCount++;
}
}
return true; // continue the iteration
});
}
}
return MissingMeshCount == 0;
}
return false;
}
void UControlRigThumbnailRenderer::Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, FRenderTarget* RenderTarget, FCanvas* Canvas, bool bAdditionalViewFamily)
{
RigBlueprint = nullptr;
if (UControlRigBlueprint* InRigBlueprint = Cast<UControlRigBlueprint>(Object))
{
if(UTexture2D* ModuleIcon = InRigBlueprint->GetRigModuleIcon())
{
Canvas->DrawTile(X, Y, Width, Height, 0, 0, 1, 1, FLinearColor::White, ModuleIcon->GetResource(), 1.f);
return;
}
UObject* ObjectToDraw = InRigBlueprint->PreviewSkeletalMesh.Get();
if(ObjectToDraw == nullptr)
{
ObjectToDraw = InRigBlueprint;
}
RigBlueprint = InRigBlueprint;
Super::Draw(ObjectToDraw, X, Y, Width, Height, RenderTarget, Canvas, bAdditionalViewFamily);
for (auto Pair : ShapeActors)
{
if (Pair.Value && Pair.Value->GetOuter())
{
Pair.Value->Rename(nullptr, GetTransientPackage());
Pair.Value->MarkAsGarbage();
}
}
ShapeActors.Reset();
}
}
void UControlRigThumbnailRenderer::AddAdditionalPreviewSceneContent(UObject* Object, UWorld* PreviewWorld)
{
TSharedRef<FSkeletalMeshThumbnailScene> ThumbnailScene = ThumbnailSceneCache.EnsureThumbnailScene(Object);
if (ThumbnailScene->GetPreviewActor() && RigBlueprint && !RigBlueprint->ShapeLibraries.IsEmpty() && RigBlueprint->GeneratedClass)
{
if(RigBlueprint->GetRigModuleIcon())
{
return;
}
UControlRig* ControlRig = nullptr;
// reuse the current control rig if possible
UControlRig* CDO = Cast<UControlRig>(RigBlueprint->GeneratedClass->GetDefaultObject(true /* create if needed */));
TArray<UObject*> ArchetypeInstances;
CDO->GetArchetypeInstances(ArchetypeInstances);
if (ArchetypeInstances.Num() > 0)
{
ControlRig = Cast<UControlRig>(ArchetypeInstances[0]);
}
if (ControlRig == nullptr)
{
// fall back to the CDO. we only need to pull out
// the pose of the default hierarchy so the CDO is fine.
// this case only happens if the editor had been closed
// and there are no archetype instances left.
ControlRig = CDO;
}
FTransform ComponentToWorld = ThumbnailScene->GetPreviewActor()->GetSkeletalMeshComponent()->GetComponentToWorld();
if (URigHierarchy* Hierarchy = ControlRig->GetHierarchy())
{
Hierarchy->ForEach<FRigControlElement>([&](FRigControlElement* ControlElement) -> bool
{
switch (ControlElement->Settings.ControlType)
{
case ERigControlType::Float:
case ERigControlType::ScaleFloat:
case ERigControlType::Integer:
case ERigControlType::Vector2D:
case ERigControlType::Position:
case ERigControlType::Scale:
case ERigControlType::Rotator:
case ERigControlType::Transform:
case ERigControlType::TransformNoScale:
case ERigControlType::EulerTransform:
{
if (const FControlRigShapeDefinition* ShapeDef = RigBlueprint->GetControlShapeByName(ControlElement->Settings.ShapeName))
{
UStaticMesh* StaticMesh = ShapeDef->StaticMesh.Get();
if (StaticMesh == nullptr) // not yet loaded
{
return true;
}
const FTransform ShapeGlobalTransform = ControlRig->GetHierarchy()->GetGlobalControlShapeTransform(ControlElement->GetKey());
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
SpawnInfo.bNoFail = true;
SpawnInfo.ObjectFlags = RF_Transient;
AStaticMeshActor* ShapeActor = PreviewWorld->SpawnActor<AStaticMeshActor>(SpawnInfo);
ShapeActor->SetActorEnableCollision(false);
if (!ShapeDef->Library.IsValid())
{
return true;
}
UMaterial* DefaultMaterial = ShapeDef->Library.Get()->DefaultMaterial.Get();
if (DefaultMaterial == nullptr) // not yet loaded
{
return true;
}
UMaterialInstanceDynamic* MaterialInstance = UMaterialInstanceDynamic::Create(DefaultMaterial, ShapeActor);
MaterialInstance->SetVectorParameterValue(ShapeDef->Library.Get()->MaterialColorParameter,FVector(ControlElement->Settings.ShapeColor));
UStaticMeshComponent* MeshComponent = ShapeActor->GetStaticMeshComponent();
for (int32 i=0; i<MeshComponent->GetNumMaterials(); ++i)
{
MeshComponent->SetMaterial(i, MaterialInstance);
}
ShapeActors.Add(ControlElement->GetFName(), ShapeActor);
ShapeActor->GetStaticMeshComponent()->SetStaticMesh(StaticMesh);
ShapeActor->SetActorTransform(ShapeDef->Transform * ShapeGlobalTransform);
}
break;
}
default:
{
break;
}
}
return true;
});
}
}
}