文章

UE5中添加自定义ViewMode

UE5中添加自定义ViewMode

在UE5中,通过定制ViewMode(如Lighting Only)可以实现不同的渲染调试工具。以下是步骤介绍和代码示例:

目标

我们将通过学习并修改UE5的Lighting Only工具,从源码入手,实现以下自定义ViewMode:

  • Diffuse Only
  • Specular Only
  • Direct Lighting Only
  • Indirect Lighting Only

此外,还可以添加新的ViewPort控件显示调试信息。

步骤

1. 定义自定义ViewMode

文件:EngineBaseTypes.h

在此文件中找到Lighting Only定义片段:

1
2
/** Lit wo/ materials. */
VMI_LightingOnly = 5 UMETA(DisplayName = "Lighting Only"),

然后添加自定义ViewMode的定义:

1
2
3
4
5
6
7
8
9
// Custom View Mode
/** Diffuse Only */
VMI_DiffuseOnly = 30 UMETA(DisplayName = "Diffuse Only"),
/** Specular Only */
VMI_SpecularOnly = 31 UMETA(DisplayName = "Specular Only"),
/** Direct Lighting Only */
VMI_DirectLightingOnly = 32 UMETA(DisplayName = "Direct Lighting Only"),
/** Indirect Lighting Only */
VMI_IndirectLightingOnly = 33 UMETA(DisplayName = "Indirect Lighting Only"),

2. 设置显示标志

文件:ShowFlagsValues.inl

在ShowFlagsValues.inl文件中,我们可以看到如下代码行:

1
SHOWFLAG_FIXED_IN_SHIPPING(0, LightingOnlyOverride, SFG_Hidden, NSLOCTEXT("UnrealEd", "LightingOnlyOverrideSF", "Lighting Only"))

注释写道:

1
needed for VMI_LightingOnly, Whether to override material diffuse with constants, used by the Lighting Only viewmode.

译为: VMI_LightingOnly需要,是否使用常量替代材质漫反射,仅照明视图模式使用。

类推, 在后方添加:

1
2
3
4
5
6
7
8
9
// Custom View Mode
/** Diffuse Only */
SHOWFLAG_FIXED_IN_SHIPPING(0, DiffuseOnlyOverride, SFG_Hidden, NSLOCTEXT("UnrealEd", "DiffuseOnlyOverrideSF", "Diffuse Lighting Only"))
/** Specular Only */
SHOWFLAG_FIXED_IN_SHIPPING(0, SpecularOnlyOverride, SFG_Hidden, NSLOCTEXT("UnrealEd", "SpecularOnlyOverrideSF", "Specular Lighting Only"))
/** Direct Lighting Only */
SHOWFLAG_FIXED_IN_SHIPPING(0, DirectLightingOnlyOverride, SFG_Hidden, NSLOCTEXT("UnrealEd", "DirectLightingOnlyOverrideSF", "Direct Lighting Only"))
/** Indirect Lighting Only */
SHOWFLAG_FIXED_IN_SHIPPING(0, IndirectLightingOnlyOverride, SFG_Hidden, NSLOCTEXT("UnrealEd", "IndirectLightingOnlyOverrideSF", "Indirect Lighting Only"))

注意: ShowFlagsValues.inl 会被ShowFlags.h中的struct FEngineShowFlags类使用。生成一个成员属性。

3. 查找并返回自定义ViewMode

文件:ShowFlags.cpp

FindViewMode函数中找到以下代码行:

1
2
3
4
else if (EngineShowFlags.LightingOnlyOverride)
{
    return VMI_LightingOnly;
}

然后为每个自定义ViewMode添加判断语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
else if (EngineShowFlags.DiffuseOnlyOverride)
{
    return VMI_DiffuseOnly;
}
else if (EngineShowFlags.SpecularOnlyOverride)
{
    return VMI_SpecularOnly;
}
else if (EngineShowFlags.DirectLightingOnlyOverride)
{
    return VMI_DirectLightingOnly;
}
else if (EngineShowFlags.IndirectLightingOnlyOverride)
{
    return VMI_IndirectLightingOnly;
}

在EngineShowFlagOverride函数中

1
2
Some view modes want some features off or on (no state)
某些视图模式需要关闭或打开某些功能(无状态)

添加:

注意:此处有问题未解决

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
27
if (ViewModeIndex == VMI_DiffuseOnly)
{
    EngineShowFlags.SetDiffuse(true);
    EngineShowFlags.SetSpecular(false);
    EngineShowFlags.SetMaterials(true);
}

if (ViewModeIndex == VMI_SpecularOnly)
{
    EngineShowFlags.SetSpecular(true);
    EngineShowFlags.SetDiffuse(false);
    EngineShowFlags.SetMaterials(true);
}

if (ViewModeIndex == VMI_DirectLightingOnly)
{
    EngineShowFlags.SetDirectLighting(true);
    EngineShowFlags.(false);
    EngineShowFlags.SetMaterials(false);
}

