mcpField
U
ue-materials-rendering

ue-materials-rendering

github.com/quodsoler开发4191.3k 次安装4 周前更新
代码仓库

关于 ue-materials-rendering

面向 UE 5.8 C++ 材质与渲染开发的编码技能,按常见任务指引相关 API,并提供签名和实现说明,涵盖材质、渲染目标、场景捕获及渲染器功能。

主要功能

  1. 01运行时材质参数控制
  2. 02材质参数集合
  3. 03渲染目标与场景捕获
  4. 04后期处理与 Decal 指引
  5. 05UE 5.8 渲染器功能参考

适用场景

  1. 01修改单个 Actor 的材质值
  2. 02在多个材质间共享天气或时间值
  3. 03渲染小地图、镜面或摄像机画面
  4. 04实现后期处理效果或 Decal

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/quodsoler/unreal-engine-skills --skill ue-materials-rendering

安装后在 Claude Code 中输入/ue-materials-rendering确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
global-shaders-rdg.md
material-parameter-reference.md
post-process-settings.md

详细介绍

UE 材质与渲染

目标引擎:UE 5.8。以下 API 已根据 5.8 头文件验证;较旧的形式列在“已弃用 — 请勿使用”下。

运行时材质与渲染 C++:UMaterialInstanceDynamic、UMaterialParameterCollection、UTextureRenderTarget2D、USceneCaptureComponent2D、FPostProcessSettings、UDecalComponent,以及 5.8 渲染器功能(Nanite、Lumen、MegaLights、Substrate、Virtual Shadow Maps、TSR)。材质头文件位于 Runtime/Engine/Public/Materials;渲染目标、场景和后期处理体积位于 Runtime/Engine/Classes/Engine;蓝图库位于 Runtime/Engine/Classes/Kismet。Build.cs:"Engine" 涵盖以上所有内容;只有在使用 EShaderPlatform、RDG 和全局着色器时,才添加 "RenderCore" 和 "RHI"。

上下文

如果 .agents/ue-project-context.md 存在,请阅读它(模块名称、约定、已启用插件、渲染器设置)。如果该文件缺失,请继续。

根据请求和代码库确定相关领域。只有当两种合理解读会产生不同代码时才提问。

请求涉及……前往
在运行时更改网格上的材质参数动态材质实例
一个值驱动多个材质(天气、一天中的时间)材质参数集合
小地图、镜子、监控摄像头、运行时纹理绘制渲染目标 / 场景捕获
Bloom、曝光、景深、色彩分级、Lumen 质量控制项后期处理
以材质形式制作的全屏特效后期处理材质
弹孔、血迹、投影纹理贴花
Nanite 网格/材质兼容性、WPO、Nanite 覆盖材质Nanite
GI、反射、多个带阴影的灯光Lumen 和 MegaLights
分层/多 BSDF 材质系统Substrate
轮廓、X 射线、模板遮罩、阴影/抗锯齿设置阴影、抗锯齿和自定义深度
API 需要 EShaderPlatform,但你只有一个功能级别功能级别与着色器平台
使用 C++ 编写实际的 HLSL 着色器通道全局着色器与渲染图

完整的签名表位于 material-parameter-reference.md;FPostProcessSettings 字段表位于 post-process-settings.md;全局着色器和 RDG 代码位于 global-shaders-rdg.md。

动态材质实例

MID 是在父材质基础上按实例覆盖参数的对象。创建方式有三种:

需求调用
创建未绑定到插槽的独立 MIDUMaterialInstanceDynamic::Create(Parent, Outer, Name)
将 MID 分配给组件的材质插槽UPrimitiveComponent::CreateDynamicMaterialInstance(ElementIndex, SourceMaterial, OptionalName)
通过面向 Blueprint 的库代码创建 MIDUKismetMaterialLibrary::CreateDynamicMaterialInstance(WorldContextObject, Parent, OptionalName, CreationFlags)

原样签名:

// Materials/MaterialInstanceDynamic.h
static UMaterialInstanceDynamic* Create(class UMaterialInterface* ParentMaterial, class UObject* InOuter, FName Name = NAME_None);

// Components/PrimitiveComponent.h
virtual class UMaterialInstanceDynamic* CreateDynamicMaterialInstance(int32 ElementIndex, class UMaterialInterface* SourceMaterial = NULL, FName OptionalName = NAME_None);

// Kismet/KismetMaterialLibrary.h
static class UMaterialInstanceDynamic* CreateDynamicMaterialInstance(UObject* WorldContextObject, class UMaterialInterface* Parent, FName OptionalName = NAME_None, EMIDCreationFlags CreationFlags = EMIDCreationFlags::None);

