Init
This commit is contained in:
BIN
03-UnrealEngine/VisualEffect/FlowMap/FlowMapPaper,Siggraph.pdf
(Stored with Git LFS)
Normal file
BIN
03-UnrealEngine/VisualEffect/FlowMap/FlowMapPaper,Siggraph.pdf
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
03-UnrealEngine/VisualEffect/FlowMap/水流效果.mp4
(Stored with Git LFS)
Normal file
BIN
03-UnrealEngine/VisualEffect/FlowMap/水流效果.mp4
(Stored with Git LFS)
Normal file
Binary file not shown.
102
03-UnrealEngine/VisualEffect/Niagara Module笔记.md
Normal file
102
03-UnrealEngine/VisualEffect/Niagara Module笔记.md
Normal file
@@ -0,0 +1,102 @@
|
||||
---
|
||||
title: Niagara Module笔记
|
||||
date: 2024-02-20 11:14:46
|
||||
excerpt:
|
||||
tags:
|
||||
rating: ⭐
|
||||
---
|
||||
# 前言
|
||||
- UE4 Niagara源码解析:https://zhuanlan.zhihu.com/p/362638250
|
||||
|
||||
不论Niagara Emitter有多少的Module,Module里有多少的脚本,脚本中写了多少东西。我们当然要抓住本质数据,其都是更新某个渲染器所需要的必要参数,也就是如下图所示的信息。
|
||||

|
||||
也就是说,只有这些信息是每个渲染器所需要的,其会传递给渲染线程并最终提交渲染。任何其他参数仅仅为中间变量。因此我们首先关心的是这个数据是存储在什么地方的。由于一个Emitter可以拥有多个不同的Renderer。因此其本身存储在Emitter级别,而不是在Renderer级别。
|
||||
因此我们最终传递给渲染线程的数据存储在每个Emitter实例FNiagaraEmitterInstance的FNiagaraDataSet身上。不论是GPU粒子还是CPU粒子。
|
||||

