ContentExamples —— Niagara_Advanced_Particles

        高级Niagara示例,如Nearest Neighbor queries、simulation stages、iterative constraints、 mesh reproduction、exporting particle data to blueprint 等等;

Simulation Stage Fill Render Target

        在GPU发射器添加Simulation Stages,当前不支持CPU;可将Simulation Stages视为类似”Patricle Update“的额外堆栈(可每帧计算),不同之处在于它可迭代,可在一帧上对其中的所有元素运行多次,可想象成堆栈中的“For循环”;

        "Iteration source"不仅仅是粒子,可迭代Grid 2d collection内的每个单元以创建解算器,迭代render target每个像素以写入,或迭代每个粒子;

 

此案例中没有创建粒子,渲染器的source mode设置为emitter:

  • Emitter Spawn初始化Data Interface类型的变量Texture Sample、Render Target 2D;
  • 在simulation stage,将iteration source设置为Render Target 2D,即迭代其中的每个像素;
    • Render Target 2D索引(即每个纹理像素)除以render tatget size以创建UV,使用该UV采样纹理,在直接填充Render Target;
    • “Exec Index”指的是迭代源元素执行时的序号,即render target cell, grid 2d cell等;
  • Sprite Render的Source Mode为Emitter以创建单个Sprite,添加material parameter/attribute bindings;

 

 

Advect Grid 2D Collection

        Grids的性能完全受限于其分辨率和底层数据的精度;几乎所有Grids都可以采用半浮点精度,几乎不需要使用全浮点精度;

  • Grid2d Collection是一个可保存浮点属性的2d缓冲区数组,可理解为不会移动的矩阵排列粒子(一个粒子对应一个单元格);需设置单元格数量;

 

        首先,在模拟阶段用texture填充Grid 2D Collection,其iteration source是Grid 2D Collection,即希望遍历每个网格单元并执行某些操作;

  • 写入StackContext.RGBA,会自动在 Iteration Source(Grid 2D Collection)上创建Vector4属性,并可在之后读写;
  • 命名空间StackContext会自动转换为目标空间;

        其后,在对Grid 2D Collection的属性RGBA进行扰动,以使纹理显现动画;

        最后,采样Grid 2D Collection,并写入render target;

 

Communicate with External Render Targets

 

        使用用户参数"TextureRenderTargetObject",来读取外部的Render Target;此时会使用用户提供的Render Target,而不再是创建内部的Render Target;Simulation Stage计算的结果也会写回外部的Render Target;此参数可通过以下方式提供:

  • 一个磁盘Render Target 2D;

  • 使用"Set Niagara Variable - Texture Render Target"蓝图;

采样纹理并灰度化处理,最后存于Grid2D Collection属性RGBA;

  • 灰度化即RGB数值相等,且数值不超过1;

模糊Grid2D Collection属性RGBA;

 

注,白色边框是在材质里添加的,不是Simulation Stage内计算的;

Sample GBuffer Attributes

        GBuffer可理解为当前相机内不透明物体的纹理集合;

        在Skeletal Mesh表面采样位置生成粒子,然后采样GBuffer属性(如Base Color、Depth、Roughness、Metallic等)应用于粒子;

  • 将粒子在世界上的位置,转化为在屏幕上的UV;

 

Skeletal Mesh Reproduction

首先在系统节点的生成阶段,创建Particle Attribute Reader类型的属性;

  • Particle Attribute Reader可读取自身或其他发射器中的粒子属性;

 

创建引导粒子,用于对Mesh Reproduction粒子施加影响;

 

创建Mesh Reproduction粒子;

  • 通过Mesh Reproduction粒子与引导粒子的距离,来施加影响;

 

注,如隐藏skeletal Mesh仍需保留动画,设置Always Tick Pose and Refresh Bones;

Distance Field Traversal

让昆虫附着在物体表面:

  • Move to Nearest Distance Field Surface GPU,将空间中的昆虫移动的物体表面;
  • Initial Mesh Orientation,旋转对齐方向(使用Vector to Nearest Surface Normal);

让昆虫沿着物体表面移动:

  • 让移动的昆虫始终附着在表面,且更正速度方向;
  • 更正昆虫旋转方向;

让昆虫躲避光线

  • Ray Trace Distance Field GPU,通过矢量(粒子与光源)与物体是否交叉来判断是否在光源内,需关闭Libary Only;
  • Avoid Cone,用于使粒子偏离聚光灯或其他锥体;

 

Particle Attribute Reader

        Data Interface类型Particle Attribute Reader,识别要读取的粒子时,有两种选择:Index和ID;

  • Index是指定发射器粒子中的索引(范围从0到NumParticles-1);但粒子消亡时,Index可能会发生变化,因此是不稳定的;
  • ID是保持不变,且在系统中的所有发射器中都是唯一的,但在不同的发射器之间可能很难识别;leader粒子需开启ID,在follow粒子使用Get ID at Spawn Index将ID缓存起来;

 

Follow The Leader 1.0

        Leaders发射器粒子围绕原点随机运动,使用Pendulum Constraint保持离原点距离不变;

        Followers发射器粒子跟随Leaders粒子运动且相对位置不变(使用速度);

  • 在粒子生成时,采样并保存Leaders粒子的ID,以在粒子更新阶段仍采样该粒子;使用Random Vector动态输入,生成并保存该随机单位矢量;

 