创建一次,缓存到 UPROPERTY 中,并在 Tick 中或事件触发时更新:

// MyGlowActor.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyGlowActor.generated.h"

class UMaterialInstanceDynamic;
class UStaticMeshComponent;

UCLASS()
class MYGAME_API AMyGlowActor : public AActor
{
    GENERATED_BODY()

public:
    AMyGlowActor();
    virtual void BeginPlay() override;

protected:
    UPROPERTY(VisibleAnywhere, Category = "Rendering")
    TObjectPtr<UStaticMeshComponent> Mesh;

    UPROPERTY(Transient)
    TObjectPtr<UMaterialInstanceDynamic> GlowMID;
};
// MyGlowActor.cpp
#include "MyGlowActor.h"

#include "Components/StaticMeshComponent.h"
#include "Materials/MaterialInstanceDynamic.h"

AMyGlowActor::AMyGlowActor()
{
    Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
    SetRootComponent(Mesh);
}

void AMyGlowActor::BeginPlay()
{
    Super::BeginPlay();

    GlowMID = Mesh->CreateDynamicMaterialInstance(0);
    if (GlowMID)
    {
        GlowMID->SetVectorParameterValue(TEXT("GlowColor"), FLinearColor(1.f, 0.4f, 0.1f, 1.f));
        GlowMID->SetScalarParameterValue(TEXT("GlowStrength"), 1.f);
    }
}

如果每帧要更改数十个参数,请将名称查找替换为索引 API:先调用一次 InitializeScalarParameterAndGetIndex,之后每帧调用 SetScalarParameterByIndex。签名和对应的向量版本见 material-parameter-reference.md。

Setter(MaterialInstanceDynamic.h)——名称是区分大小写的 FName,必须与材质参数完全匹配:

void SetScalarParameterValue(FName ParameterName, float Value);
void SetVectorParameterValue(FName ParameterName, FLinearColor Value);
void SetDoubleVectorParameterValue(FName ParameterName, FVector4 Value);
void SetTextureParameterValue(FName ParameterName, class UTexture* Value);
void SetRuntimeVirtualTextureParameterValue(FName ParameterName, class URuntimeVirtualTexture* Value);
void SetSparseVolumeTextureParameterValue(FName ParameterName, class USparseVolumeTexture* Value);
void SetTextureCollectionParameterValue(FName ParameterName, UTextureCollection* Value);

除双精度向量和稀疏体积 setter 外,其他 setter 都有对应的 ByInfo 版本——例如 SetScalarParameterValueByInfo(const FMaterialParameterInfo& ParameterInfo, float Value)——可用于访问材质层或函数中的参数。

读取值:K2_GetScalarParameterValue(FName)、K2_GetVectorParameterValue(FName)、K2_GetTextureParameterValue(FName) 会直接返回值。UMaterialInterface 上的类型化形式是 bool GetScalarParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, float& OutValue, bool bOveriddenOnly = false) const——它接受参数 info,而非单独的名称。

在实例之间复制:CopyParameterOverrides(仅复制已覆盖的参数)、CopyInterpParameters(仅复制源实例自身的标量、向量、纹理和字体覆盖,不遍历层级)、CopyMaterialUniformParameters(复制 uniform,跳过静态参数)、K2_CopyMaterialInstanceParameters(复制所有非静态参数)、CopyScalarAndVectorParameters(const UMaterialInterface&, EShaderPlatform) 和 K2_InterpolateMaterialInstanceParams(SourceA, SourceB, Alpha)。ClearParameterValues() 会清除所有覆盖值。完整签名见 material-parameter-reference.md。

静态参数(静态开关、静态布尔值、静态分量蒙版)无法在 MID 上更改。请在编辑器中为每种排列创建一个 UMaterialInstanceConstant,再在其上叠加 MID。

材质参数集合

UMaterialParameterCollection 是由 ScalarParameters / VectorParameters 数组组成的资源;每个引用它的材质都会从每个世界的一个 uniform buffer 中读取数据。通过 UWorld 获取对应世界的实例:

#include "Materials/MaterialParameterCollection.h"
#include "Materials/MaterialParameterCollectionInstance.h"

void AMyWeatherActor::SetRain(float Intensity)
{
    UMaterialParameterCollectionInstance* Inst = GetWorld()->GetParameterCollectionInstance(RainCollection);
    if (Inst)
    {
        Inst->SetScalarParameterValue(TEXT("RainIntensity"), Intensity);
        Inst->SetVectorParameterValue(TEXT("RainTint"), FLinearColor(0.6f, 0.7f, 0.9f, 1.f));
    }
}

