一、完整实现流程

1. 创建后处理材质

  1. 材质设置

    • 在材质编辑器中,将材质域(Material Domain)设为后处理(Post Process)

    • 设置混合位置(Blendable Location)(如After Tonemapping)

    • 创建标量/向量参数(如IntensityColorTint

  2. 材质蓝图示例

[SceneTexture:PostProcessInput0] → [参数控制效果] → [输出节点]

2. 添加后处理材质到相机

方法1:通过相机组件(推荐)
// 创建动态材质实例
UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(PostProcessMaterial, this);// 添加到相机组件
if (UCameraComponent* Camera = GetPlayerCamera())
{Camera->AddOrUpdateBlendable(DynamicMaterial, 1.0f); // 1.0为权重
}
方法2:通过相机管理器
APlayerCameraManager* CameraManager = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0);
if (CameraManager)
{FWeightedBlendable Blendable;Blendable.Object = DynamicMaterial;Blendable.Weight = 1.0f;CameraManager->GetCameraCacheView().PostProcessSettings.WeightedBlendables.Array.Add(Blendable);CameraManager->MarkCameraSettingsDirty(); // 确保更新
}

3. 动态更新材质参数

// 高效参数更新函数
void UpdateMaterialParameter(FName ParamName, float Value)
{if (!DynamicMaterial) return;// 值变化检测避免无效更新static float LastValue = MAX_FLT;if (FMath::IsNearlyEqual(Value, LastValue, 0.001f)) return;DynamicMaterial->SetScalarParameterValue(ParamName, Value);LastValue = Value;// 可选:强制刷新(某些版本需要)if (UCameraComponent* Camera = GetPlayerCamera()){Camera->MarkRenderStateDirty();}
}// 使用示例
UpdateMaterialParameter("HitIntensity", FMath::Sin(GetWorld()->GetTimeSeconds()));

4. 移除后处理材质

// 通过相机组件移除
if (UCameraComponent* Camera = GetPlayerCamera())
{Camera->RemoveBlendable(DynamicMaterial);
}// 通过相机管理器移除
if (CameraManager)
{FPostProcessSettings& PPSettings = CameraManager->GetCameraCacheView().PostProcessSettings;for (int32 i = PPSettings.WeightedBlendables.Array.Num() - 1; i >= 0; i--){if (PPSettings.WeightedBlendables.Array[i].Object == DynamicMaterial){PPSettings.WeightedBlendables.Array.RemoveAt(i);break;}}
}

二、组件化实现(最佳实践)