if (ViewModeIndex == VMI_lndirectLightingOnly)
{
    EngineShowFlags.(true);
    EngineShowFlags.SetDirectLighting(false);
    EngineShowFlags.SetMaterials(false);
}

4. 应用视图模式

ApplyViewMode函数中,通过switch语句控制自定义模式的后处理效果。添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 开启后处理
case VMI_DiffuseOnly:
    bPostProcessing = true;
    break;
case VMI_SpecularOnly:
    bPostProcessing = true;
    break;
case VMI_DirectLightingOnly:
    bPostProcessing = true;
    break;
case VMI_lndirectLightingOnly:
    bPostProcessing = true;
	break;

然后,在switch语句末尾添加以下判断:

1
2
3
4
EngineShowFlags.SetDiffuseOnlyOverride(ViewModeIndex == VMI_DiffuseOnly);
EngineShowFlags.SetSpecularOnlyOverride(ViewModeIndex == VMI_SpecularOnly);
EngineShowFlags.SetDirectLightingOnlyOverride(ViewModeIndex == VMI_DirectLightingOnly);
EngineShowFlags.SetIndirectLightingOnlyOverride(ViewModeIndex == VMI_IndirectLightingOnly);

5. 显示自定义ViewMode名称

文件:ViewModeNames.cpp

FillViewModeDisplayNames函数中,添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Custom View Mode
else if (ViewModeIndex == VMI_DiffuseOnly)
{
    ViewModeDisplayNames.Emplace(LOCTEXT("UViewModeUtils_VMI_DiffuseOnly", "Diffuse Only"));
}
else if (ViewModeIndex == VMI_SpecularOnly)
{
    ViewModeDisplayNames.Emplace(LOCTEXT("UViewModeUtils_VMI_SpecularOnly", "Specular Only"));
}
else if (ViewModeIndex == VMI_DirectLightingOnly)
{
    ViewModeDisplayNames.Emplace(LOCTEXT("UViewModeUtils_VMI_DirectLightingOnly", "Direct Lighting Only"));
}
else if (ViewModeIndex == VMI_IndirectLightingOnly)
{
    ViewModeDisplayNames.Emplace(LOCTEXT("UViewModeUtils_VMI_IndirectLightingOnly", "Indirect Lighting Only"));
}

6. 绑定命令

文件:EditorViewportCommands.h

FEditorViewportCommands类中添加如下定义:

1
2
3
4
5
/** Custom View Mode */
TSharedPtr< FUICommandInfo > DiffuseOnlyMode;
TSharedPtr< FUICommandInfo > SpecularOnlyMode;
TSharedPtr< FUICommandInfo > DirectLightingOnlyMode;
TSharedPtr< FUICommandInfo > IndirectLightingOnlyMode;

EditorViewportCommands.cpp中,RegisterCommands函数中注册命令:

1
2
3
4
UI_COMMAND(DiffuseOnlyMode, "Diffuse Only View Mode", "Diffuse Only Mode", EUserInterfaceActionType::RadioButton, FInputChord());
UI_COMMAND(SpecularOnlyMode, "Specular Only View Mode", "Specular Only Mode", EUserInterfaceActionType::RadioButton, FInputChord());
UI_COMMAND(DirectLightingOnlyMode, "Direct Lighting Only View Mode", "Direct Lighting Only Mode", EUserInterfaceActionType::RadioButton, FInputChord());
UI_COMMAND(IndirectLightingOnlyMode, "Indirect Lighting Only View Mode", "Indirect Lighting Only Mode", EUserInterfaceActionType::RadioButton, FInputChord());

7. 绑定Viewport命令

文件:SEditorViewport.cpp

BindCommands函数中绑定各ViewMode:

1
2
3
4
MAP_VIEWMODE_ACTION(Commands.DiffuseOnlyMode, VMI_DiffuseOnly);
MAP_VIEWMODE_ACTION(Commands.SpecularOnlyMode, VMI_SpecularOnly);
MAP_VIEWMODE_ACTION(Commands.DirectLightingOnlyMode, VMI_DirectLightingOnly);
MAP_VIEWMODE_ACTION(Commands.IndirectLightingOnlyMode, VMI_IndirectLightingOnly);

8. 添加ViewPort菜单

文件:SEditorViewportViewMenu.cpp

FillViewMenu函数中添加菜单项:

1
2
3
4
Section.AddMenuEntry(BaseViewportActions.DiffuseOnlyMode, UViewModeUtils::GetViewModeDisplayName(VMI_DiffuseOnly));
Section.AddMenuEntry(BaseViewportActions.SpecularOnlyMode, UViewModeUtils::GetViewModeDisplayName(VMI_SpecularOnly));
Section.AddMenuEntry(BaseViewportActions.DirectLightingOnlyMode, UViewModeUtils::GetViewModeDisplayName(VMI_DirectLightingOnly));
Section.AddMenuEntry(BaseViewportActions.IndirectLightingOnlyMode, UViewModeUtils::GetViewModeDisplayName(VMI_IndirectLightingOnly));
本文由作者按照 CC BY 4.0 进行授权