前言
最近因为项目需要打算做一个简易的插槽编辑器, 因为传统的插槽编辑都需要打开每个静态模型单独编辑, 操作相对比较麻烦, 那么首先需要创建一个自定义的预览试图, 本文先从这个开始
准备工作
首选创建一个插件, 类型随意, 如果先效率高一点简易选择 Editor Toolbar Button
, 这样就直接可以通过一个工具栏按钮启动插件
关于这个按钮, 我个人习惯还是把他放到工具栏最前面,也就是要重写默认模块文件RegisterMenus()
方法里的内容, 如下
1 2 3 4 5 6 7 8 9 10 11
| 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
模式的插件来创建一个窗口
1 2 3 4 5 6 7 8
| void FSimpleSocketEditorModule::MapActions() { PluginCommands = MakeShareable(new FUICommandList); PluginCommands->MapAction( FSimpleSocketEditorCommands::Get().PluginAction, FExecuteAction::CreateRaw(this, &FSimpleSocketEditorModule::PluginButtonClicked), FCanExecuteAction()); }
|
1 2 3 4
| void FSimpleSocketEditorModule::PluginButtonClicked() { FGlobalTabmanager::Get()->TryInvokeTab(SimpleSocketEditorTabName); }
|
1 2 3
| FGlobalTabmanager::Get()->RegisterNomadTabSpawner(SimpleSocketEditorTabName, FOnSpawnTab::CreateRaw(this, &FSimpleSocketEditorModule::OnSpawnPluginTab)) .SetDisplayName(LOCTEXT("SocketEditorTitil", "Socket Editor")) .SetMenuType(ETabSpawnerMenuType::Hidden);
|
1 2 3 4 5 6 7 8
| TSharedRef<SDockTab> FSimpleSocketEditorModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs) { return SNew(SDockTab) .TabRole(ETabRole::NomadTab) [ SNew(SSHud_SimpleSocket) ]; }
|
层层相关, 最后打开一个我们自定义的Slate
控件
其实一般情况会创建一个类似资源编辑器的类来作为编辑器视图类, 比如FStaticMeshEditor
, 或者如我之前文章创建自定义编辑器写的那种资源编辑器, 但是这里我们就任性一次, 用Slate
的方式硬怼出来一个编辑器
视图类
然后就是视图相关的类了, 这里有好几个类可以扩展, 虽然都不是必须的, 我们先从最主要的类开始扩展,这个继承自SEditorViewport
的类, 他就是我们视图界面的Slate
类
1 2
| class SEditorViewport_SimpleSocket : public SEditorViewport, public FGCObject, public ICommonEditorViewportToolbarInfoProvider {
|
我们又额外继承了FGCObject
(用于GC管理), ICommonEditorViewportToolbarInfoProvider
(界面扩展)
接下来重写几个重要函数
1 2 3
| virtual void OnFocusViewportToSelection()override; virtual TSharedRef<FEditorViewportClient> MakeEditorViewportClient() override; virtual TSharedPtr<SWidget> MakeViewportToolbar()override;
|
如果想简单的看到视图效果, 我们可以大致像下面一样实现
1 2 3 4 5 6 7
| TSharedRef<FEditorViewportClient> SEditorViewport_SimpleSocket::MakeEditorViewportClient() { FPreviewScene PreviewScene = MakeShareable(new FPreviewScene()); EditorViewportClient = MakeShareable(new FEditorViewportClient(nullptr, PreviewScene)); return EditorViewportClient.ToSharedRef(); }
|
里面有两个类我们使用了默认类型, 分别是FPreviewScene
和FEditorViewportClient
同样的,工具栏也使用默认类型实现即可
1 2 3 4
| TSharedPtr<SWidget> SEditorViewport_SimpleSocket::MakeViewportToolbar() { return SNew(SCommonEditorViewportToolbarBase, SharedThis(this)); }
|
但是这样场景中是黑漆漆一片, 没有任何物体
所以我们需要对PreviewScene
对象添加物体
1 2 3
| 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
该对象内有很多参数可以设置, 比如我们可以这样使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| TSharedPtr<class FAdvancedPreviewScene> AdvancedScene;
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);
|
这样就能完成指定图片那种光照效果了