Niagara / unreal GDC



@ShaunKime Does SampleCurve work? I think I have a pretty basic setup:

Yet given changing values in CurveX, I always get CurveValues of 0.
The curve I’m using is already in the 0-1 range, so I’ve set bAllowUnnormalizedLUT to true to skip normalizing it again. I also use Curve.Eval instead of the LUT, because I know Curve.Eval is certainly working code. I can see it returning values on my breakpoint. Unless it’s evaluating for slate only. Hrm. I also tried turning on LUT and using curves beyond 1.

So I’m left scratching my head on how my setup is wrong.

And jumping down the UNiagaraDataInterfaceCurve rabbit hole was a fun journey. Clever stuff. Oh wait…shouldn’t the sim target be GPU?

LogNiagaraShaderCompiler: ERROR: GPU shader compile failed! Id 8

Okay that doesn’t help me. This does:

LogNiagaraShaderCompiler: Warning: /Engine/Generated/NiagaraEmitterInstance.usf(173,18-41): err0r X3004: undeclared identifier ‘Modulo’

Line 173 is the problem:

LogNiagaraShaderCompiler: 169 int Result4 = ExecIndex();
LogNiagaraShaderCompiler: 170 float Constant2 = 1;
LogNiagaraShaderCompiler: 171 float Result5 = Context.Map.Emitter.NumCopies + Constant2; LogNiagaraShaderCompiler: 172 float Result6 = Context.Map.Emitter.NumInstances / Result5; LogNiagaraShaderCompiler: 173 float Result7 = Modulo(Result4, Result6);

Shoud that be fmod? Anyway, I’ll keep poking at it. Any help appreciated. Cheers.


Gpu shaders are an area where we have a lot of work left to do. For now, I suggest flipping back to CPU for testing. What value are you using for X when sampling the curve? Is it changing? I would also swap your checkboxes. If you are between 0 and 1 there is no need for the unnormalized lut to be checked. However, for perf you almost always want the Lut table checked.


The sample values used are under the CurveX column in the screenshot (next to the red arrow). They’re clearly incrementing in value.

I deleted the curve and created a new one. This time I set a linear 0-1 curve, so I/O should be 1:1. No change. All values returned from SampleCurve continue to be 0.

Then I tried adding a curve to a new emitter. Untouched, out of the box, with only this small particle update script sampling the curve at 0.5

All values are 0 in the output. Either my setup is wrong or it simply doesn’t work yet?

Well, that’s enough frustration for one night :slight_smile:



Hmmm… I was able to get this working locally. Here’s what my module looks like:

Here’s what my emitter looks like:

Attribute debugger:

If you want to zip up your project and send it, I can take a look. Clearly we’re either missing an error or there’s some sort of mental model problem that we’ll need to address in documentation or clearer UI.


I forgot to mention that when I added the Emitter.Curve to the Emitter Update’s Set Variables module, I had to

  1. Create a dummy variable
  2. Drag Emitters.Curve from the parameters tab onto the Set Variables module
  3. This generated a warning about not having a default value for the curve. I simply hit the reset to defaults and that created a default curve for me to edit.
  4. I removed the unneeded variable that I used to create the set variables module.

Clearly this workflow above is a pain and we’ll try and fix it moving forwards, ideally just allowing you to drag and drop from the Parameters tab to the modules and have it auto-create the module for you.


@ShaunKime The fix was NOT to assign an existing curve. Creating the curve right there in the details panel did the trick. I am now getting proper values returned from sample curve. OMG…such a relief. Yay!

Thanks for your help. I am thoroughly enjoying Niagara. It literally keeps me up at night because it is so damn exciting.


I made a tutorial video about getting started in Niagara. Hopefully it’ll help get other people up and running; sharing what we learn in a virtuous cycle. Cheers.


That was awesome to watch. I registered about 7 new issues into our bug-tracking system for all the pain points I saw in that video. Hopefully we’ll be able to fix them up over the next few days.

Thanks for the shout out in the video. We’re just excited to see what the community comes up with.



Okay, next challenge: global variables.

I think the GDC vid mentioned creating these at the System level? I suppose in HLSL this would be equivalent to setting a uniform. That would mean it’s a constant that can’t be updated inside the shader (script module). Is there a way in Niagara to set a global variable to a new value before each iteration through the pipeline?


Thanks for the tut,
Quickly punched in some numbers aswell, just to see what we can do.

It did take 7 crashes, but It’s something :smiley:


There are several levels of variables.

User - these are what you can set per component or through blueprints. Readable everywhere, not writable within Niagara.
System - these are values shared by everything within the system, readable everywhere, writable only within system scripts
Emitter - values shared by everything within that emitter instance, readable in Emitter and Particle scripts, writable only in Emitter scripts
Particles - per-particle values, readable only by particle scripts, writable only by particle scripts

Hope that helps.



@Wyvery Yay! It’s great to see I’m not alone.

Has anyone figured out how to add keyframes in the timeline? I know Shaun mentioned, “expose them as user namespaces variables” but I still haven’t figured it out. It’s probably just my unfamiliarity with Sequencer in general.

@ShaunKime It does help. Thank you very much.


The timeline lets you set spawn bursts but that is it for now. You’ll need access to the latest branch for that to work, though.


And I’m back :smirk: this time with a…

@ShaunKime If I drop an Engine.DeltaTime in a System Update script it compiles successfully. However, the System that uses this script then fails to compile with: “Unable to deduce type for numeric input pin.” Probably a known issue but thought I’d mention it.


Copies of animated curves…

I also made a twitter account today :expressionless:


Last feature for today. Each curve is slightly delayed:


I remember some of the deformation functions you are using from my own material and Instanced Static Mesh experiments. I wonder if there is any benefits to using them in a particle system. Is it more manageable to spawn particles on top of the existing ones or add more particles over time at a specified location?


Sorry, I’m not sure I understand the question about managing particles.

As for the benefits…I’m basically creating a procedural system for motion graphics based on what I see in Maya Mash. Here’s an example of using Mash to create a pixel globe. That could easily be used with a holographic material to create an interactive UI widget in games. Here are more examples of futuristic UI created in Mash.

My vids are more like development updates. I’ll add a feature and twist it into abstract forms - VJ type work.

So are there benefits? Well…(assuming feature parity) take anything you can do in Mash and make it real time and interactive. This would include:

  • 3D user interfaces
  • Motion graphics
  • VJing

Using Niagara in this way falls more inline with Epic’s push into the film/tv industries. I’m interested in using Niagara for these types of use cases. However, if your only concern is making magic FX (nothing wrong with that!) then, yes, on the surface there doesn’t appear to be a lot of value here. In that case, I should probably focus my updates elsewhere. I don’t want to spam the thread. Sorry.


I don’t think you are spamming, so keep on. It’s just that making these waves working on objects can easily be made in a material and ISM. Twisting and scaling is also just a rotate material node. Creating a globe with cubes starts to get interesting, but possible with Particles. I just asked out of curiosity if there is something more advanced you can only do in Niagara with these math functions, because right now, this can be made already pretty easily. Don’t want to devalue your work, it’s still cool, no matter which way you choose to create these effects!


because right now, this can be made already pretty easily

I would genuinely like to see this. Do you have a video for your ISM stuff?