粒子效果

场景中有一个纹理和一个模型(应用了Unreal Engine 4的logo),但是没有Niagara粒子的标识符。这次展示出来的是一个Actor蓝图类,里面包含了两个组件,UNiagaraComponent和StaticMeshComponent,分别对应了我们看见的纹理和模型。

Actor蓝图类的构造脚本(Construction Script)里,首先创建Render Target 2D(256*256),然后将这个返回值设置为Niagara中一个变量(Variable)的引用,这个变量名字是TextureRenderTargetObject;随后为我们的StaticMesh(是一个平面)创建动态材质实例,最后再以Render Target 2D的值作为材质实例中纹理参数的值。

这里执行的操作其实就是将Render Target 2D作为外部变量传入Niagara系统(之前都是在Niagara内部创建Render Target 2D,而这里是要让Niagara内部创建的Render Target 2D引用外部创建的这个),在Niagara系统里对它进行一顿操作,再把用一个材质把操作过后的Render Target 2D在静态网格体上显示出来。

我们打开引用的Niagara System来看看内部发生了什么。

Niagara蓝图部分

可以看到,发射器部分和之前1.2中的例子在结构上非常相似,都是用Emitter级别的属性进行渲染。在Simulation Stage里,亦是三个阶段:Fill Grid with Texture,Blur Grid,Fill Render Target with Grid。其中Blur Grid是对纹理(Gird中的数据)的模糊化处理。

效果实现分析

前面说过,Actor蓝图类在Niagara外部创建了一个Render Target 2D(256*256),并将返回值传入Niagara系统中的变量TextureRenderTargetObject。这个变量是我们自己创建的,位于USER命名空间下的一个只读的属性,所以我们才需要用一个Render Target 2D作为接口,从而可编辑其中的值。需要注意的是,Niagara里创建的这个Render Target 2D尺寸是512,与传入的尺寸不同,Niagara会自动做这个适应性的调整(即以512为准)。

Fill Grid with Texture,用纹理数据填充Grid2D Collection。值得注意的是,这里的Emitter Reset Only勾选,意味着这个阶段只会在每次Emitter重置之后才会运行,也就不会让这里的采样结果在后续干扰模糊操作的显示。

Execution Index to Unit构建UV,乘以1.5将范围拉伸到01.5(原先采1的跑去采1.5了,原先采0.66的跑来采1了),减去0.25范围下降为-0.251.25(最原先采1到跑去采1.25了,最原先采0.83的跑来采1了),再Clamp一下取到0~1(掐头去尾可以吃了,最原先采0.83的跑去采1了,最远先采0.16的跑来采0了),这样相当于对纹理进行了缩小(可以理解成一张图片,画框大小不变,你把它从中心缩小,从中心用画框截取)。之后再作一个灰度处理,得到两个float值(一个代表RGB,一个代表A,即透明度值),存储在该Grid2D Collection的属性中(次级属性,命名空间是STACKCONTENT)。

未缩小的画和缩小的画(画框大小不变)。

Blur Grid,是对纹理进行的模糊处理。我们先看看这段HLSL的代码各个输入:Blurred Grid即是Grid2D Collection,TickCount是系统的帧计数,Unit是用来描述当前正在处理Grid2D Collection上的哪一个Cell,Index X和Index Y分别是当前整个Cell的横纵Index,dxdy是横向宽度和纵向长度的倒数,StageIterations代表了当前所处的迭代数。

细看HLSL代码片段,我尽可能得添加了注释(中文部分)

