UE5.5 PCGFrameWork--GPU CustomHLSL

在上一篇UE5.5 PCGFrameWork使用入门-CSDN博客 大致介绍了UE5 PCG框架的基本使用.

本篇探索PCGFrame的高级应用--GPU点云。也就是利用GPU HLSL编程对点云进行操纵,可以大幅度提升点云生成效率。

目前在UE5 PCG框架中,点云GPU的应用大致分为三类: PointGenerator, PointProcessor, Custom

GPU节点

三种模式下是同一个节点,只是选择模式,GPU变量预声明,GPU函数等存在一些差别。

SourceEditor

SourceEditor可以打开相应模式下的GPU,可以看到预先声明变量和各种公用函数。

PointGenerator

预先生成的点云函数和变量

预生成数量

预定义生成点云的数量,

在GPU HLSL NumPoints和ElementIndex

输入声明(Input Declartions)

由节点的输入类型和名字动态决定来生成相应输入函数,可以用来在GPU获取点云,地形,纹理等数据,类型有下面几种

比如增加一个点云输入和地形数据输入

预先生成输入代码:

下面具体分析每种类型输入的相应简单使用

点云输入

"InPosition"名的点云输入

cpp 复制代码
/*** INPUT DATA FUNCTIONS ***/

uint InPosition_GetNumData();
uint InPosition_GetNumElements();
uint InPosition_GetNumElements(uint DataIndex);

// Valid types: bool, int, float, float2, float3, float4, Rotator (float3), Quat (float4), Transform (float4x4), StringKey (int), Name (uint2)

<type> InPosition_Get<type>(uint DataIndex, uint ElementIndex, int AttributeId);
<type> InPosition_Get<type>(uint DataIndex, uint ElementIndex, 'AttributeName');

/*** INPUT POINT DATA FUNCTIONS ***/

float3 InPosition_GetPosition(uint DataIndex, uint ElementIndex);
float4 InPosition_GetRotation(uint DataIndex, uint ElementIndex);
float3 InPosition_GetScale(uint DataIndex, uint ElementIndex);
float3 InPosition_GetBoundsMin(uint DataIndex, uint ElementIndex);
float3 InPosition_GetBoundsMax(uint DataIndex, uint ElementIndex);
float4 InPosition_GetColor(uint DataIndex, uint ElementIndex);
float InPosition_GetDensity(uint DataIndex, uint ElementIndex);
int InPosition_GetSeed(uint DataIndex, uint ElementIndex);
float InPosition_GetSteepness(uint DataIndex, uint ElementIndex);
float4x4 InPosition_GetPointTransform(uint DataIndex, uint ElementIndex);
bool InPosition_IsPointRemoved(uint DataIndex, uint ElementIndex);

这里暂时不清楚NumData意义,可以确定的并不是点云数量

这里的Type代表你获取数据的类型, 而ElementIndex代码第N个点云,DataIndex暂时推荐都使用0.

InPosition_GetNumElements

获取输入点云的数量

InPosition_Get<type>

这里是获取第N个点云的相应属性, 这里有两种方法