|
||||
|
||||
# Module 变量类型
|
||||
- Input:Module输入的变量。
|
||||
- Local:单帧内存在的变量。
|
||||
- Particle:粒子级别**持久存在**的变量。
|
||||
- Emitter:发射器级别**持久存在**的变量。
|
||||
- Engine:引擎提供的只读变量。
|
||||
|
||||
# 粒子属性读取
|
||||
在Module中在ParticleAttributeReader中可以读取对应的例子属性。引用的数据的方式有两种:粒子的ID或者Index索引。但是难就难在最初的我不太了解这两个是啥。大致知道是某种编号。ID的话倒是了解一点,但不知道它结果分为Index 和Acquire Tag组合在一起的。
|
||||
|
||||
PS.**Niagara Debugger**工具可以用于检查粒子ID以及对应变量的变化情况。
|
||||
|
||||
# 其他
|
||||
1. **发射器固定粒子ID**:勾选发射器上**RequiresPersistentIDs**选项即可固定。
|
||||
2. ExportParticleDataToBlueprint:可以输出CPU或者GPU变量
|
||||
1. 在该节点上添加蓝图变量名。之后在蓝图的BeginPlay()设置这个变量为该蓝图类。之后实现ReceiveParticleData接口。
|
||||
2. GPU 粒子数据导出是通过从 GPU 内存回读的方式进行的。这需要不可预知的非固定帧数,通常为 1-2 帧。
|
||||
3. GPU 回读性能受限于回读缓冲区的大小。建议使用最小值的 GPU 固定大小分配来捕捉特定帧中可能发生的所有事件。任何超过固定大小的事件都将无法发送。
|
||||
3. Window - GeneratedCode可以看到生成出的HLSL代码。
|
||||
|
||||
#
|
||||
Particle的Module都是c++级别写死的。基本位于`Engine\Source\Runtime\Engine\Classes\Particles`目录。基类为**UParticleModule**;Niagara的Module都是蓝图资产,引擎自带的都在 `Engine\Plugins\FX\Niagara\Content\Modules`。基类为**UNiagaraScript**。
|
||||
|
||||
- UNiagaraScriptBase:定义了一些编译相关的接口。ModifyCompilationEnvironment()、ShouldCompile()以及获取模拟元数据接口GetSimulationStageMetaData()。
|
||||
- UNiagaraScript:排除掉Editor相关函数,主要的函数为:
|
||||
- IsXXXScript()系列判断函数。
|
||||
- 相关接口,PreSave、Serialize、PostLoad;基类接口实现。
|
||||
- FNiagaraVMExecutableData相关
|
||||
- 编译相关。
|
||||
- 其他。
|
||||
|
||||
## Niagara里面的相关类型
|
||||
### DataInterface
|
||||
基类为UNiagaraDataInterface。
|
||||
- UNiagaraDataInterfaceTexture:NiagaraDataInterfaceTextureTemplate.ush
|
||||
- LoadTexture2D()
|
||||
- GatherRedTexture2D()
|
||||
- SampleTexture2D()
|
||||
- SamplePseudoVolumeTexture()
|
||||
- GetTextureDimensions()
|
||||
- GetNumMipLevels()
|
||||
- UNiagaraDataInterface2DArrayTexture:NiagaraDataInterfaceTexture2DArrayTemplate.ush
|
||||
- LoadTexture()
|
||||
- GatherRedTexture()
|
||||
- SampleTexture()
|
||||
- TextureDimension()
|
||||
- UNiagaraDataInterfaceVirtualTexture:NiagaraDataInterfaceVirtualTextureTemplate.ush
|
||||
- GetAttributesValid()
|
||||
- SampleRVTLayer()
|
||||
- SampleRVT()
|
||||
|
||||
## Texture相关Module
|
||||
- Textures
|
||||
- SampleTexture
|
||||
- SamplePseudoVolumeTexture
|
||||
- SubUV_TextureSample
|
||||
- WorldAlignedTextureSample
|
||||
- SubUV
|
||||
- SubUVAnimation
|
||||
- V2
|
||||
- SubUVAnimation
|
||||
|
||||
里面的一些节点调用一些函数,这些函数都在对应的**UNiagaraDataInterface**中的**GetFunctions()** 定义,具体的逻辑位于 对应的**xxxTemplate.ush**
|
||||
## 生成的代码
|
||||
高斯3D里Niagara采用PositionTexture生成的相关代码:
|
||||
```c++
|
||||
int2 Emitter_SampleTexture_Texture_TextureSize;
|
||||
int Emitter_SampleTexture_Texture_MipLevels;
|
||||
Texture2D Emitter_SampleTexture_Texture_Texture;
|
||||
SamplerState Emitter_SampleTexture_Texture_TextureSampler;
|
||||
void SampleTexture2D_Emitter_SampleTexture_Texture(in float2 UV, in float MipLevel, out float4 OutValue)
|
||||
{
|
||||
OutValue = Emitter_SampleTexture_Texture_Texture.SampleLevel(Emitter_SampleTexture_Texture_TextureSampler, UV, MipLevel);
|
||||
}
|
||||
|
||||
|
||||
void SampleTexture_Emitter_Func_(inout FSimulationContext Context)
|
||||
{
|
||||
float4 SampleTexture2D_Emitter_SampleTexture_TextureOutput_Value;
|
||||
SampleTexture2D_Emitter_SampleTexture_Texture(Context.MapSpawn.SampleTexture.UV, Constants_Emitter_SampleTexture_MipLevel, SampleTexture2D_Emitter_SampleTexture_TextureOutput_Value);
|
||||
Context.MapSpawn.OUTPUT_VAR.SampleTexture.SampledColor = SampleTexture2D_Emitter_SampleTexture_TextureOutput_Value;
|
||||
Context.MapSpawn.OUTPUT_VAR.SampleTexture.SamplerUV = Context.MapSpawn.SampleTexture.UV;
|
||||
Context.MapSpawn.Particles.SampleTexture.SampledColor = SampleTexture2D_Emitter_SampleTexture_TextureOutput_Value;
|
||||
Context.MapSpawn.Particles.SampleTexture.SamplerUV = Context.MapSpawn.SampleTexture.UV;
|
||||
}
|
||||
```
|
114
03-UnrealEngine/VisualEffect/Niagara官方中文视频教学笔记.md
Normal file
114
03-UnrealEngine/VisualEffect/Niagara官方中文视频教学笔记.md
Normal file
@@ -0,0 +1,114 @@
|
||||
## Emitter Properties-Deteminsim
|
||||
勾选之后,重复播放的粒子都会是相同(随机值不会起作用)。可以用在制作阶段的效果预览,但需要在制作完后去掉勾选。
|
||||
|
||||
## 查看粒子各项数值与Debug技巧
|
||||
在Niagara编辑器中的Window选项卡中开启Attribute Spreadsheet。即可对粒子数据进行捕获并查看。
|
||||
|
||||
你可以在给粒子设置Debug材质的方式来进行指定粒子的查看。具体的方式为:通过Niagara(Bindings)传递参数,之后材质中使用Debug节点进行显示。
|
||||
### 按下键盘上的Pause键可以暂停
|
||||
同时再按F8可以自由转换视角,或者在编辑器中点击Eject,结束对Character的控制,以此切换为自由观察视角来进行观察。
|
||||
### 在play或者Simulate下按下;开启DebugCamera装下
|
||||
在这个状态下有着各种调试功能。还可以检查场景剔除情况。
|
||||
|
||||
## Niagara系统的数据传递
|
||||
https://zhuanlan.zhihu.com/p/74796515
|
||||
1. 从外界把数据传进来<br>
|
||||
主要通过ParameterCollection或者直接对NiagaraSystem进行数据设置。(这个数据需要加到Niagara变量中的User标签下)
|
||||
2. Emitter内部数据传递<br>
|
||||
本质上是使用MapGet和MapSet通过名字来找到数据的。
|
||||
3. NiagaraModuleScript之间的数据传递<br>
|
||||
4. Emitter之间的数据传递<br>
|
||||
在ParticleUpdate里添加事件。(因为需要跟踪粒子Id,所以需要勾选RequiresPersistentIds)<br>
|
||||
在需要监听事件的Emitter中的EventHandler中添加监听事件即可。
|
||||
|
||||
## 调节场景中的Niagara粒子播放速度
|
||||
命令行输入Slomo [倍率],即可调节播放速度,例如输入Slomo 0.1,就可以慢动作观察粒子播放了。
|
||||
|
||||
## 使用CurveAsset与CurveAtlasAsset将渐变信息导入材质中
|
||||
CurveAtlas可以用于制作渐变贴图,它支持的渐变条数与TextureSize有关(一行一条渐变)。之后再材质编辑器是使用CurveAtlasRowParameter节点即可读取渐变信息。
|
||||
|
||||
给CurveTime输入节点连上上UV节点的R通道即可观察渐变效果。如果把黑白渐变图连上,那结果就会被染色成渐变效果。
|
||||
|
||||
CurveAtlas除了可以调整颜色值,还可以通过调整Alpha值曲线来调整边缘效果。
|
||||
|
||||
另一种思路就是使用材质编辑器中的Gradient系列节点。
|
||||
## 让特效具有立体感
|
||||
粒子模型使用穿插面片:
|
||||