如果集合中不存在该名称,两个 setter 都会返回 false。Getter 为 bool GetScalarParameterValue(FName ParameterName, float& OutParameterValue) const 及对应的向量版本。ForceReturnToDefaultValues() 会重置该实例。

面向 Blueprint 的库会为你执行世界查找(Kismet/KismetMaterialLibrary.h):

static void SetScalarParameterValue(UObject* WorldContextObject, UMaterialParameterCollection* Collection, FName ParameterName, float ParameterValue);
static void SetVectorParameterValue(UObject* WorldContextObject, UMaterialParameterCollection* Collection, FName ParameterName, const FLinearColor& ParameterValue);
static float GetScalarParameterValue(UObject* WorldContextObject, UMaterialParameterCollection* Collection, FName ParameterName);
static FLinearColor GetVectorParameterValue(UObject* WorldContextObject, UMaterialParameterCollection* Collection, FName ParameterName);

集合不包含纹理参数。若一个值会被多个材质读取,请使用集合;若要表示每个 Actor 的状态,请使用 MID。

渲染目标

UKismetRenderingLibrary(Kismet/KismetRenderingLibrary.h)负责运行时渲染目标工作流:

static UTextureRenderTarget2D* CreateRenderTarget2D(UObject* WorldContextObject, int32 Width = 256, int32 Height = 256, ETextureRenderTargetFormat Format = RTF_RGBA16f, FLinearColor ClearColor = FLinearColor::Black, bool bAutoGenerateMipMaps = false, bool bSupportUAVs = false);
static void ClearRenderTarget2D(UObject* WorldContextObject, UTextureRenderTarget2D* TextureRenderTarget, FLinearColor ClearColor = FLinearColor(0, 0, 0, 1));
static void ResizeRenderTarget2D(UTextureRenderTarget2D* TextureRenderTarget, int32 Width = 256, int32 Height = 256);
static void ReleaseRenderTarget2D(UTextureRenderTarget2D* TextureRenderTarget);
static void DrawMaterialToRenderTarget(UObject* WorldContextObject, UTextureRenderTarget2D* TextureRenderTarget, UMaterialInterface* Material);
static void ExportRenderTarget(UObject* WorldContextObject, UTextureRenderTarget2D* TextureRenderTarget, const FString& FilePath, const FString& FileName);
static FColor ReadRenderTargetPixel(UObject* WorldContextObject, UTextureRenderTarget2D* TextureRenderTarget, int32 X, int32 Y);

ETextureRenderTargetFormat(Engine/TextureRenderTarget2D.h):RTF_R8、RTF_RG8、RTF_RGBA8、RTF_RGBA8_SRGB、RTF_R16f、RTF_RG16f、RTF_RGBA16f、RTF_R32f、RTF_RG32f、RTF_RGBA32f、RTF_RGB10A2。选择能够容纳数据的最小格式——LDR/UI 使用 RTF_RGBA8,HDR 使用 RTF_RGBA16f,单通道使用 RTF_R16f。

需要精确像素格式时,可手动创建:

UTextureRenderTarget2D* RT = NewObject<UTextureRenderTarget2D>(this);
RT->InitCustomFormat(512, 512, PF_FloatRGBA, /*bInForceLinearGamma=*/true);
RT->UpdateResourceImmediate(/*bClearRenderTarget=*/true);

Canvas 绘制会将多次绘制合并为一次渲染目标切换:

UCanvas* Canvas = nullptr;
FVector2D CanvasSize = FVector2D::ZeroVector;
FDrawToRenderTargetContext Context;

UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(this, RT, Canvas, CanvasSize, Context);
Canvas->K2_DrawMaterial(IconMaterial, FVector2D::ZeroVector, CanvasSize, FVector2D::ZeroVector);
UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(this, Context);

UCanvasRenderTarget2D(Engine/CanvasRenderTarget2D.h)封装了该循环:使用 CreateCanvasRenderTarget2D(WorldContextObject, CanvasRenderTarget2DClass, Width, Height) 创建,绑定 OnCanvasRenderTargetUpdate,并在需要重绘内容时调用 UpdateResource()。

ReadRenderTargetPixel 等函数会导致 GPU 停顿。请在编辑器工具或一次性捕获中使用,切勿每帧调用;如需流式读取,请使用 FRHIGPUTextureReadback。

场景捕获