#pragma once#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "PostProcessComponent.generated.h"UCLASS(ClassGroup=(Rendering), meta=(BlueprintSpawnableComponent))
class YOURPROJECT_API UPostProcessComponent : public UActorComponent
{GENERATED_BODY()public:UPostProcessComponent();protected:virtual void BeginPlay() override;virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;public:UFUNCTION(BlueprintCallable, Category = "Post Process")void ActivateEffect(float Duration = 2.0f, float Intensity = 1.0f);UFUNCTION(BlueprintCallable, Category = "Post Process")void SetParameter(FName ParamName, float Value);private:void InitializeMaterial();UCameraComponent* GetCamera() const;void UpdateCamera();UPROPERTY(EditAnywhere, Category = "Post Process")UMaterialInterface* PostProcessMaterial;UPROPERTY(Transient)UMaterialInstanceDynamic* DynamicMaterial = nullptr;UCameraComponent* TargetCamera = nullptr;
};
#include "PostProcessComponent.h"
#include "Camera/CameraComponent.h"
#include "Kismet/GameplayStatics.h"UPostProcessComponent::UPostProcessComponent()
{PrimaryComponentTick.bCanEverTick = false;
}void UPostProcessComponent::BeginPlay()
{Super::BeginPlay();InitializeMaterial();
}void UPostProcessComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{if (DynamicMaterial && TargetCamera){TargetCamera->RemoveBlendable(DynamicMaterial);}Super::EndPlay(EndPlayReason);
}void UPostProcessComponent::InitializeMaterial()
{if (!PostProcessMaterial) return;DynamicMaterial = UMaterialInstanceDynamic::Create(PostProcessMaterial, this);if (!DynamicMaterial) return;TargetCamera = GetCamera();if (TargetCamera){TargetCamera->AddOrUpdateBlendable(DynamicMaterial, 1.0f);}
}void UPostProcessComponent::ActivateEffect(float Duration, float Intensity)
{if (!DynamicMaterial) return;// 重置效果权重if (TargetCamera){TargetCamera->AddOrUpdateBlendable(DynamicMaterial, 1.0f);}// 设置初始参数DynamicMaterial->SetScalarParameterValue("Intensity", Intensity);// 启动定时器自动结束GetWorld()->GetTimerManager().SetTimer(EffectTimer, [this](){if (TargetCamera){TargetCamera->RemoveBlendable(DynamicMaterial);}}, Duration, false);
}void UPostProcessComponent::SetParameter(FName ParamName, float Value)
{if (DynamicMaterial){// 带变化检测的更新float CurrentValue;if (DynamicMaterial->GetScalarParameterValue(ParamName, CurrentValue) &&!FMath::IsNearlyEqual(CurrentValue, Value, 0.001f)){DynamicMaterial->SetScalarParameterValue(ParamName, Value);}}
}UCameraComponent* UPostProcessComponent::GetCamera() const
{AActor* Owner = GetOwner();if (!Owner) return nullptr;// 查找相机组件UCameraComponent* Camera = Owner->FindComponentByClass<UCameraComponent>();if (Camera) return Camera;// 回退到玩家相机if (APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(), 0)){if (APawn* Pawn = PC->GetPawn()){return Pawn->FindComponentByClass<UCameraComponent>();}}return nullptr;
}

三、常见问题与解决方案

1. 材质不显示

原因:

  • 材质域未设置为Post Process
  • 相机未启用后处理(bEnablePostProcessing=false)
  • 混合权重为0

解决:

// 确保相机启用后处理
if (UCameraComponent* Camera = GetCamera())
{Camera->bEnablePostProcessing = true;
}// 验证材质域
if (DynamicMaterial->GetMaterial()->MaterialDomain != MD_PostProcess)
{UE_LOG(LogTemp, Error, TEXT("Material domain must be Post Process!"));
}

2. 参数更新无效

原因:

  • 参数名称拼写错误(区分大小写)
  • 未使用动态材质实例
  • 更新频率过高

解决:

// 验证参数存在
float TempValue;
if (!DynamicMaterial->GetScalarParameterValue("HitIntensity", TempValue))
{UE_LOG(LogTemp, Warning, TEXT("Parameter not found!"));
}// 添加变化检测
void SafeSetParameter(FName Name, float Value)
{static TMap<FName, float> LastValues;if (!LastValues.Contains(Name)) LastValues.Add(Name, MAX_FLT);if (!FMath::IsNearlyEqual(Value, LastValues[Name], 0.001f)){DynamicMaterial->SetScalarParameterValue(Name, Value);LastValues[Name] = Value;}
}

3. 性能问题

优化策略:

  • 参数批量更新:
void SetParameters(TMap<FName, float> Params)
{for (auto& Param : Params){DynamicMaterial->SetScalarParameterValue(Param.Key, Param.Value);}// 单次提交DynamicMaterial->UpdateParameterValues();
}
  • 使用材质参数集合:

// 全局参数控制
UMaterialParameterCollection* GlobalParams = ...;
GetWorld()->GetParameterCollectionInstance(GlobalParams)->SetScalarParameterValue("GlobalIntensity", Value);

四、高级技巧

1. 效果混合与叠加

// 管理多个效果
TMap<FName, UMaterialInstanceDynamic*> ActiveEffects;void AddEffect(FName EffectID, UMaterialInterface* Material)
{UMaterialInstanceDynamic* NewMID = UMaterialInstanceDynamic::Create(Material, this);ActiveEffects.Add(EffectID, NewMID);if (UCameraComponent* Camera = GetCamera()){Camera->AddOrUpdateBlendable(NewMID, 1.0f);}
}void RemoveEffect(FName EffectID)
{if (UMaterialInstanceDynamic** MIDPtr = ActiveEffects.Find(EffectID)){if (UCameraComponent* Camera = GetCamera()){Camera->RemoveBlendable(*MIDPtr);}ActiveEffects.Remove(EffectID);}
}

2. 基于距离的LOD控制

void UpdateEffectLOD()
{FVector PlayerLocation = ...;float Distance = FVector::Distance(GetOwner()->GetActorLocation(), PlayerLocation);float Intensity = FMath::Clamp(1.0f - (Distance / MaxDistance), 0.0f, 1.0f);if (DynamicMaterial){DynamicMaterial->SetScalarParameterValue("EffectIntensity", BaseIntensity * Intensity);// 完全禁用远距离效果if (Intensity < 0.01f){if (UCameraComponent* Camera = GetCamera()){Camera->RemoveBlendable(DynamicMaterial);}}}
}

3. 后处理材质动画

// 在tick中创建动画效果
void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{Super::TickComponent(DeltaTime, TickType, ThisTickFunction);if (bIsAnimating){AnimationTime += DeltaTime;float Pulse = FMath::Sin(AnimationTime * 5.0f) * 0.5f + 0.5f;DynamicMaterial->SetScalarParameterValue("PulseIntensity", Pulse);if (AnimationTime > AnimationDuration){bIsAnimating = false;}}
}

五、总结与最佳实践

1. 材质设置

  • 务必设置材质域为Post Process

  • 使用暴露参数而非硬编码值

2. 生命周期管理

virtual void BeginPlay() override;  // 初始化
virtual void EndPlay() override;     // 清理资源

3. 性能优化:

  • 使用变化检测减少更新次数
  • 批量更新材质参数
  • 远距离禁用效果

4. 错误预防:

// 安全访问模式
if (DynamicMaterial && GetCamera())
{// 操作
}

5. 调试工具:

// 控制台命令
r.PostProcessing.Debug 1  // 显示活动后处理
r.PostProcess 0           // 禁用所有后处理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/91540.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/91540.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/91540.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django基础(三)———模板

前言 在之前的文章中&#xff0c;视图函数只是直接返回文本&#xff0c;而在实际生产环境中其实很少这样用&#xff0c;因为实际的页面大多是带有样式的HTML代码&#xff0c;这可以让浏览器渲染出非常漂亮的页面。目前市面上有非常多的模板系统&#xff0c;其中最知名最好用的…

mysql6表清理跟回收空间

mysql6表清理跟回收空间 文章目录mysql6表清理跟回收空间1.清理表2.备份表或者备份库3.回收表空间4.查看5.验证业务1.清理表 ## 登录 C:\Program Files\MySQL\MySQL Server 5.6\bin>mysql -uroot -p Enter password: ****** Welcome to the MySQL monitor. Commands end w…

Java-74 深入浅出 RPC Dubbo Admin可视化管理 安装使用 源码编译、Docker启动

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; AI炼丹日志-30-新发布【1T 万亿】参数量大模型&#xff01;K…

VSCode同时支持Vue2和Vue3开发的插件指南

引言 随着Vue生态系统的演进&#xff0c;许多开发者面临着在同一开发环境中同时处理Vue 2和Vue 3项目的需求。Visual Studio Code (VSCode)作为最受欢迎的前端开发工具之一&#xff0c;其插件生态对Vue的支持程度直接影响开发效率。本文将深入探讨如何在VSCode中配置插件组合&a…

卷积神经网络CNN的Python实现

一、环境准备与库导入 在开始实现卷积神经网络之前&#xff0c;需要确保开发环境已正确配置&#xff0c;并导入必要的Python库。常用的深度学习框架有TensorFlow和PyTorch&#xff0c;本示例将基于Keras&#xff08;可使用TensorFlow后端&#xff09;进行实现&#xff0c;因为K…

js是实现记住密码自动填充功能

记住密码自动填充使用js实现记住密码功能&#xff0c;在下次打开登陆页面的时候进行获取并自动填充到页面【cookie和localStorage】使用js实现记住密码功能&#xff0c;在下次打开登陆页面的时候进行获取并自动填充到页面【cookie和localStorage】 //添加功能----记住上一个登陆…

【Java】文件编辑器

代码&#xff1a;&#xff08;SimpleEditor.java&#xff09;import java.awt.Color; import java.awt.Font; import java.awt.Insets; import java.awt.BorderLayout;import java.awt.event.ActionEvent; import java.awt.event.ActionListener;import java.io.BufferedReader…

PyTorch中torch.topk()详解:快速获取最大值索引

torch.topk(similarities, k=2).indices 是什么意思 torch.topk(similarities, k=2).indices 是 PyTorch 中用于获取张量中最大值元素及其索引的函数。在你的代码中,它的作用是从 similarities 向量里找出得分最高的2个元素的位置索引。 1. 核心功能:找出张量中最大的k个值…

快速搭建本地HTTP服务器:`python -m http.server`详解

文章目录 一、什么是 http.server? 二、基础使用 1. 启动服务器 2. 指定端口 3. 绑定特定IP 三、实际应用场景 1. 本地前端开发 2. 文件共享 3. 启用CGI脚本(高级) 四、目录浏览详解* 五、安全注意事项 六、进阶技巧 1. 后台运行(Linux/macOS) 2. 自定义错误页面 3. 结合其…

运维技术教程之Jenkins上的known_hosts文件

在Jenkins中&#xff0c;known_hosts文件用于存储已验证的远程节点主机密钥&#xff0c;避免每次连接时重复验证。以下是基于不同场景的解决方案&#xff1a;1. 创建并配置 known_hosts 文件 若Jenkins提示 No Known Hosts file 或找不到文件&#xff0c;需手动创建并配置&…

leetcode 3201. 找出有效子序列的最大长度 I 中等

给你一个整数数组 nums。nums 的子序列 sub 的长度为 x &#xff0c;如果其满足以下条件&#xff0c;则称其为 有效子序列&#xff1a;(sub[0] sub[1]) % 2 (sub[1] sub[2]) % 2 ... (sub[x - 2] sub[x - 1]) % 2返回 nums 的 最长的有效子序列 的长度。一个 子序列 指的…

Java并发编程第三篇(深入解析Synchronized)

1. Synchronized简介&#xff1a;一个常见的并发“陷阱” 在正式开始学习新知识前&#xff0c;我们不妨先来看一个现象&#xff0c;这是一个很多并发编程新手都会遇到的“陷阱”&#xff1a; public class SynchronizedDemo implements Runnable {// 共享变量private static in…

Chatbox AI|多模型多模态交互+MCP,一个工具打造你的全能私人助手

ChatBoxAI集成GPT-4、Claude等顶尖模型&#xff0c;支持Windows/macOS/Linux多平台&#xff0c;具备隐私加密、文件智能解析&#xff08;PDF/代码/图片&#xff09;及开发者友好特性。其应用覆盖自媒体创作、代码实时预览、AI绘图&#xff08;封面/表情包&#xff09;及联网搜索…

在Autodl服务器中使用VNC建立图形界面

在Autodl服务器中使用VNC建立图形界面**AutoDL 3D 图形桌面搭建教程****第一步&#xff1a;安装桌面和 VNC****第二步&#xff1a;进行一次性配置****第三步&#xff1a;日常启动与使用**AutoDL 3D 图形桌面搭建教程 目标: 在你的 AutoDL 环境上&#xff0c;以最少的步骤搭建一…

CD54.【C++ Dev】vector和list的反向迭代器的实现

目录 1.反向迭代器的功能 2.算法 方法1:新写一个类用于反向迭代器 方法2:封装正向迭代器实现反向迭代器 解析operator* 正向迭代器和反向迭代器的关系 返回 *--tmp的原因 3.为自制的vector和list编写反向迭代器 编写统一的反向迭代器 修改vector头文件 修改list头文…

如何解决pip安装报错ModuleNotFoundError: No module named ‘django’问题

【Python系列Bug修复PyCharm控制台pip install报错】如何解决pip安装报错ModuleNotFoundError: No module named ‘django’问题 摘要 在日常 Django 项目开发中&#xff0c;最常见的“拦路虎”之一就是 ModuleNotFoundError: No module named django。该异常通常在以下场景出…

单页面和多页面的区别和优缺点

单页面应用&#xff08;SPA&#xff09;与多页面应用&#xff08;MPA&#xff09;的区别单页面应用&#xff08;SPA&#xff09;整个应用只有一个HTML文件&#xff0c;内容通过JavaScript动态加载和渲染。页面切换时无需重新加载整个页面&#xff0c;仅更新部分DOM。依赖前端框…

暑期自学嵌入式——Day05(C语言阶段)

接续上文&#xff1a;暑期自学嵌入式——Day04&#xff08;C语言阶段&#xff09;-CSDN博客 点关注不迷路哟。你的点赞、收藏&#xff0c;一键三连&#xff0c;是我持续更新的动力哟&#xff01;&#xff01;&#xff01; 主页&#xff1a; 一位搞嵌入式的 genius-CSDN博客 …

通用人工智能AGI遥遥无期,面临幻灭

通用人工智能AGI有可能2080年前也实现不了 首先说一下&#xff0c;目前的人工智能方向是错的&#xff0c;通用人工智能不值得追捧。 真的特别无奈&#xff0c;现在还有很多人在吹AI&#xff0c;说什么2027年就能实现AGI&#xff0c;如果你指的是真正的强人工智能AGI&#xff0c…

智能体开发工具链全景图:IDE、调试器与监控平台

智能体开发工具链全景图&#xff1a;IDE、调试器与监控平台 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不停歇的探索者。 ✨ 用代码丈量世界&…