Niagara_Advanced内容示例 3.1 Color Copy by Cell

在这里插入图片描述

粒子效果

存在类似于框架一样的东西,将空间分为了8块。在大约1s的时间间隔下,粒子会随机出现在着八个格子内,并且在有粒子的每个格子中,又存在一个较大的Sprite粒子和多个较小的Sprite粒子,他们共享着相同的颜色。

Niagara蓝图部分

本系列开始介绍并着重研究一个新的结构——Neighbor Grid 3D,这是一种基于位置的哈希查找结构。

哈希表是什么?简单来讲就是通过键与哈希函数来为对应的数据分配存储位置。哈希表的优势是什么?快速查找。Neighbor Grid 3D即是希望起到这样的作用。它的使用中随时伴随着各种各样的“哈希函数”来进行空间分配和查找。

最后还需要注意一点,即蓝图中透露现在Neighbor Grid 3D仅限于GPU粒子。

回到蓝图中,其中有三个发射器,Grid_Visualizer是负责将Grid 3D显示出来,Grid_Write和Grid_Read是分别负责对Neighbor Grid 3D进行写入和读取的发射器。此外,因为Neighbor Grid 3D需要被两个多个发射器访问,这里将其定义成系统变量(位于System Update里,意味着每一帧都会发生创建和销毁操作,两者中间又发生着访问、渲染等显示相关的操作,由Emitter决定)。

在这里插入图片描述

效果实现分析

我们分别来看三个粒子发射器

Grid_Visualizer——显示Grid 3D

这个发射器和Neighbor Grid 3D的使用关系并不大,更多的是为了将Grid的边界显示出来,作以辅助理解之用。我们这里简要介绍其中的模块。

首先定义了两个Emitter级的参数——GridSize和GridResolution,分别用来控制绘制的Grid的大小(150x150x150,即边长为150的立方体)和分辨率(2x2x2,即总共8个格子)。

在这里插入图片描述

Emitter Update部分,使用的是Spawn Burst Instantaneous,其中的数目是自定义的动态输入模块GridVisualizerCount。

在这里插入图片描述

GridVisualizerCount中的运算,换句话说其实就是6x9,6个面,每个面上9个粒子。

在这里插入图片描述

Particle Spawn阶段的Grid Visualizer Location模块写入了每个粒子的位置Position和RibbonID两个属性,用以定义条带Ribbon渲染器中渲染的顺序(即哪个粒子连接哪个粒子)。

在这里插入图片描述

Grid_Write——写入Neighbor Grid 3D

这个发射器是负责生成立方体内的那些大粒子,并将一些信息写入了Grid 3D中,其中写入信息是在Simulation Stage里完成的。我们重点看这个自定义模块的内容。

在这里插入图片描述

模块主要是读粒子的位置,并将Execution Index数据写入到Grid中。具体来说,主要看其中的两端HLSL代码片段。

在这里插入图片描述

其中World BBox Size是之前定义好的。

在这里插入图片描述

左侧较小的HLSL代码片段中,输入Scale是一个Vector类型,输入的值是Neighbor Grid 3D大小的倒数;输出OutMatrix是一个Matrix类型。

OutMatrix[0][0] = Scale.x;
OutMatrix[1][1] = Scale.y;
OutMatrix[2][2] = Scale.z;
OutMatrix[3][3] = 1.0f;

OutMatrix[1][0] = 0.0f;
OutMatrix[2][0] = 0.0f;
OutMatrix[3][0] = .5f;

OutMatrix[0][1] = 0.0f;
OutMatrix[2][1] = 0.0f;
OutMatrix[3][1] =.5f;

OutMatrix[0][2] = 0.0f;
OutMatrix[1][2] = 0.0f;
OutMatrix[3][2] = .5f;

OutMatrix[0][3] = 0.0f;
OutMatrix[1][3] = 0.0f;
OutMatrix[2][3] = .5f;

其实就是用Scale构建了一个矩阵
O u t M a t r i x = ( 1 / 150 0 0 0 0 1 / 150 0 0 0 0 1 / 150 0.5 0.5 0.5 0.5 1 ) \mathbf{OutMatrix} = \begin{pmatrix} 1/150 & 0 & 0 & 0 \\ 0 & 1/150 & 0 & 0\\ 0 & 0 & 1/150 & 0.5\\ 0.5 & 0.5 & 0.5 & 1\\ \end{pmatrix}\\ OutMatrix=1/150000.501/15000.5001/1500.5000.51
较大的HLSL代码片段中,输入有NeighborGrid,即我们读取的Neighbor Grid 3D,Position是粒子的Position,SimulationToUnit是上面的OutMatrix矩阵,ExecIndex是当前粒子的索引。具体解读见代码注释

AddedToGrid = false;

#if GPU_SIMULATION