USceneCaptureComponent2D 会将世界渲染到 UTextureRenderTarget2D 中。它自身的字段包括:TextureTarget、FOVAngle、PostProcessSettings、PostProcessBlendWeight、bMainViewResolution、CaptureScene()、CaptureSceneDeferred()。从 USceneCaptureComponent 继承的成员包括:CaptureSource、bCaptureEveryFrame、bCaptureOnMovement、PrimitiveRenderMode、ShowOnlyActors、HiddenActors、ShowFlags、ShowOnlyComponent()、ShowOnlyActorComponents()。

#include "Components/SceneCaptureComponent2D.h"

SceneCapture = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("SceneCapture"));
SceneCapture->SetupAttachment(RootComponent);
SceneCapture->FOVAngle = 90.f;
SceneCapture->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR;
SceneCapture->bCaptureEveryFrame = false;   // drive it manually
SceneCapture->bCaptureOnMovement = false;
SceneCapture->PrimitiveRenderMode = ESceneCapturePrimitiveRenderMode::PRM_UseShowOnlyList;
SceneCapture->ShowFlags.SetFog(false);
SceneCapture->ShowFlags.SetMotionBlur(false);

ESceneCaptureSource(Engine/EngineTypes.h):SCS_SceneColorHDR、SCS_SceneColorHDRNoAlpha、SCS_FinalColorLDR、SCS_SceneColorSceneDepth、SCS_SceneDepth、SCS_DeviceDepth、SCS_Normal、SCS_BaseColor、SCS_FinalColorHDR、SCS_FinalToneCurveHDR。SCS_Normal 和 SCS_BaseColor 仅适用于延迟渲染器。

将 bCaptureEveryFrame = false 和 bCaptureOnMovement = false 设置为 false 后,在视图确实需要更新时调用 SceneCapture->CaptureScene()——场景捕获会额外完整渲染一次场景。

后期处理

FPostProcessSettings(Engine/Scene.h)由 APostProcessVolume::Settings、UPostProcessComponent::Settings、UCameraComponent::PostProcessSettings 和 USceneCaptureComponent2D::PostProcessSettings 持有。每个值字段都有对应的 bOverride_<Field> 位;除非该覆盖位为 true,否则该值会被忽略。

#include "Engine/PostProcessVolume.h"
#include "Engine/Scene.h"

void AMyMoodDirector::ApplyDangerMood(APostProcessVolume* Volume)
{
    Volume->bEnabled = true;
    Volume->bUnbound = true;
    Volume->Priority = 10.f;
    Volume->BlendWeight = 1.f;

    FPostProcessSettings& S = Volume->Settings;
    S.bOverride_BloomIntensity = true;
    S.BloomIntensity = 0.35f;
    S.bOverride_VignetteIntensity = true;
    S.VignetteIntensity = 0.8f;
    S.bOverride_ColorSaturation = true;
    S.ColorSaturation = FVector4(0.6f, 0.6f, 0.6f, 1.f);
}

APostProcessVolume 和 UPostProcessComponent 都公开了 Settings、Priority、BlendRadius、BlendWeight、bEnabled、bUnbound 以及 AddOrUpdateBlendable(TScriptInterface<IBlendableInterface> InBlendableObject, float InWeight = 1.0f)。重叠的体积中,Priority 较高者优先;bUnbound 会使体积在任何位置生效。

按摄像机设置后期处理:使用 UCameraComponent::PostProcessSettings 和 PostProcessBlendWeight,以及 AddOrUpdateBlendable / RemoveBlendable。(AddExtraPostProcessBlend 只会存储设置——只有编辑器视口会读取这些设置,Camera/CameraComponent.h:323。)在摄像机修饰器或摄像机管理器中,通过 APlayerCameraManager::AddCachedPPBlend(FPostProcessSettings& PPSettings, float BlendWeight, EViewTargetBlendOrder BlendOrder = VTBlendOrder_Base) 推送临时混合;使用 GetCachedPostProcessBlends 读取。缓存会在每帧开始时的 ApplyCameraModifiers 中清空(PlayerCameraManager.cpp:289),因此每帧都要重新添加混合;ClearCachedPPBlends 和 PostProcessBlendCache 数组都受保护(Camera/PlayerCameraManager.h:371,391)。

有关 bloom、exposure、DOF、color grading、film grain、AO、Lumen、SSR、motion blur 和 lens 的逐字段表格,请参阅 post-process-settings.md。

后期处理材质

后期处理材质是 MaterialDomain 为 MD_PostProcess 的 UMaterial(MaterialDomain.h)。相关 UMaterial 字段:BlendableLocation、BlendablePriority、bIsBlendable、UserSceneTexture。