Spawn Particles From Another Emitter

        Spawn Particles From Other Emitter用于查询其他发射器并设置发射率,Sample Particles From Other Emitter选择并应用其他发射器的属性,两模块是成对出现的;

 

IterativeConstraints

Particles Spawn

  • 将生成的粒子位置依次排列为竖线,利用ExecutionCount、ExecutionIndex;
  • 记录下每个粒子离原点的距离ChainGoalDistanceFromOrigin,前粒子ID号ChainLinkAhead,后粒子ID号ChainLinkAhead;
  • 调整每个粒子的方向,以形成锁链形态;

Particles Supdate

  • 对粒子施加各种力,如Gravity、Curl Noise Force、Wind Force、Drag等;
  • 在Solve Forces and Velocity后,将每个粒子距离约束到开始时的距离;此时粒子还不在一条线上且方向也不正确;

Simulation Stage

  • 通过多次迭代将粒子约束在一条线上且方向正确;

 

Color Copy by Cell

        Neighbor Grid 3D本质上是一种基于位置的哈希查找结构,将空间划分为多个单元格Cell,每个单元格Cell负责管理其内部粒子;

  • 空间划分 (Initialize),将空间划分为指定数量的单元格,每个单元格有唯一索引;
    • Initialize Neighbor Grid 模块;
  • 网格填充 (Fill),根据粒子位置,计算出其所属单元格的索引,并将该粒子的Execution Index存储单元格;
  • 快速查询 (Query),当一个粒子需要查找其邻近粒子时(如检测碰撞),只需查询自己所在的网格单元及其周围相邻的 26 个单元,极大缩小了搜索范围;

        利用数据接口Neighbor Grid 3D,首先存储粒子本身的索引号到所属的单元格,一个单元格可指定多个邻居数;

AddedToGrid = false;

#if GPU_SIMULATION
//根据粒子的世界位置,计算出所属单元格索引
float3 UnitPos;
NeighborGrid.SimulationToUnit(Position, SimulationToUnit, UnitPos);
int3 Index;
NeighborGrid.UnitToIndex(UnitPos, Index.x,Index.y,Index.z);

//验证单元格索引是否有效
int3 NumCells;
NeighborGrid.GetNumCells(NumCells.x, NumCells.y, NumCells.z);

if (Index.x >= 0 && Index.x < NumCells.x && 
    Index.y >= 0 && Index.y < NumCells.y && 
	Index.z >= 0 && Index.z < NumCells.z)
{
    int LinearIndex;
    NeighborGrid.IndexToLinear(Index.x, Index.y, Index.z, LinearIndex);
    int PreviousNeighborCount;
    NeighborGrid.SetParticleNeighborCount(LinearIndex, 1, PreviousNeighborCount);
    int MaxNeighborsPerCell;
    NeighborGrid.MaxNeighborsPerCell(MaxNeighborsPerCell);

    if (PreviousNeighborCount < MaxNeighborsPerCell)
    {
        AddedToGrid = true;

        int NeighborGridLinear;
        NeighborGrid.NeighborGridIndexToLinear(Index.x, Index.y, Index.z, PreviousNeighborCount, NeighborGridLinear);
        int IGNORE;
        NeighborGrid.SetParticleNeighbor(NeighborGridLinear, ExecIndex, IGNORE);
    }		
}
#endif 

        在利用数据接口Neighbor Grid 3D,计算单元格内最近的存储粒子索引号,在通过该索引号获取所需数据如颜色;

NeighborIndex = -1;

#if GPU_SIMULATION

bool Valid;
float neighbordist =  3.4e+38;

//根据粒子的世界位置,计算出所属单元格索引
float3 UnitPos;
NeighborGrid.SimulationToUnit(Position, SimulationToUnit, UnitPos);
int3 Index;
NeighborGrid.UnitToIndex(UnitPos, Index.x,Index.y,Index.z);

//循环单元格内的所有邻居(刚才存储到单元格的粒子索引号),以找到最近的邻居粒子
int MaxNeighborsPerCell;
NeighborGrid.MaxNeighborsPerCell(MaxNeighborsPerCell);

for (int i = 0; i < MaxNeighborsPerCell; ++i)
{
    int NeighborLinearIndex;
    NeighborGrid.NeighborGridIndexToLinear(Index.x, Index.y, Index.z, i, NeighborLinearIndex);
    int CurrNeighborIdx;
    NeighborGrid.GetParticleNeighbor(NeighborLinearIndex, CurrNeighborIdx);

    if (CurrNeighborIdx != -1)
    {
        float3 NeighborPos;
        AttributeReader.GetPositionByIndex<Attribute="Position">(CurrNeighborIdx, Valid, NeighborPos);

        const float3 delta = Position - NeighborPos;
        const float dist = length(delta);

        if( dist < neighbordist )
        {
            neighbordist = dist;
            NeighborIndex = CurrNeighborIdx;
        }
    }  
}    

#endif

 

Dynamic Grid Transform

        Initialize Neighbor Grid 创建一网格并可轻松定义其变换;

Visualize Grid Cells

  • 首先利用Spawn Particles in Grid、Grid Location创建一个单位空间的粒子矩阵(中心点在原点),每个点可看成是单元格的中心,所以需偏移达到正确的单位空间位置;
  • 在通过GridUnitToWorld将单位空间变换到世界空间;
  • 最后还要设置方向UnitToWorldRotationAsQuat;

 

Max Neighbors Per Cell

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值