1\]通过属性序号来获取 ```cpp InPosition_Get(uint DataIndex, uint ElementIndex, int AttributeId); ``` 案例: 获取输入的第2个点云的位置,Position的AttributeId为0 ```cpp float3 Position = InPosition_GetFloat3(0, 1, 0); ``` \[2\]一种是通过属性名字来获取 ```cpp InPosition_Get(uint DataIndex, uint ElementIndex, 'AttributeName'); ``` 案例: 获取输入的第2个点云的位置,Position的名字为'$Position', 注意**单引号和$字符前缀** 否则会报语法错误.当然类型映射措辞和属性名字不存在也会报语法错误. ![](https://i-blog.csdnimg.cn/direct/f9013eec105443d6b50221929b46b2c8.png) ```cpp float3 Position = InPosition_GetFloat3(0, 0, '$Position'); ``` ##### InPosition_GetXXX 这里比较容易理解,直接获取点云各种属性(位置,缩放,旋转,Color, Bound等等)。 ```cpp float3 InPosition_GetPosition(uint DataIndex, uint ElementIndex); float4 InPosition_GetRotation(uint DataIndex, uint ElementIndex); float3 InPosition_GetScale(uint DataIndex, uint ElementIndex); float3 InPosition_GetBoundsMin(uint DataIndex, uint ElementIndex); float3 InPosition_GetBoundsMax(uint DataIndex, uint ElementIndex); float4 InPosition_GetColor(uint DataIndex, uint ElementIndex); float InPosition_GetDensity(uint DataIndex, uint ElementIndex); int InPosition_GetSeed(uint DataIndex, uint ElementIndex); float InPosition_GetSteepness(uint DataIndex, uint ElementIndex); float4x4 InPosition_GetPointTransform(uint DataIndex, uint ElementIndex); bool InPosition_IsPointRemoved(uint DataIndex, uint ElementIndex); ``` #### 地形输入 "Landscape"名的地形输入 ![](https://i-blog.csdnimg.cn/direct/496ee2742a7447bca84abd7d27688e79.png) ```cpp float Landscape_GetHeight(float3 WorldPos); float3 Landscape_GetNormal(float3 WorldPos); ``` 这里不用解释太多,就是根据WorldPos采样地形的高度和法线等属性 #### 纹理输入 "Texture"名的纹理输入 ![](https://i-blog.csdnimg.cn/direct/65b8272ae58348cabfab37855bbc6a37.png) ```cpp float2 Texture_GetTexCoords(float2 WorldPos, float2 Min, float2 Max); float4 Texture_Sample(uint DataIndex, float2 TexCoords); // Computes sample coordinates of the WorldPos relative to the texture data's bounds.float4 Texture_SampleWorldPos(uint DataIndex, float2 WorldPos); ``` 案例: 在一个PCG Volume的Grid2D点云设置相应的纹理值为点云缩放 ```cpp float3 Min = GetComponentBoundsMin(); // World-space float3 Max = GetComponentBoundsMax(); // World-space float3 InPosition = CreateGrid2D(ElementIndex, NumPoints, Min, Max); float2 UV = Texture_GetTexCoords(float2(InPosition.x, InPosition.y), Min, Max); float4 SampleValue = Texture_Sample(0, UV); Out_SetScale(Out_DataIndex, ElementIndex, float3(SampleValue.x, SampleValue.x, SampleValue.x)); Out_SetPosition(Out_DataIndex, ElementIndex, InPosition); ``` #### AttributeSet ### 输出函数(Output Declarations) ```cpp /*** OUTPUT DATA FUNCTIONS ***/ // Valid types: bool, int, float, float2, float3, float4, Rotator (float3), Quat (float4), Transform (float4x4), StringKey (int), Name (uint2) void Out_Set(uint DataIndex, uint ElementIndex, int AttributeId, Value); void Out_Set(uint DataIndex, uint ElementIndex, 'AttributeName', Value); /*** OUTPUT POINT DATA FUNCTIONS ***/ void Out_InitializePoint(uint DataIndex, uint ElementIndex); void Out_CopyElementFrom_(uint TargetDataIndex, uint TargetElementIndex, uint SourceDataIndex, uint SourceElementIndex); bool Out_RemovePoint(uint DataIndex, uint ElementIndex); void Out_SetPosition(uint DataIndex, uint ElementIndex, float3 Position); void Out_SetRotation(uint DataIndex, uint ElementIndex, float4 Rotation); void Out_SetScale(uint DataIndex, uint ElementIndex, float3 Scale); void Out_SetBoundsMin(uint DataIndex, uint ElementIndex, float3 BoundsMin); void Out_SetBoundsMax(uint DataIndex, uint ElementIndex, float3 BoundsMax); void Out_SetColor(uint DataIndex, uint ElementIndex, float4 Color); void Out_SetDensity(uint DataIndex, uint ElementIndex, float Density); void Out_SetSeed(uint DataIndex, uint ElementIndex, int Seed); void Out_SetSteepness(uint DataIndex, uint ElementIndex, float Steepness); void Out_SetPointTransform(uint DataIndex, uint ElementIndex, float4x4 Transform); ``` 设置输出点云数据的各种函数(虽然Ouput引脚支持各种类型,暂时只发现只有Point类型可以输出) 这里和上面的输入函数用法基本一致。主要解释一个特殊函数: **Out_RemovePoint(Out_DataIndex, ElementIndex);** 这个函数用于移除某个ElementIndex的点云 代码例子: 移除ElementIndex为3的整数倍的点云 ```cpp if(ElementIndex % 3 == 0) Out_RemovePoint(Out_DataIndex, ElementIndex); ``` ### 辅助函数(Helper Declarations) ```cpp /*** HELPER FUNCTIONS ***/ int3 GetNumThreads(); uint GetThreadCountMultiplier(); // Returns false if thread has no data to operate on. // Valid pins: InPosition, Landscape, Texture, Out bool _GetThreadData(uint ThreadIndex, out uint OutDataIndex, out uint OutElementIndex); float3 GetComponentBoundsMin(); // World-space float3 GetComponentBoundsMax(); uint GetSeed(); float FRand(inout uint Seed); // Returns random float between 0 and 1. uint ComputeSeed(uint A, uint B); uint ComputeSeed(uint A, uint B, uint C); uint ComputeSeedFromPosition(float3 Position); // Returns the position of the Nth point in a 2D or 3D grid with the given constraints. float3 CreateGrid2D(int ElementIndex, int NumPoints, float3 Min, float3 Max); float3 CreateGrid2D(int ElementIndex, int NumPoints, int NumRows, float3 Min, float3 Max); float3 CreateGrid3D(int ElementIndex, int NumPoints, float3 Min, float3 Max); float3 CreateGrid3D(int ElementIndex, int NumPoints, int NumRows, int NumCols, float3 Min, float3 Max); ``` #### GetComponentBoundsMin和GetComponentBoundsMax 获取PCG Volume的BoundMin, BoundMax ![](https://i-blog.csdnimg.cn/direct/96ccbe0b100649dab5b0612a7ee5356b.png) #### 随机函数 ```cpp uint GetSeed(); float FRand(inout uint Seed); // Returns random float between 0 and 1. uint ComputeSeed(uint A, uint B); uint ComputeSeed(uint A, uint B, uint C); uint ComputeSeedFromPosition(float3 Position); ``` 和随机种子和随机值密切相关的一组函数,非常常见的配套函数. GetSeed函数获取的种子来自节点面板: ![](https://i-blog.csdnimg.cn/direct/e66f35e714d74057b5521d5d709d1165.png) #### 创建Grid点云函数 ```cpp // Returns the position of the Nth point in a 2D or 3D grid with the given constraints. float3 CreateGrid2D(int ElementIndex, int NumPoints, float3 Min, float3 Max); float3 CreateGrid2D(int ElementIndex, int NumPoints, int NumRows, float3 Min, float3 Max); float3 CreateGrid3D(int ElementIndex, int NumPoints, float3 Min, float3 Max); float3 CreateGrid3D(int ElementIndex, int NumPoints, int NumRows, int NumCols, float3 Min, float3 Max); ``` 一组可以让用户快速创建Grid(2D或者3D)点云的函数 演示一个案例: 创建400个 行数为10的Grid 2D点云 使用 ```cpp float3 CreateGrid2D(int ElementIndex, int NumPoints, int NumRows, float3 Min, float3 Max); ``` ![](https://i-blog.csdnimg.cn/direct/69fdbd19375a4a2083f7546992e4842c.png) **完整代码:** ```cpp float3 Min = GetComponentBoundsMin(); // World-space float3 Max = GetComponentBoundsMax(); // World-space float3 InPosition = CreateGrid2D(ElementIndex, NumPoints, 10, Min, Max); Out_SetPosition(Out_DataIndex, ElementIndex, InPosition); ``` **演示效果:** ![](https://i-blog.csdnimg.cn/direct/25e3e97ef6b44243826aa3ad0747e64e.png) ### 自定义函数(ShaderFunction) ![](https://i-blog.csdnimg.cn/direct/49bacde4cfa44bf5ba5a67a2592f76f6.png) 用户自定义函数,如何生成各种分形点云,各种自定义几何形状分布的点云等等 ### 演示Demo: 生成一个以某点位置为中心的贴地形点云圆圈 ![](https://i-blog.csdnimg.cn/direct/d608f7e111a24d2ca74d3fe5d64a6e82.png) ![](https://i-blog.csdnimg.cn/direct/5f0c90b96ec442509b6c276381efb869.png) ![](https://i-blog.csdnimg.cn/direct/ff6e5059f365420fbc30c355512c1b4b.png) #### GPU代码相关 ##### **Shader Function** ```cpp /** CUSTOM SHADER FUNCTIONS **/ float3 CreateCircle2D(uint ElementIndex, int NumPoints, float3 Center, float Radius) { // 计算角度(均匀分布) float Angle = 2 * 3.14159265358979323846 * ElementIndex / NumPoints; // 极坐标转笛卡尔坐标 float X = Center.x + Radius * cos(Angle); float Z = Center.y + Radius * sin(Angle); return float3(X, Z, 0); } ``` ##### **Shader Source** ```cpp float3 InPosition = InPosition_GetFloat3(0, 0, 0); float3 Position = CreateCircle2D(ElementIndex, NumPoints, InPosition, 3000.0); float Height = Landscape_GetHeight(Position); Position.z = Height; Out_SetPosition(Out_DataIndex, ElementIndex, Position); ``` #### 运行Demo效果 跟随PCG Actor移动的贴地点云圆圈 ![](https://i-blog.csdnimg.cn/direct/6c8dd69a37b64c61b7a7eca5c725c944.png) ## PointProcessor和Custom 目前看PointProcessor和Custom像PointGenerator除了无法预定义点云数量, 暂时看不出什么和PointGenerator存在什么区别 ![](https://i-blog.csdnimg.cn/direct/aa88c853afa8454bb585608e80044597.png) ## 参考资料 \[1\][PCG: Advanced Topics \& New Features in UE 5.5 \| Unreal Fest 2024](https://www.youtube.com/watch?v=j3ke6MmcaeY&t=108s "PCG: Advanced Topics & New Features in UE 5.5 | Unreal Fest 2024") \[2\][Unreal Engine 5.5 - Compute Shaders With PCG Introduction (Height Thresholding in HLSL)](https://www.youtube.com/watch?v=4EnCsJvcIbA "Unreal Engine 5.5 - Compute Shaders With PCG Introduction (Height Thresholding in HLSL)") \[3\][Unreal Engine 5.5 - PCG Compute Introduction (Fractals in HLSL)](https://www.youtube.com/watch?v=VKx3Jfp56RE "Unreal Engine 5.5 - PCG Compute Introduction (Fractals in HLSL)") \[4\][Directx11入门教程四十八之小议ComputeShader_dx11 dispatch-CSDN博客](https://blog.csdn.net/qq_29523119/article/details/81024907 "Directx11入门教程四十八之小议ComputeShader_dx11 dispatch-CSDN博客")

相关推荐
书鸢12365 小时前
UE5中 Character、PlayerController、PlayerState、GameMode和GameState核心类之间的联动和分工·
ue5
金米kk19 小时前
Unreal Engine 5(虚幻引擎)动画制作快捷键大全
ue5·游戏引擎·虚幻
avi91111 天前
UE4-UE5虚幻引擎,前置学习一--Console日志输出经常崩溃,有什么好的解决办法
ue5·ue4·虚幻·日志
远离UE42 天前
UE5 RVT 制作场景交互 - 遮罩
ue5
lcw_lance3 天前
UE5与U3D引擎对比分析
ue5·数字孪生
妙为3 天前
要在Unreal Engine 5(UE5)中实现角色打击怪物并让怪物做出受击反应,
ue5·敌人受击效果·打击感
爱编程的鱼4 天前
UE5.4分层渲染设置
前端·ue5
Dawn·张4 天前
UE小:UE5.5 PixelStreamingInfrastructure 使用时注意事项
ue5
Maya动画技术7 天前
ue5.5崩溃报gpu错误快速修复注册表命令方法
ue5·ue5.5崩溃报gpu错误
每天回答3个问题9 天前
AI数字人| Fay开源项目、UE5数字人、本地大模型
人工智能·python·ue5·开源·游戏引擎