EBlendableLocation(Engine/BlendableInterface.h):BL_SceneColorBeforeDOF、BL_SceneColorAfterDOF、BL_TranslucencyAfterDOF、BL_SSRInput、BL_SceneColorBeforeBloom、BL_ReplacingTonemapper、BL_SceneColorAfterTonemapping。

// Weight 0 = invisible, 1 = full. Calling it again with the same object updates the weight.
Volume->AddOrUpdateBlendable(OutlineMaterial, 1.0f);

// A MID works as a blendable too, so the effect can be parameterised at runtime.
UMaterialInstanceDynamic* OutlineMID = UMaterialInstanceDynamic::Create(OutlineMaterial, this);
OutlineMID->SetScalarParameterValue(TEXT("Thickness"), 2.f);
Volume->AddOrUpdateBlendable(OutlineMID, 1.0f);

如果持有的是设置结构体而非体积,FPostProcessSettings::AddBlendable(TScriptInterface<IBlendableInterface> InBlendableObject, float InWeight) 和 RemoveBlendable 会直接操作 WeightedBlendables 数组。

Decal

UDecalComponent(Components/DecalComponent.h)会将材质投射到其盒体覆盖的对象上:

void SetDecalMaterial(class UMaterialInterface* NewDecalMaterial);
class UMaterialInterface* GetDecalMaterial() const;
virtual class UMaterialInstanceDynamic* CreateDynamicMaterialInstance();
void SetFadeOut(float StartDelay, float Duration, bool DestroyOwnerAfterFade = true);
void SetFadeIn(float StartDelay, float Duration);
void SetFadeScreenSize(float NewFadeScreenSize);
void SetSortOrder(int32 Value);
void SetDecalColor(const FLinearColor& Color);

字段:DecalSize(局部空间范围,用于缩放投射盒)、SortOrder、FadeScreenSize、FadeStartDelay、FadeDuration、DecalColor。

通过 UGameplayStatics(Kismet/GameplayStatics.h)在运行时生成:

UDecalComponent* Decal = UGameplayStatics::SpawnDecalAtLocation(
    this, BulletHoleMaterial, FVector(16.f, 16.f, 16.f), Hit.ImpactPoint, Hit.ImpactNormal.Rotation(), 10.f);

if (Decal)
{
    UMaterialInstanceDynamic* DecalMID = Decal->CreateDynamicMaterialInstance();
    DecalMID->SetScalarParameterValue(TEXT("Wear"), 0.25f);
}

SpawnDecalAttached(DecalMaterial, DecalSize, AttachToComponent, AttachPointName, Location, Rotation, LocationType, LifeSpan) 会跟随移动组件。LifeSpan = 0 表示 Decal 会一直存在。之后若要更改,可调用 UDecalComponent::SetLifeSpan(float)(Components/DecalComponent.h:153,不是 UFUNCTION),或通过 SetFadeOut 控制淡出。

DBuffer Decal 会在基础通道之前累积到缓冲区,因此能够正确影响光照贴图和天空光照;它们需要启用项目设置 r.DBuffer(URendererSettings::bDBuffer,Engine/RendererSettings.h:942),且更改后需要重启。未启用时,常规延迟渲染 Decal 仍会写入 GBuffer,但无法正确影响烘焙光照或天空光照。

Nanite

UStaticMesh::HasValidNaniteData() 用于报告网格是否具有 Nanite 渲染数据(IsNaniteEnabled() 属于 WITH_EDITORONLY_DATA,仅限编辑器构建,Engine/StaticMesh.h:1049)。设置应通过访问器而非原始字段进行:GetNaniteSettings() / SetNaniteSettings(const FMeshNaniteSettings&) / NotifyNaniteSettingsChanged()。

const UStaticMesh* Mesh = MeshComponent->GetStaticMesh();
const bool bIsNanite = Mesh && Mesh->HasValidNaniteData();

编写代码前值得了解的材质规则:

材质属性Nanite
不透明、双面支持
遮罩支持;受 r.Nanite.AllowMaskedMaterials 控制
世界位置偏移支持;可在 UStaticMeshComponent 上逐组件调用 SetEvaluateWorldPositionOffset(bool) 和 SetWorldPositionOffsetDisableDistance(int32)
半透明Nanite 不会渲染;网格会回退
材质使用标记MATUSAGE_Nanite;蒙皮 Nanite 还需要 MATUSAGE_SkeletalMesh(NaniteResources.cpp:2648)

材质可以通过 FMaterialOverrideNanite 携带 Nanite 专用替换材质(Materials/MaterialOverrideNanite.h,GetOverrideMaterial() / SetOverrideMaterial(UMaterialInterface*, bool));对于 MID,对应接口是 SetNaniteOverride(UMaterialInterface* InMaterial)。