//每次迭代进来要重新初始化这两个值
OutputUnitGrid =  float2(0,0);
OutputBlurGrid =  float2(0,0);#if GPU_SIMULATION//一些局部变量(作用域就是这个片段)
float2 Offsets = float2(0.5, -0.5);
StageIterations += 1;//
float2 Outputs[4];
float2 Taps[4];
float2 CornerTap;//是对前一帧的值进行采样,即取到Grid2D Collection前一帧的FloatPlusAlpha属性值,怎么采呢?根据Unit传入的位置信息,最后输出到OutputUnitGrid
Grid2DCollection.SampleGridVector2Value<Attribute=FloatPlusAlpha>(Unit,  OutputUnitGrid);//就是(1/512,1/512) * StageIterations
// For each iteration, reach a little further out to neighboring texels
CornerTap = dxdy * StageIterations;//随着迭代层数的增加,StageIterations越来越大,这四个位置的Taps值也会越来越大(意味着越来越深/长/距离采样点越远)//左上角,(1/512,1/512) * StageIterations * (-0.5,-0.5)
Taps[0] = CornerTap * Offsets.yy;
//右上角,(1/512,1/512) * StageIterations * (0.5,-0.5)
Taps[1] = CornerTap * Offsets.xy;
//左下角,(1/512,1/512) * StageIterations * (-0.5,0.5)
Taps[2] = CornerTap * Offsets.yx;
//右下角,(1/512,1/512) * StageIterations * (0.5,0.5)
Taps[3] = CornerTap * Offsets.xx;// Sample our four corners, average the samples.
//向Grid2D Collection中正在进行的采样点的四个边角进行采样(FloatPlusAlpha),得到的值输出到Output里
Grid2DCollection.SampleGridVector2Value<Attribute=FloatPlusAlpha>(Unit+Taps[0],  Outputs[0]);
Grid2DCollection.SampleGridVector2Value<Attribute=FloatPlusAlpha>(Unit+Taps[1],  Outputs[1]);
Grid2DCollection.SampleGridVector2Value<Attribute=FloatPlusAlpha>(Unit+Taps[2],  Outputs[2]);
Grid2DCollection.SampleGridVector2Value<Attribute=FloatPlusAlpha>(Unit+Taps[3],  Outputs[3]);//取四个边角采样值的平均值,输出到OutputBlurGrid里
OutputBlurGrid += (Outputs[0]+Outputs[1]+Outputs[2]+Outputs[3]) / 4;
if (TickCount <= 1)
{//TickCount是系统的计时器,
}
else
{
OutputBlurGrid = OutputUnitGrid;
}//如果是从点下Save/Apply那一刻起的第一帧,以OutputBlurGrid(总共走8个循环后)设置FloatPlusAlpha属性;后面的每帧输出OutputUnitGrid(对第八帧的FloatPlusAlpha采样,是经历了8层模糊循环后的结果),以保持一个恒定的模糊度。
//这也就是为什么Fill Grid with Texture要勾选Emitter Reset Only,否则如果Fill Grid with Texture每帧更新的话,会刷掉已近写过的FloatPlusAlpha值,就意味着要输出未被模糊的结果
Grid2DCollection.SetVector2Value<Attribute=FloatPlusAlpha>(IndexX, IndexY,  OutputBlurGrid);#endif

Fill Render Target with Grid,将Grid2D Collection的数据写入到Render Target 2D里。

最后再通过材质参数绑定写入到材质纹理中(这样就得到了最开始那副效果图中左侧的那个纹理(实际上Niagara Emitter级的Sprite粒子))。

而右侧的那个StaticMesh上的纹理则是通过读到其上的材质纹理参数,再用Render Target对这个参数进行赋值。还记得开局Actor蓝图中的那两个节点吗(下图)?此时蓝图中创建的Render Target已经经过了Niagara System里的一些列计算并赋了模糊化后的值,这些值又要传入NiagaraRT这个参数里。

材质中的这个参数的B值决定了这个材质的Emissive Color和顶点的偏移值,所以才会有凸起的效果。

总结

本例中涉及的知识点相当得驳杂,当时我还是尽力将其全部梳理了出来(蓝图和Niagara数据传递,材质,模糊卷积算法(不算是完全的卷积),系统数据更新等等)。其中甚至一些点我之前都没有了解过,比如说我在TickCount的作用上纠结了比较久。最后还是多个概念的综合理解、结合蓝图和代码的上下文才将流程梳理通畅。

