This week I took a little break to work on other technical things. Unreal Niagara does not currently support the use of spline input for GPU particle emitters. So I would try to get them to work. This can also be done with user parameters and a blueprint, but I wanted to do most of the editing work in Niagara. Here is my result and how to achieve it.
Since this isn't a tutorial on how to use splines in Unreal, I'm not going to focus on it, but I personally have a blueprint that I call SplineUtility that I can drag around the world and use to create the curves I want. I also assume that you have a good knowledge of blueprints and particles in general.
STEP 1 – Setup
Since splines cannot be read by GPU emitters, we have to create our spline with something else. The way we do this is to write the curve we want to use in a texture. I'm only going to cover static splines because I don't think animated splines are too common in Unreal. Here's the kind of texture we're going to get.
You need to create a new design and canvas rendering target.
In the target render texture, set the size X to 128 and the size Y to 1. You can copy the other options, but I don't think they're too important. I felt that adjusting to clamps usually gives more accurate results.
STEP 2 – Create the blueprint
After we set up the basics, create a new blueprint actor and name something appropriate. Add a spline component and set up the design this way.
- With the construction script I can define another spline in the tool from which a texture is to be rendered.
(Optionally, you can just use the spline component you just created. It can even be easier and less buggy.)
2. This is what the event diagram looks like. I have commented on it as often as possible and kept it as simple as possible. Let me know if you prefer this or a step-by-step process.
Make the render target and spline cast member you want to use public so that they can be accessed when you drag the cast member out into the world.
The knot on the last picture is very important. If you've ever worked with vertex animation textures, this workflow will seem familiar to you. The min and max positions are required to get values between 0 and 1. If you then retrieve these positions in the output log, you can copy them and paste them into the Niagara module that we will create. If you want to learn more about using render targets, you can watch this video https://youtu.be/jWxdEhz9Zmo by @simon writes. If you are already there, you should also watch these if you do not have https://www.youtube.com/watch?v=aYZEmaQUrAo. This inspired the idea of writing the curve in a texture.
When you're done with the design, compile it, save it, drag it into the world, and set up the default variables you want to use. If you use the construction script method, you must use the lock to drag the spline actor into the spline utility input.
STEP 3 – Create the texture
Activate the output protocol in Windows and in the development tools. Then press the play button with the blueprint of the world. Min and Max should be printed on your screen and also in the output log. If not, return to the design and click the Print check box to log on both the Min and Max print string nodes.
It should look something like this:
The texture should now be in your render target. You could use it directly, but I prefer to change it to a static texture. You can do this by right-clicking on it and clicking "Create Static Texture" above.
Set the texture to HDR. If you want, you can also change the filter to get more accurate data. In this case, however, I have not done so. At this point, you can delete blueprints from the world if you want. Now that we have our texture, we can finally get to the fun part!
STEP 4 – Create Particle System
Set up a simple GPU emitter, make sure it's set to local, return to the content browser, and create a new Niagara module script. We don't technically need to create a new module since we could do the math directly in Niagara and use a texture sampler, but this should be cleaner. On my page I called it CurveTextureSample. If you want, you can also use a notepad module.
Make it available to the library, otherwise you won't be able to see it.
We are nearly there! Add a texture sample input, a Vector2D (UVs) and two float (min, max) and copy the setup. Copy the setup and add a new vector output. You can assign it directly to the particle position, but I prefer to rename it and then set the parameter. For clarity, I'll add the module name as a namespace modifier. The math we use here to get from color to position is (TextureValue * (max-min)) + min
Finally, we return to our Niagara system and enter the minimum maximum value and our texture. You can break the vector2D to get two float values, and then use a curve to animate the spawn position over the normaliszedLoopAget, or do something else, I'm not your mother. Create a set parameter module and assign the particle position to the particle attribute you created in your new module. Note that I used it here in the spawn area, but you can also use it in the update and move particles along the spline and let it die in the end. Or let them appear randomly along the spline and move along the spline in the update by adding a new value to the UV. You can also multiply or add the value you get from the texture by a floating point or vector curve to scale or change the curve. There are many opportunities!
If you want to improve this, you can write the min and max values directly into the texture or use a different texture / line to write the tangents or try to use them with a larger texture and larger curves! You can also change some elements so that they run in the editor instead of starting the game. Let me know if you do something cool!
Writing took a lot more time than I thought. Let me know if you like them or if I can improve them! I don't often work on more technical things, but I may do more from time to time.
Hope you will have fun with it! Feel free to ask questions and post your results here
Thanks to Niels Dewitte for working on his own implementation in C ++ and for the back and forth of ideas during the week!