//求出粒子的位置转化为的在Grid 3D中的位置(单位位置,相当于世界空间转局部空间,再将局部坐标做一个归一化)
// Derive the Neighbor Grid Index from the world position
float3 UnitPos;
NeighborGrid.SimulationToUnit(Position, SimulationToUnit, UnitPos);

//将粒子的单位位置转化为所在格子的索引
int3 Index;
NeighborGrid.UnitToIndex(UnitPos, Index.x,Index.y,Index.z);

// Verify that the derived index is valid.
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)
{
    //将三维的索引转化为1维索引(目的都是为了用索引确定唯一的一个格子)
    int LinearIndex;
    NeighborGrid.IndexToLinear(Index.x, Index.y, Index.z, LinearIndex);
	
    //当前该索引下的格子所拥有的属性之一Neighbor Count自增1表示,格子自生所能容纳的信息数+1(Neighbor即是信息的容器,在本例中,可以简单得理解为大粒子,即一个格子中有几个大粒子,就存了几个Neighbor)。
    // Increment the neighbor count for this cell. This records the number of overlaps
    // and can return a higher count than the MaxNeighborsPerCell
    int PreviousNeighborCount;
    NeighborGrid.SetParticleNeighborCount(LinearIndex, 1, PreviousNeighborCount);
	
    //每个格子所能存储的最多信息数,是我们自己设定好的
    int MaxNeighborsPerCell;
    NeighborGrid.MaxNeighborsPerCell(MaxNeighborsPerCell);
	
    //当我们增加的Neighbor Count超过了所能容纳的最大值时,就不再继续往里塞东西了。
    // Limit the number of neighbors added to each cell
    if (PreviousNeighborCount < MaxNeighborsPerCell)
    {
        AddedToGrid = true;
		
        //此时,我们可以通过Index找到格子,但是怎么找到某一个存进去的Neighbor,所以需要给这个新人Neighbor一个Index索引(一维的)
        int NeighborGridLinear;
        NeighborGrid.NeighborGridIndexToLinear(Index.x, Index.y, Index.z, PreviousNeighborCount, NeighborGridLinear);
		
        //本例中,是将ExecIndex信息,存入了Neighbor
        int IGNORE;
        NeighborGrid.SetParticleNeighbor(NeighborGridLinear, ExecIndex, IGNORE);
    }		
}
#endif    

迭代的结果就是,Grid_Write这帧的这些粒子被分别写入了不同的格子当中(其中如果有某个格子满了,就不再往那个格子里塞了)。

是不是看得有点懵。我们模拟一下,现在要弄清楚靠前面的左上角的格子存了一个什么信息,怎么查?首先搞清楚这个格子的索引,假如是1,那么要继续在这个索引是1的格子内部看看它存了多少信息,打开一看Neighbor Count是2,是2个Neighbor信息,再仔细看看索引是?的Neighbor里放的是什么,哇,原来是个ExecIndex,是某个粒子的执行索引啊。那么我们拿到这个执行索引可以干嘛呢?这就是后面Grid_Read里完成的工作了。

Grid_Read

对Neighbor Grid 3D的读取还伴随着粒子属性的读取(Particle Attribute Reader),最终通过Sumulation Stage : Query Grid来完成整合。其中主要是两个自定模块——Find Closest Neighbor和Copy Color。

在这里插入图片描述

Find Closest Neighbor做的事情就是找到距离当前粒子最近的那个格子所存储的Neighbor中的那个ExecIndex。

在这里插入图片描述

NeighborIndex = -1;

#if GPU_SIMULATION

bool Valid;

//找到粒子所在的格子的索引
// Derive the Neighbor Grid Index from the world position
float3 UnitPos;
NeighborGrid.SimulationToUnit(Position, SimulationToUnit, UnitPos);

int3 Index;
NeighborGrid.UnitToIndex(UnitPos, Index.x,Index.y,Index.z);

// Initialize the closest distance to a really large number
float neighbordist =  3.4e+38;

// loop over all neighbors in this cell
int MaxNeighborsPerCell;
NeighborGrid.MaxNeighborsPerCell(MaxNeighborsPerCell);

//遍历找到的格子中所有的Neighbor
for (int i = 0; i < MaxNeighborsPerCell; ++i)
{
    // Find the ExecIndex for the current neighbor particle
    
    //从0到最大,挨个翻开来看里面是不是存了东西
    int NeighborLinearIndex;
    NeighborGrid.NeighborGridIndexToLinear(Index.x, Index.y, Index.z, i, NeighborLinearIndex);
	
    //把里面村的东西拿出来赋予到当前变量上
    int CurrNeighborIdx;
    NeighborGrid.GetParticleNeighbor(NeighborLinearIndex, CurrNeighborIdx);

    // Only proceed if the returned index is valid. This is most often triggered
    // by there being fewer neighbors in the cell than the MaxNeighborsPerCell limit.
    if (CurrNeighborIdx != -1)
    {
        // Use the Attribute Reader to query the position of the neighbor particle
        float3 NeighborPos;
        //通过Attribute Reader以及拿到的ExecIndex来查询里面粒子的位置,写入到上面的变量里
        AttributeReader.GetVectorByIndex<Attribute="Position">(CurrNeighborIdx, Valid, NeighborPos);

        // Compare the distance found maintaining the closest
        const float3 delta = Position - NeighborPos;
        const float dist = length(delta);
		//跌打查找距离当前粒子最近的那个存入的Neighbor粒子
        if( dist < neighbordist )
        {
            neighbordist = dist;
            NeighborIndex = CurrNeighborIdx;
        }
    }  
}    

