落败的青春阳落s 发表于 2020-12-3 07:24

Unreal Sequencer 菜单工具栏嵌入

本文章转载自 智伤帝的个人博客 - 原文链接

前言

关于菜单搭建,我之前就写过一篇文章关于如何使用 Python 搭建 Unreal 主界面的菜单。
但是倘若要实现更为复杂的效果,比如在 Sequencer 的右键菜单上扩展,或者添加工具栏。
要实现这样的功能 Python 就无能为力了。
既然要用 C++ 实现,就必须要推荐一下官方提供的扩展教程。 B站链接 Youtube链接 github链接
教程稍微有点老了,是 2015 年的,不过我把 Github 的代码拉下来,稍微修复一些编译的小问题,基本上是可用的。
作为引擎扩展是绝佳的参考,另外最近逛论坛的时候还发现了一个不错 Python Editor 扩展插件。
在 Unreal 里面实现 Maya 工具栏的效果,也是引擎扩展非常好的参考。 论坛地址 github地址
不过 Python Editor 在 4.25 引擎下编译会出现大量错误,头文件的索引很多都不可用,还有一些代码的小问题。
所以我把这些杂七杂八的错误全部修复了,参见我 Fork 的仓库。 github地址
时间不足,有空要好好研究一下这个插件,做得非常好。
这个需求和我上次研究的 Unreal 自定义快捷键拓展中诸多相似的地方,可以结合到一起看 链接
Sequencer 菜单扩展

虚幻是开源的,所以即使再不济,也可以在源码上进行修改。
但是改动引擎是非常不好的操作,说明架构设计上扩展性不足,堂堂虚幻引擎怎么会沦落到这种地步。
所以在官方论坛上搜索一下,可以看到官方工作人员给出了一些使用提示 链接
官方的回答有提到大部分 Slate 都预留了 FExtender 来进行菜单的扩展,不需要修改源代码。
可以通过 C++ 插件来实现,并且插件实现可以迁移到不同项目的引擎,相比之下更友好。
到这一步可以去查 Unreal 的 C++ API 文档,看看 Sequencer 的 API 有没有提供相关的方法。
通常优先查 I 开头的类,因为这种类属于接口,将内部函数转换到外部使用的。
所以可以在 ISequencerModule 里面找到目标。
这个函数获取到 FExtensibilityManager 基本上就和上次扩展快捷键一样。
需要定制一个 UI_COMMAND 然后通过 AddExtender 将 UI_COMMAND 定义的命令添加进去。
同时 FExtender 构建参数里面 FMenuExtensionDelegate 中定义菜单嵌入的生成代码。
// NOTE 获取 SequencerModule 以及 FExtensibilityManager
ISequencerModule &SequencerModule = FModuleManager::Get().LoadModuleChecked<ISequencerModule>("Sequencer");   
TSharedPtr<FExtensibilityManager> Manager = SequencerModule.GetObjectBindingContextMenuExtensibilityManager();   

struct Callback
{
static void ExportCurve()
{
    // NOTE 点击触发执行的函数,这里我通常是定义调用特定路径的 Python 脚本
    FString Script = "py \" xxx \"";
    GEngine->Exec(NULL, Script.GetCharArray().GetData());   
}

static void ExtendMenu(FMenuBuilder &MenuBuilder)
{
    // NOTE 设置 Section
    MenuBuilder.BeginSection("FXCurve", LOCTEXT("FXCurve", "FXCurve"));
    {
      // NOTE 设置点击菜单栏
      MenuBuilder.AddMenuEntry(
      LOCTEXT("ExportCurve", "Export Curve"),
      LOCTEXT("ExportCurveTooltip", "Export Curve to FX Blueprint"),
      FSlateIcon(),
      // NOTE 设置点击触发的函数
      FExecuteAction::CreateStatic(&ExportCurve)
      );
    }
    MenuBuilder.EndSection();
}
};

// NOTE 获取 SequencerModule 以及 FExtensibilityManager
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender);   
MenuExtender->AddMenuExtension(   
TEXT("Spawnable"),
EExtensionHook::Before,
TSharedPtr<FUICommandList>(),   
FMenuExtensionDelegate::CreateStatic(&Callback::ExtendMenu));
Manager->AddExtender(MenuExtender);   

上面的代码可以在 Sequencer 的 binding 菜单上嵌入 Entry 。
嵌入的 Spawnable 位置是怎么填写的呢?
其实看了官方的引擎扩展教程就可以知道怎么操作 ~
需要在引擎的配置面板上开启显示。
需要在引擎的配置面板上勾选显示。
然后重开引擎。(不重开 动态菜单也可以更新,不过 Toolbar 之类的就不行)
这样就可以看到菜单背后的代码标记了。
方便定位菜单的嵌入。
工具栏嵌入

其实有了菜单功能的嵌入,工具栏嵌入也是大同小异而已。
不逼逼,直接上代码。
ISequencerModule &SequencerModule = FModuleManager::Get().LoadModuleChecked<ISequencerModule>("Sequencer");   
TSharedPtr<FExtensibilityManager> Manager = SequencerModule.GetToolBarExtensibilityManager();   

struct Callback
{
static void ExportCurve()
{
    FString Script = "py \" xxx \"";
    GEngine->Exec(NULL, Script.GetCharArray().GetData());   
}

static void ExtendToolBar(FToolBarBuilder &ToolBarBuilder)
{

    ToolBarBuilder.BeginSection("Keys");
    {
      ToolBarBuilder.AddToolBarButton(
      FPyCommandList::Get().ExportSelectedKeys,
      NAME_None,
      TAttribute<FText>(),   
      TAttribute<FText>(),   
      FSlateIcon(FEditorStyle::GetStyleSetName(), "Matinee.ToggleCurveEditor")
      );
    }
    ToolBarBuilder.EndSection();
    ToolBarBuilder.AddSeparator();
}
};

TSharedRef<FUICommandList> CommandList = MakeShareable(new FUICommandList);   
CommandList->MapAction(   
FPyCommandList::Get().ExportSelectedKeys,
FExecuteAction::CreateStatic(&Callback::ExportCurve)
);

TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender);   
MenuExtender->AddToolBarExtension(   
TEXT("Curve Editor"),
EExtensionHook::After,
CommandList,
FToolBarExtensionDelegate::CreateStatic(&Callback::ExtendToolBar));
Manager->AddExtender(MenuExtender);   

Toolbar 多了一个操作,需要创建一个 UI_COMMAND
然后通过 CommandList 来映射执行的回调函数。
这里我直接用了 Unreal 内置的图标,具体的名称可以参考引擎源码 SlateEditorStyle.cpp 里面的定义。
总结

可惜目前 Python 还没有暴露出相关的 UObject 类型来调用。
所以没法用 Python 进行扩展,不过也可以参考 Sequencer Scripting 插件的做法,将 FClass 转成 UClass 进行调用。
后续有空再进一步研究吧,c++的开发效率实在是太低了,而且我的基础极其不扎实,需要一些基础教程巩固一下_(:з」∠)_
页: [1]
查看完整版本: Unreal Sequencer 菜单工具栏嵌入