一、新建空白插件

在Bulid.cs内加入两个模块,"EditorSubsystem","UnrealEd",
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"EditorSubsystem",
"UnrealEd",
// ... add other public dependencies that you statically link with here ...
}
);
创建继承于EditorSubsystenm的子类

?
点创建后会报错,没关系回C++重新编译一下就好

二、C++代码
ExportSixViewsSub.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EditorSubsystem.h"
#include "ExportSixViewsSub.generated.h"
class USpringArmComponent;
/**
*
*/
UCLASS()
class EXPORTSIXVIEWS_API UExportSixViewsSub : public UEditorSubsystem
{
GENERATED_BODY()
public:
//获取World
UFUNCTION(BlueprintPure, Category = "FunTool")
UWorld* GetContextWorld();
//遍历指定路径下所有的StaticMesh
UFUNCTION(BlueprintCallable, Category = "FunTool")
TArray<UStaticMesh*> FindOrLoadAssetsByPath(const FString& FilePath);
//将Actor的Privot设置为Center
UFUNCTION(BlueprintCallable, Category = "FunTool")
bool SetActorPrivotOnCenter(AActor* InActor, bool bWorldSpace /*= false*/, FVector& CenterLocation);
//拍摄模型六视图并保存到指定文件夹
UFUNCTION(BlueprintCallable, Category = "FunTool")
bool SaveRenderTargetToFile(UTextureRenderTarget2D* rt, const FString& Filepath);
//复制指定文件到指定目录
UFUNCTION(BlueprintCallable, Category = "FunTool")
void CopyFile(UStaticMesh* SM, const FString& Filepath);
//导出完成时的消息提示框
UFUNCTION(BlueprintCallable, Category = "FunTool")
void Tips();
//打开文件管理器并返回选择的文件的目录
UFUNCTION(BlueprintCallable, Category = "FunTool")
void OpenFiles(FString& DirectoryName);
};
ExportSixViewsSub.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ExportSixViewsSub.h"
#include "EngineUtils.h"
#include "UnrealEdGlobals.h"
#include "Editor/UnrealEdEngine.h"
#include "Engine/TextureRenderTarget2D.h"
#include "Misc/FileHelper.h"
#include "ImageUtils.h"
#include "GameFramework/SpringArmComponent.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Developer/DesktopPlatform/Public/IDesktopPlatform.h"
#include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h"
UWorld* UExportSixViewsSub::GetContextWorld()
{
UWorld* World = GEditor->GetEditorWorldContext().World();
return World;
}
TArray<UStaticMesh*> UExportSixViewsSub::FindOrLoadAssetsByPath(const FString& FilePath)
{
TArray<UObject*> OutAssets;
TArray<UStaticMesh*> OutStaticMeshs;
FString GamePath = FilePath;
GamePath.ReplaceInline(*FPaths::ProjectContentDir(), TEXT("/Game/"));
if (!GamePath.IsEmpty())
{
EngineUtils::FindOrLoadAssetsByPath(GamePath, OutAssets, EngineUtils::ATL_Regular);
for (auto SM : OutAssets)
{
UStaticMesh* TempSM = Cast<UStaticMesh>(SM);
if (TempSM)
{
OutStaticMeshs.Add(TempSM);
}
}
UE_LOG(LogTemp, Warning, TEXT("FilePaths: Directory Exists"));
return OutStaticMeshs;
}
else
{
UE_LOG(LogTemp, Warning, TEXT("FilePaths: Directory Does not exist"));
return OutStaticMeshs;
}
}
bool UExportSixViewsSub::SetActorPrivotOnCenter(AActor* InActor, bool bWorldSpace /*= false*/, FVector& CenterLocation)
{
if (InActor)
{
FVector PivotOffset = InActor->GetComponentsBoundingBox().GetCenter();
if (bWorldSpace)
{
FVector Delta(PivotOffset - InActor->GetActorLocation());
PivotOffset = InActor->GetTransform().InverseTransformVector(Delta);
}
if (InActor->GetPivotOffset() == PivotOffset)
{
CenterLocation = InActor->GetActorLocation();
return false;
}
else
{
InActor->Modify();
InActor->SetPivotOffset(PivotOffset);
GUnrealEd->SetPivotMovedIndependently(false);
InActor->PostEditMove(/*bFinished=*/ true);
CenterLocation = InActor->GetActorLocation() + PivotOffset;
return true;
}
}
return false;
}
bool UExportSixViewsSub::SaveRenderTargetToFile(UTextureRenderTarget2D* rt, const FString& fileDestination)
{
FTextureRenderTargetResource* rtResource = rt->GameThread_GetRenderTargetResource();
FReadSurfaceDataFlags readPixelFlags(RCM_UNorm);
TArray<FColor> outBMP;
for (FColor& color : outBMP)
{
color.A = 255;
}
outBMP.AddUninitialized(rt->GetSurfaceWidth() * rt->GetSurfaceHeight());
rtResource->ReadPixels(outBMP, readPixelFlags);
FIntPoint destSize(rt->GetSurfaceWidth(), rt->GetSurfaceHeight());
TArray<uint8> CompressedBitmap;
FImageUtils::CompressImageArray(destSize.X, destSize.Y, outBMP, CompressedBitmap);
bool imageSavedOk = FFileHelper::SaveArrayToFile(CompressedBitmap, *fileDestination);
return imageSavedOk;
}
void UExportSixViewsSub::CopyFile(UStaticMesh* SM, const FString& FilePath)
{
FString SM_AbsolutePath = UKismetSystemLibrary::GetSystemPath(SM);
FString FileDestination = FilePath;
FileDestination.Append("/" + SM->GetFName().ToString() + ".uasset");
IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
if (FileManager.CreateDirectory(*FilePath))
{
UE_LOG(LogTemp, Warning, TEXT("FilePaths: Directory was created"));
}
else
{
UE_LOG(LogTemp, Warning, TEXT("FilePaths: Directory was not created"));
}
if (FileManager.CopyFile(*FileDestination, *SM_AbsolutePath))
{
UE_LOG(LogTemp, Warning, TEXT("FilePaths: File Copied!"));
}
else
{
UE_LOG(LogTemp, Warning, TEXT("FilePaths: File not Copied!"));
}
}
void UExportSixViewsSub::Tips()
{
FText const Title = FText::FromString("Message");
FText const DialogText = FText::FromString("Export complete!");
EAppReturnType::Type const ReturnType = FMessageDialog::Open(EAppMsgType::Ok, DialogText, &Title);
}
void UExportSixViewsSub::OpenFiles(FString& DirectoryName)
{
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
DesktopPlatform->OpenDirectoryDialog(nullptr, TEXT("ProjectDir"), FPaths::ConvertRelativePathToFull(FPaths::ProjectDir()), DirectoryName);
}
?三、蓝图代码
?
1.新建Actor蓝图,就只添加一个StaticMeshComponent用于测试用

?2.新建相机蓝图,添加一个相机臂和SceneCaptureComponent2D,相机臂取消碰撞,设置CaptureSource默认值


?3.新建结构体和创建表格


?4.新建编辑器UI
设计界面:

?逻辑界面:
自定义事件:拷贝模型资源文件到指定文件夹

自定义事件:将图片保存到指定文件夹

销毁Actor的函数

?Button Pressed事件 选择文件夹


?Button Pressed事件 导出图片



?四、测试

?


?五、插件下载(4.27)
链接:https://pan.baidu.com/s/1q7uYrQ41xaY1mIR0ZuQGmA?pwd=rx5y? 提取码:rx5y
|