Niagara_Advanced内容示例 1.3 Communicate with External Render Targets相关推荐

  1. Niagara_Advanced内容示例 1.2 Advect Grid 2D Collection

    粒子效果 这个例子主要由三部分组成:上边悬于空中.始终面向相机的Unreal Engine 4的黑白Logo,它还会受到某种噪声的影响向四周扭曲:地面上贴着的两张纹理图片,左侧类似于一张迷宫图,但是斜 ...

  2. Niagara_Advanced内容示例 1.5 Skeletal Mesh Reproduction

    粒子效果 中心是一个人物模型,似乎也是由粒子贴片而成的.此外还有一些发光粒子,在无规则运动,不时会撞击到模型上,导致模型裂开成一些粒子.这些散落的粒子被撞击裂开后,会逐渐恢复原先在模型上的位置. Ni ...

  3. js动态改变下拉菜单内容示例 .

    <HTML><HEAD><TITLE>动态改变下拉菜单内容示例</TITLE></HEAD><SCRIPT LANGUAGE=java ...

  4. python用方括号提取字符中的数值_Python使用re模块正则提取字符串中括号内的内容示例...

    Python使用re模块正则提取字符串中括号内的内容示例 本文实例讲述了Python使用re模块正则提取字符串中括号内的内容操作.分享给大家供大家参考,具体如下: 直接上代码吧: # -*- codi ...

  5. python爬去新浪微博_Python爬虫爬取新浪微博内容示例【基于代理IP】

    Python爬虫爬取新浪微博内容示例[基于代理IP] 发布时间:2020-09-07 10:08:14 来源:脚本之家 阅读:120 本文实例讲述了Python爬虫爬取新浪微博内容.分享给大家供大家参 ...

  6. Python使用re模块正则提取字符串中括号内的内容示例

    Python使用re模块正则提取字符串中括号内的内容示例 这篇文章主要介绍了Python使用re模块正则提取字符串中括号内的内容,结合实例形式分析了Python使用re模块进行针对括号内容的正则匹配操 ...

  7. 学习Cascade粒子系统:观察内容示例所展示的特性

    目标 内容示例中有展示粒子特效的场景: 目标是观察场景中几个范例想要展示的是粒子系统的哪个功能,并尝试了解如何操作.需要注意的是:由于并没有实际用资源复现一遍,所以很可能有疏漏之处,即有些效果的实现还 ...

  8. python修改html内容_详解Python利用Beautiful Soup模块修改内容示例代码

    Beautiful Soup是一个可以从HTML或XML文件中提取数据的Python 库.它能够通过你喜欢的转换器实现惯用的文档导航.查找.修改文档的方式.他还能够修改HTML/XML文档的内容.这篇 ...

  9. Niagara内容示例 4.3 Mesh Orientation vs. Rotational Force

    粒子效果 有三竖列的粒子,都在绕某个轴进行旋转.根据下面的文本提示来看,应该是每堆粒子的旋转操作的赋予方式不同,分别是直接操作网格体朝向(Mesh Orientation),操作旋转的速度(Rotat ...

最新文章

  1. HashMap和HashTable区别
  2. Cervical Cancer mechanism
  3. git Rebase 变基 教程
  4. 关于jquery-Validate
  5. SGU 201 Non Absorbing DFA (DP)
  6. TypeScript 的存在削弱了 JavaScript 生态系统?
  7. java ssm网上超市购物管理系统
  8. 英语背单词软件需求分析
  9. wps参考文献乱码。英文的行间距怎么调?
  10. Office中快速删除批注
  11. 在Ubuntu上安装Azure DevOps self-hosted agent
  12. 备案域名服务器DNS修改,未备案域名也可以用高防CDN加速
  13. JavaScript常用的字符串操作对象方法
  14. 龙芯1c300b开发语言,龙芯 1C0300B 主控芯片已成功进入激光打印机市场
  15. 数字逻辑设计基础(何建新)第三章
  16. svn不小心ignore了怎么办
  17. 中国书法艺术会消亡吗?
  18. SAP FICO 基础(1)中日双语
  19. sublime text3 多窗口打开设置
  20. 404(not found)错误

热门文章

  1. 微积分:闭区间上 有界、可积、连续、可导 的强弱关系
  2. Android Studio中对res、AndroidManifest、buil.gradle文件夹的讲解
  3. spark RDD 打印元素
  4. 小木虫内蒙古科技大学计算机,2019年内蒙古科技大学招收考研调剂(二)
  5. 个人计算机是国产芯片,全球最纯国产PC诞生!所有芯片/系统都是国产
  6. 中南大学复试上机:1009: 安全路径
  7. Code Project精彩系列(转)
  8. 数据结构与算法笔记:哈希表——力扣389
  9. 2021年中国学前教育行业发展现状及未来发展趋势分析:毛入学率达88.1%[图]
  10. 开发团队建设与管理的一些心得