|
||||
|
||||
使用Fresnal或者DotProduct节点(记得使用abs),与黑白Ramp贴图相乘,以此来减弱接近平行的面片渲染效果。(记得勾选双面渲染)
|
||||

|
||||
|
||||
## Ribbon与Beam
|
||||
Beam也是使用Ribbon进行渲染的。差别在于,Ribbon是一个一个发射粒子,之后再渲染飘带模型。 Beam是一下就生成完所有粒子的,之后再渲染飘带模型。
|
||||
### 设置步骤
|
||||
1. 在EmitterUpdate中添加BeamEmitterUpdate
|
||||
2. 在ParticleSpawn中添加SpawnBeam
|
||||
3. 在Render中添加RibbonRenderer
|
||||
|
||||
记得勾选AbsoluteBeamEnd将本地坐标转化为世界坐标。
|
||||
### 调整宽度
|
||||
在ParticleSpawn中添加Initialize Ribbon
|
||||
### 控制Ribbon UV
|
||||
1. 在UV0Tiling Distance设置数值
|
||||
2. 在材质编辑器中的对UV进行求余数运算。
|
||||
|
||||
个人认为或许使用WorldPosition应该可以把。
|
||||
|
||||
## 另一种给材质传递传递数据的方法
|
||||
对一个StaticMesh调用SetCustom Primtive Data XXX。(可以是float、Vec2、vec3、vec4)之后在材质编辑器中新建一个变量节点,之后在变量节点的Details-CustomPrimitiveData选项卡中,勾选UseCustomPrimitveData。
|
||||
|
||||
它的消耗比Dynamic Material Instance少的多,而且不同的Component都是相互独立的,不像材质集是全局的。
|
||||
## 性能调试
|
||||
Shift+Ctrl+,开启GPU Visualizer
|
||||
|
||||
限制:其基类必须是Primtive。
|
||||
|
||||
## 直接控制SubImageIndex变量
|
||||
通过修改SubImageIndex变量的方式来直接控制SubMaterial渲染结果。
|
||||
|
||||
### 使用随机值进行采样
|
||||
可以在Niagara里设置一个变量,在使用SetParameter节点对这个变量赋予随机值,之后使用这个随机值变量对曲线进行采样。(将这个值赋予CurveIndex)
|
||||
|
||||
### 碰撞
|
||||
碰撞类型需要与粒子类型相同(GPU与CPU)。同时使用的粒子材质需要是Translucent,使用Mask会影响场景深度,使得Depth不正确,从而导致模拟出问题。
|
||||
|
||||
下雨逻辑,GPU判定碰撞,产生事件,计算碰撞时间与法线,之后生成水花(SubImage)
|
||||
|
||||
If you open the Material function "Imposter_ThreeFrameBlend" you will have to go to each "World to Loc" node and edit the shader code by replacing Primitive by GetPrimitiveData(Parameters.PrimitiveId).
|
||||
|
||||
In the material editor go to Window and then "Find results"
|
||||
There you can search for "Custom" this will look for every custom node with custom code. Cycle through every result until you find a World to Loc node.
|
||||
Then you can proceed to edit the code. There are a total of 5 nodes which you need to edit.
|
||||
|
||||
The edited code for me looks like this :
|
||||
```c++
|
||||
#if USE_INSTANCING || IS_MESHPARTICLE_FACTORY
|
||||
return mul(InWorldVector, transpose(Parameters.InstanceLocalToWorld));
|
||||
#else
|
||||
return mul(InWorldVector, (MaterialFloat3x3)GetPrimitiveData(Parameters.PrimitiveId).WorldToLocal);
|
||||
#endif
|
||||
```
|
||||
And like this :
|
||||
```c++
|
||||
#if USE_INSTANCING || IS_MESHPARTICLE_FACTORY
|
||||
float3 temp;
|
||||
temp.x = length(TransformLocalVectorToWorld(Parameters, float3(1,0,0)));
|
||||
temp.y = length(TransformLocalVectorToWorld(Parameters, float3(0,1,0)));
|
||||
temp.z = length(TransformLocalVectorToWorld(Parameters, float3(0,0,1)));
|
||||
return mul(InWorldVector, (MaterialFloat3x3)transpose(Parameters.InstanceLocalToWorld)) / (temp*temp);
|
||||
#else
|
||||
return mul(InWorldVector, (MaterialFloat3x3)GetPrimitiveData(Parameters.PrimitiveId).WorldToLocal);
|
||||
#endif
|
||||
```
|
||||
---
|
||||
- https://answers.unrealengine.com/questions/882887/index.html
|
||||
- https://docs.unrealengine.com/en-US/Programming/Rendering/MeshDrawingPipeline/4_22_ConversionGuide/index.html
|
||||
primitive replace by GetPrimitiveData(Parameters.PrimitiveId)
|
||||
```c++
|
||||
#if USE_INSTANCING || IS_MESHPARTICLE_FACTORY
|
||||
return mul(InWorldVector, transpose(Parameters.InstanceLocalToWorld));
|
||||
#else
|
||||
return mul(InWorldVector, (MaterialFloat3x3)Primitive.WorldToLocal);
|
||||
#endif
|
||||
```
|
Reference in New Issue
Block a user