Nanite 装配体会用多个部分组合成一个 Nanite 网格:FNaniteAssemblyData、FNaniteAssemblyPart、FNaniteAssemblyNode、FNaniteAssemblyBoneInfluence(Engine/NaniteAssemblyData.h)。可通过组件上的 USkinnedMeshComponent::HasValidNaniteData() / GetNaniteResources() 查询蒙皮 Nanite,并通过逐组件设置 bDisallowNanite 将其禁用。

Lumen 和 MegaLights

Lumen 的质量由 FPostProcessSettings 控制:LumenSceneDetail、LumenSceneLightingQuality、LumenSceneLightingUpdateSpeed、LumenFinalGatherQuality、LumenFinalGatherLightingUpdateSpeed、LumenMaxTraceDistance、LumenReflectionQuality、LumenRayLightingMode——每项都有对应的 bOverride_* 位。ELumenRayLightingModeOverride 的取值包括 Default、SurfaceCache、HitLightingForReflections、HitLighting。渲染器路径本身由同一结构体中的 DynamicGlobalIlluminationMethod 和 ReflectionMethod 选择。

与逐体积覆盖相比,调整可伸缩性设置成本更低:sg.GlobalIlluminationQuality 会选择 BaseScalability.ini 中的 [GlobalIlluminationQuality@N] 配置块。等级 1(“Lumen Lite”)会将 Lumen 切换为使用辐照度体积进行最终采集,并通过 r.Lumen.FinalGatherMethod=0 使用精简的表面缓存;等级 2 及以上使用屏幕探针采集。在 C++ 中,可使用 Scalability.h 中的 Scalability::SetQualityLevels(const FQualityLevels& QualityLevels, bool bForce = false)。

MegaLights 使用随机采样渲染多个投射阴影的光源。项目范围内的设置是 URendererSettings::bEnableMegaLights(控制台变量 r.MegaLights.EnableForProject);逐体积设置是 FPostProcessSettings::bMegaLights,并使用 bOverride_bMegaLights。运行时 CVar 包括 r.MegaLights.Allowed 和 r.MegaLights.HardwareRayTracing。它需要光线追踪数据——硬件光线追踪,或作为回退方案的软件(Lumen)追踪(MegaLights::HasRequiredTracingData、Renderer/Private/MegaLights/MegaLights.cpp:541)——会取代它所处理光源的其他直接光照和阴影路径;除非设置 r.MegaLights.DirectionalLights=1,否则会跳过方向光(默认值为 0,MegaLights.cpp:239)。

FPostProcessSettings& S = Volume->Settings;
S.bOverride_bMegaLights = true;
S.bMegaLights = true;

Substrate

Substrate 是分层材质系统,可通过 URendererSettings::bEnableSubstrate(r.Substrate)按项目启用;r.Substrate.ProjectGBufferFormat 和 r.Substrate.ProjectClosuresPerPixel 用于控制内存和闭包预算。Substrate 材质节点位于 Materials/MaterialExpressionSubstrate.h。