#endif

这个模块输出一个NeighborIndex,在上面的代码中,已经用其进行了一次位置查找,后面的Copy Color其实是一样的,是做了一次颜色查找,过程更为简单。

在这里插入图片描述

总结

本例已经是涉及到一些高级的数据结构,和代码语言,单单看表层代码已经很难去理解代码片段的功能了。所以此次的话借助了源码,即通过联系代码中的上下文(包括代码和注释),找到函数的用途和功能,从而帮助理解。

### 回答1: 《niagara_4_developercourse_labexercises.pdf》是一份关于Niagara 4开发者课程实验练习的PDF文件。Niagara 4是特尔斯控制系统公司开发的一款用于建筑自动化的软件平台,旨在提供集成管理各种设备和技术的解决方案。这份文件可能包含了一系列实验练习,旨在帮助学习者掌握Niagara 4的开发和配置技巧。 这些实验练习可能涉及不同的主题,包括系统架构、设备配置、图形界面设计、数据收集与分析等。学习者可能需要按照指导进行一系列的实验任务,通过实践来熟悉Niagara 4的各项功能和工具。这些实验练习可以帮助学习者了解如何使用Niagara 4平台来创建自定义的控制策略、设置定时任务、监视和控制设备,以及收集和分析数据等。 通过完成这些实验练习,学习者可以获得对Niagara 4开发和配置过程的实际经验,并加深对系统的理解。这份文件可能包含了实验指南、示例代码、实验结果分析等各种信息,以便学习者能够按照指导顺利完成实验任务。 总之,《niagara_4_developercourse_labexercises.pdf》是一份提供Niagara 4开发者课程实验练习的文件,通过完成其中的实验任务,学习者可以提高他们在Niagara 4平台上开发和配置的能力。 ### 回答2: niagara_4_developercourse_labexercises.pdf 是一份开发者课程实验练习的文档。 这份文档主要是针对Niagara 4开发者课程中的实验练习而编写的。Niagara 4是一种基于Tridium公司的框架和平台,用于建立和管理建筑自动化系统。开发者课程旨在帮助开发人员深入了解Niagara 4的功能和特性,并提供实践的机会来掌握其开发技术。 在这份文档中,会列出一系列的实验练习,帮助开发者逐步学习和实践Niagara 4的开发过程。每个实验练习都会有详细的步骤和指导,包括设置环境、创建项目、编写代码等等。开发者需要按照文档的指示一步步地完成每个实验,同时还需要理解实验的目的和背景。 这份文档的目的是帮助开发者通过实践加深对Niagara 4的理解和掌握。通过每个实验的完成,开发者可以逐步提升其在Niagara 4开发方面的技能。实验的内容涵盖了不同的主题和技术,包括系统建模、设备接入、数据处理等等。 总之,niagara_4_developercourse_labexercises.pdf 是一份Niagara 4开发者课程的实验练习文档,通过实践完成每个实验,开发者可以逐步提升其在Niagara 4开发方面的能力和技术。 ### 回答3: "niagara_4_developercourse_labexercises.pdf" 是一个文件名,可能是一个包含关于 Niagara 4 开发者课程实验练习的 PDF 文件。 在这个文件中可能包含了一些与 Niagara 4 开发相关的实验练习,供开发人员使用。该 PDF 可能包含了一些说明、指导或教程,以帮助开发人员学习和实践 Niagara 4 系统的开发技术。这些实验练习可能涉及到创建和配置 Niagara 4 网络、开发自定义应用程序、编写 Niagara 4 控制程序等。 对于想要学习并使用 Niagara 4 技术的开发人员来说,这个文件应该是一个很有用的资源。通过完成其中的实验练习,开发人员可以加深对 Niagara 4 系统的理解,掌握相关的开发技能,并在实际项目中应用这些技能。 需要注意的是,为了更好地利用这个文件,开发人员可能需要先了解基本的 Niagara 4 系统知识和开发概念。此外,建议开发人员按照文件中的顺序逐个完成实验练习,以获得更好的学习效果。 总而言之,“niagara_4_developercourse_labexercises.pdf” 是一个帮助开发人员学习 Niagara 4 系统开发技术的实验练习文件,对于想要学习并应用 Niagara 4 的开发人员来说是一份有价值的资源。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Claude的羽毛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值