- Published on
编辑器扩展:自定义预览试图
- Authors

- Name
- 东哥
前言

最近因为项目需要打算做一个简易的插槽编辑器, 因为传统的插槽编辑都需要打开每个静态模型单独编辑, 操作相对比较麻烦, 那么首先需要创建一个自定义的预览试图, 本文先从这个开始
准备工作
首选创建一个插件, 类型随意, 如果先效率高一点简易选择 Editor Toolbar Button, 这样就直接可以通过一个工具栏按钮启动插件
关于这个按钮, 我个人习惯还是把他放到工具栏最前面,也就是要重写默认模块文件RegisterMenus()方法里的内容, 如下
//工具栏
`TSharedPtr<FExtender>` ToolBarExtender = MakeShareable(new FExtender());
ToolBarExtender->AddToolBarExtension("File",
EExtensionHook::Before, PluginCommands, FToolBarExtensionDelegate::CreateLambda(
[this](FToolBarBuilder& Builder)
{
Builder.AddToolBarButton(FSimpleSocketEditorCommands::Get().PluginAction);
}
));
LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolBarExtender);
这样就把按钮放到了File类型的前面, 即最靠前的地方

编辑器创建
这样默认点击插件按钮出来的就是一个消息窗口, 我们需要参考Standeralone模式的插件来创建一个窗口
void FSimpleSocketEditorModule::MapActions()
{
PluginCommands = MakeShareable(new FUICommandList);
PluginCommands->MapAction(
FSimpleSocketEditorCommands::Get().PluginAction,
FExecuteAction::CreateRaw(this, &FSimpleSocketEditorModule::PluginButtonClicked),
FCanExecuteAction());
}
void FSimpleSocketEditorModule::PluginButtonClicked()
{
FGlobalTabmanager::Get()->TryInvokeTab(SimpleSocketEditorTabName);
}
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(SimpleSocketEditorTabName, FOnSpawnTab::CreateRaw(this, &FSimpleSocketEditorModule::OnSpawnPluginTab))
.SetDisplayName(LOCTEXT("SocketEditorTitil", "Socket Editor"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
`TSharedRef<SDockTab>` FSimpleSocketEditorModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
[
SNew(SSHud_SimpleSocket)
];
}
层层相关, 最后打开一个我们自定义的Slate控件
其实一般情况会创建一个类似资源编辑器的类来作为编辑器视图类, 比如
FStaticMeshEditor, 或者如我之前文章创建自定义编辑器写的那种资源编辑器, 但是这里我们就任性一次, 用Slate的方式硬怼出来一个编辑器
视图类
然后就是视图相关的类了, 这里有好几个类可以扩展, 虽然都不是必须的, 我们先从最主要的类开始扩展,这个继承自SEditorViewport的类, 他就是我们视图界面的Slate类
class SEditorViewport_SimpleSocket : public SEditorViewport, public FGCObject, public ICommonEditorViewportToolbarInfoProvider
{//.....}
我们又额外继承了FGCObject(用于GC管理), ICommonEditorViewportToolbarInfoProvider(界面扩展)
接下来重写几个重要函数
virtual void OnFocusViewportToSelection()override;//按键F的实现, 就是聚焦的逻辑
virtual `TSharedRef<FEditorViewportClient>` MakeEditorViewportClient() override;//界面视图UI的
virtual `TSharedPtr<SWidget>` MakeViewportToolbar()override;//工具栏UI
如果想简单的看到视图效果, 我们可以大致像下面一样实现
`TSharedRef<FEditorViewportClient>` SEditorViewport_SimpleSocket::MakeEditorViewportClient()
{
FPreviewScene PreviewScene = MakeShareable(new FPreviewScene());
EditorViewportClient = MakeShareable(new FEditorViewportClient(nullptr, PreviewScene));
return EditorViewportClient.ToSharedRef();
}
里面有两个类我们使用了默认类型, 分别是FPreviewScene和FEditorViewportClient
同样的,工具栏也使用默认类型实现即可
`TSharedPtr<SWidget>` SEditorViewport_SimpleSocket::MakeViewportToolbar()
{
return SNew(SCommonEditorViewportToolbarBase, SharedThis(this));
}
但是这样场景中是黑漆漆一片, 没有任何物体
所以我们需要对PreviewScene对象添加物体
UStaticMesh* mesh = `LoadObject<UStaticMesh>`(NULL, TEXT("StaticMesh'/Engine/EngineMeshes/Cube.Cube'"), NULL, LOAD_None, NULL);;
FTransform Transform = FTransform::Identity;
PreviewScene->AddComponent(PreviewMeshComp, Transform);
这样PreviewScene内就有了一个默认的Cube物体了
FAdvancedPreviewScene
至此场景里虽然能对物体进行光照, 但是还是黑漆漆的, 引擎给了我们一个高级的场景类, 多数的预览试图也是用的该类, 即FAdvancedPreviewScene
该对象内有很多参数可以设置, 比如我们可以这样使用
//.h
`TSharedPtr<class FAdvancedPreviewScene>` AdvancedScene;
//.cpp
FAdvancedPreviewScene::ConstructionValues ConstructValues; //预览场景参数
ConstructValues.SetCreatePhysicsScene(false); //关闭物理场景
ConstructValues.ShouldSimulatePhysics(false); //关闭物理模拟
ConstructValues.LightBrightness = 3; //设置光照强度
ConstructValues.SkyBrightness = 1; //设置天空光强度
ConstructValues.bEditor = true;
AdvancedScene = MakeShareable(new FAdvancedPreviewScene(ConstructValues));
//添加天空光组件
USkyLightComponent* Skylight = `NewObject<USkyLightComponent>`();
AdvancedScene->AddComponent(Skylight, FTransform::Identity);
//设置地面
AdvancedScene->SetFloorVisibility(false); //显示地面,默认就是显示
AdvancedScene->SetFloorOffset(100.f); //设置地面高度偏移,正数是往下偏移
//设置方向光
AdvancedScene->DirectionalLight->SetMobility(EComponentMobility::Movable);
AdvancedScene->DirectionalLight->CastShadows = true; //启用阴影
AdvancedScene->DirectionalLight->CastStaticShadows = true;
AdvancedScene->DirectionalLight->CastDynamicShadows = true;
AdvancedScene->DirectionalLight->SetIntensity(3);
这样就能完成指定图片那种光照效果了