自定义 Substrate 表达式会构建拓扑树;5.8 版要重载的虚函数(仅限编辑器,在 Materials/MaterialExpression.h:481 的 #if WITH_EDITOR 中)是:

virtual FSubstrateOperator* SubstrateGenerateMaterialTopologyTree(struct FSubstrateTranslatorDataInterface& SubstrateTranslatorData, class UMaterialExpression* Parent, int32 OutputIndex) override;

静态辅助函数是 SubstrateGenerateMaterialTopologyTreeCommon,它也会首先接收 FSubstrateTranslatorDataInterface&。旧版接收 FMaterialCompiler* 的重载已弃用。

阴影、抗锯齿和自定义深度

虚拟阴影贴图是默认的阴影路径;r.Shadow.Virtual.Enable 用于启用它们。使用 World Position Offset 的材质必须在组件上启用 WPO 评估(SetEvaluateWorldPositionOffset),才能使阴影匹配。

抗锯齿设置为 URendererSettings::DefaultFeatureAntiAliasing(EAntiAliasingMethod,SceneUtils.h);AAM_TSR 表示时间超分辨率。运行时覆盖项为 r.AntiAliasingMethod。

自定义深度/模板会为轮廓、X 射线和高亮后处理材质提供数据。项目设置:URendererSettings::CustomDepthStencil(ECustomDepthStencil),控制台变量 r.CustomDepth。逐组件设置:

MeshComponent->SetRenderCustomDepth(true);
MeshComponent->SetCustomDepthStencilValue(1);   // 0-255, read as CustomStencil in a post-process material

功能级别和着色器平台

材质查询 API 接收的是 EShaderPlatform(RHIShaderPlatform.h),而不是 ERHIFeatureLevel::Type(RHIFeatureLevel.h)。使用 RHIGlobals.h 中的 GetFeatureLevelShaderPlatform 进行转换:

#include "RHIGlobals.h"

const ERHIFeatureLevel::Type FeatureLevel = GetWorld()->GetFeatureLevel();
const EShaderPlatform ShaderPlatform = GetFeatureLevelShaderPlatform(FeatureLevel);

if (MyMaterial->IsCompilingOrHadCompileError(ShaderPlatform))   // UMaterial* -- not on UMaterialInterface
{
    // hide the object until its shaders are ready
}

使用标志通过 UMaterialInterface 上的 GetUsageByFlag(EMaterialUsage Usage) 读取,切勿直接访问 bUsedWith* 字段:

if (!MyMaterial->GetUsageByFlag(MATUSAGE_Nanite))
{
    // not authorised for Nanite meshes
}

CheckMaterialUsage(EMaterialUsage) 和 CheckMaterialUsage_Concurrent(EMaterialUsage) const 会设置标志,并在标志缺失时触发重新编译;SetMaterialUsage(EMaterialUsage Usage) 是虚函数。

全局着色器与渲染图

对于真正的 HLSL 通道,声明一个 FGlobalShader 子类,并使用 DECLARE_GLOBAL_SHADER、SHADER_USE_PARAMETER_STRUCT 和 BEGIN_SHADER_PARAMETER_STRUCT 块;使用 IMPLEMENT_GLOBAL_SHADER 将其绑定到 .usf,并通过 GraphBuilder.AddPass(...) 向 FRDGBuilder 添加通道,然后调用 GraphBuilder.Execute() 提交。Build.cs 需要 "RenderCore"、"RHI" 和 "Projects"。

两条规则会导致大多数故障。在 StartupModule 中使用 AddShaderSourceDirectoryMapping 注册着色器虚拟路径。为该模块设置 "LoadingPhase": "PostConfigInit":如果使用常见的 Default 阶段,全局着色器类型注册得太晚,会触发 "Shader type was loaded too late" checkf(Shader.cpp:315)。完整的计算着色器声明、AddPass 形式和模块启动代码:references/global-shaders-rdg.md。

已弃用 — 请勿使用

请勿输出在 5.8 中使用来源
Material->bUsedWithNanite(任何 bUsedWith* 字段)Material->GetUsageByFlag(MATUSAGE_Nanite)Materials/Material.h 中的 UE_DEPRECATED(5.8)(27 个标志)
UMaterial::bEnableExecWire无 — 该实验已移除Materials/Material.h 中的 UE_DEPRECATED(5.8)
SetMaterialUsage(bool& bNeedsRecompile, EMaterialUsage, UMaterialInterface*)SetMaterialUsage(EMaterialUsage Usage)Materials/Material.h 中的 UE_DEPRECATED(5.8)
IsCompilingOrHadCompileError(ERHIFeatureLevel::Type)IsCompilingOrHadCompileError(EShaderPlatform)Materials/Material.h 中的 UE_DEPRECATED(5.7)
GetMaterialResource(ERHIFeatureLevel::Type, ...)GetMaterialResource(EShaderPlatform, ...)Materials/MaterialInterface.h 中的 UE_DEPRECATED(5.7)
GetUsedTexturesAndIndices(..., ERHIFeatureLevel::Type)EShaderPlatform 重载Materials/MaterialInterface.h 中的 UE_DEPRECATED(5.7)
CopyScalarAndVectorParameters(Source, ERHIFeatureLevel::Type)CopyScalarAndVectorParameters(Source, EShaderPlatform)Materials/MaterialInstanceDynamic.h 中的 UE_DEPRECATED(5.7)
GetUsedMaterialPropertyDesc(ERHIFeatureLevel::Type)GetUsedMaterialPropertyDesc(EShaderPlatform)Components/PrimitiveComponent.h 中的 UE_DEPRECATED(5.7)
UMaterialInstance::Resource(公共渲染代理)GetRenderProxy() 或 GetInstanceRenderProxy()Materials/MaterialInstance.h 中的 UE_DEPRECATED(5.8)
UMaterialExpressionTextureBase::GetSamplerTypeForTextureMaterialExpressionUtils::GetSamplerTypeForTextureMaterials/MaterialExpressionTextureBase.h 中的 UE_DEPRECATED(5.8)
UMaterialExpressionTextureBase::VerifySamplerTypeMaterialExpressionUtils::VerifySamplerTypeMaterials/MaterialExpressionTextureBase.h 中的 UE_DEPRECATED(5.8)
SubstrateGenerateMaterialTopologyTreeCommon(FMaterialCompiler*, ...)FSubstrateTranslatorDataInterface& 重载Materials/MaterialExpressionSubstrate.h 中的 UE_DEPRECATED(5.8)
FTextureSamplingInfo CalculateTexturesSamplingInfo(UTexture*)带输出参数的 const bool 形式Materials/MaterialInterface.h 中的 UE_DEPRECATED(5.8)
IsUsingNewTranslatorPrototype()IsUsingNewHLSLGenerator()Materials/MaterialInterface.h 中的 UE_DEPRECATED(5.8)
CreateMIDForElement / CreateMIDForElementFromMaterialCreateDynamicMaterialInstance(ElementIndex, SourceMaterial, OptionalName)Components/PrimitiveComponent.h 中的 DeprecatedFunction
StaticMesh->NaniteSettings(直接访问字段)GetNaniteSettings() / SetNaniteSettings()Engine/StaticMesh.h 中的 UE_DEPRECATED(5.7)
BL_BeforeTranslucency、BL_BeforeTonemapping、BL_AfterTonemappingBL_SceneColorBeforeDOF、BL_SceneColorAfterDOF、BL_SceneColorAfterTonemappingEngine/BlendableInterface.h 中的 UE_DEPRECATED(5.4)

常见错误

每帧都创建 MID: 每次调用 CreateDynamicMaterialInstance 都会分配一个新实例和渲染代理。在 BeginPlay 中创建一次并保存,之后只调用设置函数。

在裸指针中保存 MID: MID 是 UObject,只要没有任何引用指向它,就会被垃圾回收。将它保存在 UPROPERTY() TObjectPtr<UMaterialInstanceDynamic> 中,绝不要将其作为裸 UMaterialInstanceDynamic* 成员或静态变量保存。

设置后处理值时未设置对应的覆盖标记: 单独执行 S.BloomIntensity = 2.f; 不会产生任何效果。每次赋值都需要在旁边设置 S.bOverride_BloomIntensity = true;。

需要着色器平台时却传入功能级别: GetMaterialResource、IsCompilingOrHadCompileError、CopyScalarAndVectorParameters 和 GetUsedMaterialPropertyDesc 中接受 ERHIFeatureLevel::Type 的重载已弃用。使用 GetFeatureLevelShaderPlatform(GetWorld()->GetFeatureLevel()) 转换一次即可。

读取 bUsedWith* 字段: 这些成员已弃用。GetUsageByFlag(EMaterialUsage) 是唯一受支持的读取方式,SetMaterialUsage(EMaterialUsage) 是唯一受支持的写入方式。

以为 SetVectorParameterValue 支持双精度: FVector/FVector4 重载是内联便捷函数,会将值转换为 FLinearColor(浮点型)(Materials/MaterialInstanceDynamic.h:112-113)。当材质读取双精度向量时,请使用 SetDoubleVectorParameterValue(FName, FVector4)。

复制 MID: MID 是客户端本地对象。复制标量/向量值,并在每个客户端的 OnRep 中重建 MID 的状态。

以为静态开关可以在运行时更改: 静态参数会编译进着色器排列。为每种排列创建一个 UMaterialInstanceConstant,并将 MID 的父级设为正确的实例。

在 Tick 中调用 ReadRenderTargetPixel: 它会刷新渲染命令并阻塞管线。仅在编辑器工具中进行读回,或使用 FRHIGPUTextureReadback。

让 bCaptureEveryFrame 保持开启: 每帧都捕获的 USceneCaptureComponent2D 会再次渲染场景。关闭此选项,并在目标实际发生变化时调用 CaptureScene()。

相关技能

  • ue-niagara-effects — Niagara 系统、发射器参数,以及粒子所需的材质使用标记
  • ue-procedural-generation — 为这些材质赋值的 PCG 和运行时网格生成
  • ue-actor-component-architecture — 此处所用组件的设置、附加和生命周期
  • ue-ui-umg-slate — MD_UI 材质、控件画笔,以及将 UMG 渲染到渲染目标
  • ue-sequencer-cinematics — 从序列中为材质参数和后处理设置制作动画
  • ue-testing-debugging — 性能分析、stat 命令、Insights 和 GPU 捕获工作流
  • ue-data-assets-tables — 驱动材质和渲染配置的数据资产与表格
  • ue-cpp-foundations — UObject 生命周期、UPROPERTY、TObjectPtr 和垃圾回收

评论

支持 Markdown