开发中经常会遇到编辑器环境中制作工具拖拽控制柄编辑内容的需求,此时可以通过Editor事件拿到对应回调,进行相应更新:
1.创建Mesh编辑Actor类
创建一个Mesh编辑Actor类,提供Mesh顶点编辑的相关逻辑。
.h:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ProceduralMeshComponent.h"
#include "DraggableHandleActor.h"
#include "CustomMeshActor.generated.h"
UCLASS()
class MYPROJECT6_API ACustomMeshActor : public AActor
{
GENERATED_BODY()
public:
ACustomMeshActor();
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UProceduralMeshComponent* MeshComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ADraggableHandleActor* HandleP0;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ADraggableHandleActor* HandleP1;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ADraggableHandleActor* HandleP2;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ADraggableHandleActor* HandleP3;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void OnRebuild();
UFUNCTION()
void OnHandleP0Moved();
UFUNCTION()
void OnHandleP1Moved();
UFUNCTION()
void OnHandleP2Moved();
UFUNCTION()
void OnHandleP3Moved();
};
.cpp:
#include "CustomMeshActor.h"
ACustomMeshActor::ACustomMeshActor()
{
PrimaryActorTick.bCanEverTick = true;
MeshComponent = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("ProceduralMesh"));
RootComponent = MeshComponent;
}
void ACustomMeshActor::BeginPlay()
{
Super::BeginPlay();
HandleP0->OnHandleMoved.AddDynamic(this, &ACustomMeshActor::OnHandleP0Moved);
HandleP1->OnHandleMoved.AddDynamic(this, &ACustomMeshActor::OnHandleP1Moved);
HandleP2->OnHandleMoved.AddDynamic(this, &ACustomMeshActor::OnHandleP2Moved);
HandleP3->OnHandleMoved.AddDynamic(this, &ACustomMeshActor::OnHandleP3Moved);
this->OnRebuild();
}
void ACustomMeshActor::OnRebuild()
{
TArray<FVector> Vertices;
FTransform ActorTransform = GetActorTransform();
Vertices.Add(HandleP0->GetActorLocation());
Vertices.Add(HandleP1->GetActorLocation());
Vertices.Add(HandleP2->GetActorLocation());
Vertices.Add(HandleP3->GetActorLocation());
TArray<int32> Triangles;
Triangles.Add(0);
Triangles.Add(1);
Triangles.Add(2);
Triangles.Add(0);
Triangles.Add(2);
Triangles.Add(3);
// 定义 UV 坐标
TArray<FVector2D> UV0;
UV0.Add(FVector2D(0.0f, 0.0f));
UV0.Add(FVector2D(0.0f, 1.0f));
UV0.Add(FVector2D(1.0f, 1.0f));
UV0.Add(FVector2D(1.0f, 0.0f));
// 法线
TArray<FVector> Normals;
Normals.Add(FVector(0.0f, 0.0f, 1.0f));
Normals.Add(FVector(0.0f, 0.0f, 1.0f));
Normals.Add(FVector(0.0f, 0.0f, 1.0f));
Normals.Add(FVector(0.0f, 0.0f, 1.0f));
// 切线
TArray<FProcMeshTangent> Tangents;
Tangents.Add(FProcMeshTangent(1.0f, 0.0f, 0.0f));
Tangents.Add(FProcMeshTangent(1.0f, 0.0f, 0.0f));
Tangents.Add(FProcMeshTangent(1.0f, 0.0f, 0.0f));
Tangents.Add(FProcMeshTangent(1.0f, 0.0f, 0.0f));
TArray<FColor> VertexColors;
VertexColors.Add(FLinearColor::White.ToFColor(true));
VertexColors.Add(FLinearColor::White.ToFColor(true));
VertexColors.Add(FLinearColor::White.ToFColor(true));
VertexColors.Add(FLinearColor::White.ToFColor(true));
MeshComponent->ClearAllMeshSections();
MeshComponent->CreateMeshSection(0, Vertices, Triangles, Normals, UV0, VertexColors, Tangents, true);
}
void ACustomMeshActor::OnHandleP0Moved()
{
OnRebuild();
}
void ACustomMeshActor::OnHandleP1Moved()
{
OnRebuild();
}
void ACustomMeshActor::OnHandleP2Moved()
{
OnRebuild();
}
void ACustomMeshActor::OnHandleP3Moved()
{
OnRebuild();
}
这部分代码通过UE的ProceduralMeshComponent动态创建顶点和Mesh。
2.创建操作柄
第二步需要实现拖拽操作柄或者修改界面数值得到回调,从而更新Mesh,在UE中这一块的编辑器回调有如下:
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; //UE面板修改数值
virtual void PostEditMove(bool bFinished) override; //UE界面拖拽Actor
接下来编写Actor - DraggableHandleActor来实现这样的逻辑:
.h
#pragma once
#include "CoreMinimal.h"
#include "DraggableHandleActor.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHandleMoved);
UCLASS()
class MYPROJECT6_API ADraggableHandleActor : public AActor
{
GENERATED_BODY()
public:
ADraggableHandleActor();
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
virtual void PostEditMove(bool bFinished) override;
#endif
// Delegate for handle moved callback
UPROPERTY(BlueprintAssignable, Category = "Handle Events")
FOnHandleMoved OnHandleMoved; // Delegate for broadcasting the movement
};
.cpp:
#include "DraggableHandleActor.h"
ADraggableHandleActor::ADraggableHandleActor()
{
}
#if WITH_EDITOR
void ADraggableHandleActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
OnHandleMoved.Broadcast();
}
void ADraggableHandleActor::PostEditMove(bool bFinished)
{
Super::PostEditMove(bFinished);
OnHandleMoved.Broadcast();
}
#endif
注意这里定义了一个委托来给外部绑定回调:
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHandleMoved);
3.UE整合
最后在UE中绑定控制柄对应的Actor,并放置进对应的UMG或者Editor触发代码中即可。最后再记录顶点操作位置,再在运行时还原,即可实现这样的编辑器下顶点修改编辑需求。