[[toc]]
ImGui_WS插件提供了虚幻调试信息远程网页显示的能力,支持打包后生效。(例如独立的DS进程可以用这个调试器可视化预览游戏内的数据)
- ImGui网页绘制
- 本地Slate面板绘制
- UMG支持
- ImGui蓝图节点(自动管理作用域)
- 虚幻世界调试器
- 虚幻世界俯视图
- 细节面板
- 世界大纲视图
- 日志与控制台功能
- 面板布局系统
- ImPlot数据可视化库
- C++ RAII API
在ImGui网页选择ImGui_WS,勾选ImGuiDemo打开Demo面板
代码查看ImGuiDemo.cpp可参考Demo面板复制所需的控件绘制方法
imgui_manual demo网页版
点击右下角的ImGui按钮开启对应的网页,或者控制台输入ImGui.WS.LaunchWeb打开网页
ImGui_WS绘制只在编辑器下默认启用,打包后的DS或者客户端在启动参数添加
-ExecCmds="ImGui.WS.Enable 1"
来启用绘制
通过ImGui_WS菜单下的世界上下文选项可选择预览的World
可以通过Config或者命令行来设置端口号
-
ProjectSettings - Plugins - ImGui_WS 中可配置端口号
-
ImGui_WS.ini配置文件
[/Script/ImGui_WS.ImGui_WS_Settings]
GamePort=8890
ServerPort=8891
EditorPort=8892 -
启动参数配置 -ExecCmds="ImGui.WS.Port 8890"
- 从UImGui_WS_Manager::GetImGuiContext获取到ImGuiContext
- 成员OnDraw为ImGui_WS绘制调用的事件
- 绑定该事件调用ImGui绘制特定的面板
- UnrealImGui::FImGuiTextureHandle创建图片的句柄
- 调用UnrealImGui::UpdateTextureData更新图片信息
- ImGui::Image绘制该图片
static UnrealImGui::FImGuiTextureHandle TextureHandle = []
{
UTexture2D* Texture2D = LoadObject<UTexture2D>(nullptr, TEXT("/Engine/EditorResources/S_Actor"));
// 步骤1
const UnrealImGui::FImGuiTextureHandle Handle{ Texture2D };
// 步骤2
UnrealImGui::UpdateTextureData(Handle, UnrealImGui::ETextureFormat::RGB8, Texture2D);
return Handle;
}();
// 步骤3
ImGui::Image(TextureHandle, ImVec2{ 256.f, 256.f });
控制台变量 ImGui.WS.LocalPanelMode <ELocalPanelMode>
设置本地面板模式
控制台命令
ImGui.WS.OpenPanel
打开本地面板ImGui.WS.ClosePanel
关闭本地面板
新增ImGuiPanel
控件,将控件提升为变量(勾选Is Variable)后可绑定OnImGuiTick
绘制事件
封装大部分ImGui绘制函数给蓝图使用,且节点自动管理作用域,不用手动控制Begin、End调用配对
World Debugger为本插件提供的默认运行时虚幻世界调试器,提供了预览和设置游戏世界中Actor属性的功能
可配置控制台变量ImGui.DebugGameWorld控制是否启用该调试面板,默认启用
若需要关闭该功能,可以在游戏模块StartupModule中设置ImGuiWorldDebuggerBootstrap::bLaunchImGuiWorldDebugger = false;
为了避免无关的Actor显示太多,默认预览只会显示继承UImGuiWorldDebuggerDrawerBase声明绘制的Actor
FilterActor搜索框中输入type:ClassPath后在地图中只会显示当前类型的Actor
创建继承于UImGuiWorldDebuggerDrawerBase的类型
- 添加构造函数
UShootWeaponBulletDrawer::UShootWeaponBulletDrawer()
{
// 标识该Drawer支持的Actor类型
DrawActor = AShootWeaponBullet::StaticClass();
// 绘制的实体半径
Radius = 10.f;
// 绘制的颜色
Color = FLinearColor::Red;
}
- 重写DrawImGuiDebuggerExtendInfo等函数添加额外的调试信息绘制
void UShootWeaponBulletDrawer::DrawImGuiDebuggerExtendInfo(const AActor* Actor, const FImGuiWorldViewportContext& DebuggerContext) const
{
const AShootWeaponBullet* Bullet = CastChecked<AShootWeaponBullet>(Actor);
const FVector EndLocation = Bullet->GetActorLocation();
const FVector StartLocation = EndLocation - Actor->GetVelocity() * DebuggerContext.DeltaSeconds;
DebuggerContext.DrawLine(FVector2D{ StartLocation }, FVector2D{ EndLocation }, Color);
}
继承UImGuiWorldDebuggerViewportPanel并重写以下虚函数
- DrawDebugInfoUnderActors 在Actor的下层绘制额外的调试信息
- DrawDebugInfoUpperActors 在Actor的上层绘制额外的调试信息
建议每个世界调试信息添加开关,避免调试世界同时显示过多的元素
// 声明开关
UPROPERTY(Config)
uint8 bExampleToggle : 1;
// 实现中添加是否开启开关的菜单选项
if (ImGui::BeginMenu("Example Menu"))
{
{
bool Value = bExampleToggle;
if (ImGui::Checkbox("Example Toggle", &Value))
{
bShowGlobalLifeTime = Value;
DebuggerContext.MarkConfigDirty();
}
}
ImGui::EndMenu();
}
// 逻辑中判断开关,开启的情况再进行调试信息的绘制
可绘制传入的UObject实例所有的属性,支持多选编辑
使用方式可参考UImGuiWorldDebuggerDetailsPanel::Draw
查看FStructCustomizerScoped的使用方式
- 继承UImGuiWorldDebuggerPanelBase给ImGuiWorldDebugger新增面板
- 继承UImGuiWorldDebuggerLayoutBase给ImGuiWorldDebugger新增布局描述
UUnrealImGuiPanelBuilder用于构建所属窗口的布局,需要配置以下参数
属性名 | 描述 |
---|---|
DockSpaceName | 该布局系统的名称 |
配置完布局系统的描述信息后调用以下方法进行面板的绘制
方法名 | 描述 |
---|---|
Register | 注册该布局系统,创建时调用 |
Unregister | 注销该布局系统,销毁时调用 |
DrawPanels | 绘制该布局系统下的面板 |
LoadDefaultLayout | 重新加载激活的布局 |
继承UUnrealImGuiPanelBuilder下支持的布局基类类型,例如ImGuiWorldDebugger拓展布局就继承UImGuiWorldDebuggerLayoutBase
- 配置LayoutName,没配置布局名的布局不会显示
- 重写LoadDefaultLayout,声明默认的布局结构
- 重写ShouldCreateLayout,声明改布局系统支持的Owner
默认布局将视口划分了四个区域
UCLASS()
class UImGuiWorldDebuggerDefaultLayout : public UImGuiWorldDebuggerLayoutBase
{
GENERATED_BODY()
public:
// 声明DockId,作为面板注册Dock时的配置
enum EDockId
{
Viewport,
Outliner,
Details,
Utils,
};
UImGuiWorldDebuggerDefaultLayout();
void LoadDefaultLayout(UObject* Owner, const UUnrealImGuiPanelBuilder& LayoutBuilder) override;
};
UImGuiWorldDebuggerDefaultLayout::UImGuiWorldDebuggerDefaultLayout()
{
// 设置布局名
LayoutName = TEXT("Default");
}
void UImGuiWorldDebuggerDefaultLayout::LoadDefaultLayout(UObject* Owner, const UUnrealImGuiPanelBuilder& LayoutBuilder)
{
const ImGuiID DockId = ImGui::DockBuilderAddNode(DockSpaceId, ImGuiDockNodeFlags_None);
// 调用DockBuilderSplitNode划分布局
ImGuiID RemainAreaId;
ImGuiID ViewportId = ImGui::DockBuilderSplitNode(DockSpaceId, ImGuiDir_Left, 0.7f, nullptr, &RemainAreaId);
const ImGuiID UtilsId = ImGui::DockBuilderSplitNode(ViewportId, ImGuiDir_Down, 0.3f, nullptr, &ViewportId);
const ImGuiID OutlinerId = ImGui::DockBuilderSplitNode(RemainAreaId, ImGuiDir_Up, 0.3f, nullptr, &RemainAreaId);
const ImGuiID DetailsId = ImGui::DockBuilderSplitNode(RemainAreaId, ImGuiDir_Down, 0.7f, nullptr, &RemainAreaId);
// 将声明的DockId与ImGui的实际ID添加映射关系
const TMap<int32, ImGuiID> DockIdMap
{
{ Viewport, ViewportId },
{ Outliner, OutlinerId },
{ Details, DetailsId },
{ Utils, UtilsId },
};
// 子面板应用布局信息
ApplyPanelDockSettings(LayoutBuilder, DockIdMap, EDockId::Utils);
ImGui::DockBuilderFinish(DockId);
}
继承UUnrealImGuiPanelBuilder下支持的面板基类类型,例如ImGuiWorldDebugger拓展面板就继承UImGuiWorldDebuggerPanelBase
- 配置Title,无命名的面板不会被注册
- 配置DefaultDockSpace,添加面板在布局中的位置
- 重写Draw,实现面板的绘制
- 重写ShouldCreatePanel,声明面板支持的Owner(可选)
UImGuiWorldDebuggerViewportPanel::UImGuiWorldDebuggerViewportPanel()
{
// 声明需要显示菜单栏
ImGuiWindowFlags = ImGuiWindowFlags_MenuBar;
// 面板命名
Title = TEXT("Viewport");
// 默认在ImGuiWorldDebuggerDefaultLayout布局中的位置为Viewport
DefaultDockSpace =
{
{ UImGuiWorldDebuggerDefaultLayout::StaticClass()->GetFName(), UImGuiWorldDebuggerDefaultLayout::EDockId::Viewport }
};
}
蓝图创建的面板需要在
Project Settings - ImGui WS - Blueprint Panels
中添加才会显示
- 继承UUnrealImGuiViewportBase创建特定的Viewport面板
- 继承UUnrealImGuiViewportExtentBase创建Viewport的绘制拓展
- 重写DrawViewportMenu实现菜单的绘制
- 重写DrawViewportContent实现Viewport中元素的绘制
- 重写ShouldCreateExtent声明该拓展支持的面板(可选)
菜单Tools - ImGui Panels
可打开单独的ImGui面板
调用ImGui::InsertNotification使用全局的冒泡消息提示
开始录制:
- 菜单->ImGui_WS->Start Record
- 控制台输入ImGui.WS.StartRecord
结束录制:
- 菜单->ImGui_WS->Stop Record
- 控制台输入ImGui.WS.StopRecord
菜单->ImGui_WS->Load Record,选择录制的文件进行回看
封装ImGui API支持自动管理作用域,引用ImGuiEx.h头文件可使用作用域接口
// RAII 写法,不用开发者关心ImGui::End的调用
if (ImGui::FWindow Window{ "WindowName" })
{
ImGui::Text("Content");
}
// 等价的ImGui默认API写法,需要管理ImGui::End的调用
if (ImGui::Begin("WindowName"))
{
ImGui::Text("Content");
}
// 不能漏了,否则绘制会出错
ImGui::End();