Jose Moreno Profile picture
Coffee, math and game lover. Senior Technical Artist at @remedygames. Prev. Metroid Dread @nintendo @mercurysteam, @sabergames, @labcave and @calendulagame.

Sep 26, 2022, 15 tweets

I'm going to write a few shorts threads for those who are starting in the wonderful world of simulation stages in #ue5 #niagara. The ultimate goal is code a (simple) fluid solver in 2D/3D that allow us, for example, driving particles by fluid simulation in a similar way as games

(2/15) like Returnal or God of War does.

(3/15) As (I hope) you know, Niagara is a highly customizable particle system framework. You can put logic on every step: when the emitter spawn, when it updates, when a particle spawn and when it updates. Furthermore, you can add new attributes to particles to play with.

(4/15) You can find examples of this (attribute creation, complex logic, etc...) in the Content Examples that Epic provides us, but for the sake of completeness I'm going to make a simple one.

(5/15) Here we have a "spiked ball". The yellow part has been built using one sprite renderer, "two" points, a custom alignment and a particle size vector. The red points show the position of the endpoints used.

(6/15) The custom alignment vector allows us to orient the sprite in the direction given by "base position" and "position". We change the pivot to scale the sprite from base position. Note that we are rendering the sprite using "base position" attribute.

(7/15) So, Niagara is a wonderful particle system editor. But what (maybe) not everybody knows is that Niagara allows us to "talk" directly to GPU. When you setup "Sim Target" in Properties as "GPUCompute Sim" you're programming (almost) literally compute shaders.

(8/15) That means a lot of parallelism and thinking in a similar way you do when you are making materials. Having said that, we are going to create our first simulation stage.

(9/15) When we run a simulation stage we need to decide "where" we want to write the data. This is called "Iteration Source". Using the material analogy: the "Iteration Source" would be the pixels of a mesh seen by a camera.

(10/15) The Iteration Source can be either the particles of the system or a "Data Interface". We are going to focus on Data Interface which, normally, is going to be a Grid2D/3D.

(11/15) A Grid2D (or 3D) is, essentially, a Render Target in which you can store any number of attributes (of different kind) in each cell (pixel). Create a Grid2D is easy: set a new parameter at Emitter Spawn and set the dimensions (with a little scratch pad).

(12/15) After that, pick your Grid2D as Data Interface in your Simulation Stage. Now you have a compute shader running through all cells of your Grid2D. Doing nothing.

(13/15) The simplest Simulation Stage is the one that assigns a single constant value for every cell in the grid. This can be done setting a new parameter in "My Stage" (a float, for example) and changing the namespace of the parameter to "Stackcontext".

(14/15) The use of "Stackcontext" namespace is optional or "transitional". Once you defined the first time, you can see that Niagara has defined a new namespace (in our case) called "Emitter | My Grid". You can reference it anytime you are working with this grid in a SG.

(15/15) This is the end of our first thread :)

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling