Is there no way to write material variables to niagara data channel? I’m generating a material dynamically and sending it to a niagara system currently, but there doesn’t seam to be a function to write materials. Does this need to be moved to the niagara effect in something like a scratch pad? Is it possible to call create dynamic material there or create canvases there?
Looking at the Sprite Renderer I don’t see a way to assign a module to it for the material source so I’m not sure where or how to best handle this for generating the canvas, texture, and material inside the effect itself.
So far only way I’ve been able to optimize it further is to use a lightweight emitter as I don’t need many features for floating damage numbers, but certainly wish I could figure out this NDC. Still can’t seam to find a way to generate the texture and material inside the niagara system or how to send the material to the NDC emitter.
Hi again @Krileon!
You are correct- there is no DIRECT communication from material to Niagara system (at least not to my knowledge.) That being said, there are a lot of ways to get around this limitation depending on what you’re trying to accomplish.
First of all, if all you need to do is set your particle system to your new dynamic material, you can do that pretty easily via blueprint.
If you’re generating a dynamic material instance with custom parameters, then you must be setting these values via Blueprint. Blueprint and Niagara can communicate via Data Channels or setting Niagara parameters, so ideally you can handle it that way if you need specific variable information.
Another, clunkier, method is to directly pull out variable information from your material. I am not familiar with C++, but these are some of the functions available via Python (not executable at runtime) so I have to imagine they have a C++ equivalent. I don’t really see you needing this though, since it can only read variables which should be set via Blueprint anyways.
If you need to pull out a specific calculation, that’s a lot trickier. I would say replicate it in a blueprint or your Niagara System if possible. If NOT possible, there are ways for Niagara to read color information, so your best bet is probably to send it through the material base color and reassign the material to the correct one after the calculation’s values are stored in the system.
Let me know if you want help with any of these ideas, and I’ll see what I can do. Otherwise, if these solutions won’t help you out, give me a little more information on the exact problem you’re trying to solve and I’ll try my best to guide you through a solution.
I always go to a material-parameter collection as the go-between as it’s widely-readable, and updateble as code. This way you can have your logic sink whatever into the mpc and then either write some of that to Custom Primitive Data itself, and/or a MPC. Either is readble in the material and once you set up the read, it’s usually go-to-go from there with little maint on that end (it’s a passive setup in the material).
Whatever is driving the niagara data-channel write/output can-also update the MPC or CPD. CPD is analagous to the data-channel but for mesh-thingies.
I don’t have any issues setting my material parameter for a non-NDC system. The problem with NDC is the Write functions don’t have a function for writing to NDC a material. Only things like int, float, vector, etc.. This material is entirely dynamic as I’m generating a render 2d target, adding text to it, and assigning the material then sending that material to niagara. It’s being used for floating damage numbers.
Below is what I’m doing.
This works fine and as expected. I’m using a lightweight emitter for it and works great. I was just seeing if I can make it even better using NDC, but NDC has no way to write materials to the data channel. Below are the only available functions to write to the data channel.
My point is bypass the NDC. It sounds like you wanted to write to the NDC and have it go into the material/material-instance as input/data?
Reference the stuff you wanted to push via NDC in the material, but instead have it point to the Material Parameter Collection (MPC). What you wanted to write as a scalar/4vec in the NDC, instead write into the MPC and it can be used as a live-channel into the material instead of the NDC.
My understanding is you somehow wanted-to get data you would otherwise inject to the Niagara System to ultimately get to the material, so my take is skip that and just-write-to something the material can reference directly. If you sync the updates to where you wanted to update NDC to the MPC instead, it should all come out in the wash at runtime; the different parts will be kept in sync.
I never thought of using niagara for damage numbers, I just made a floating widget with a status bar.
That is way above my head. I’m barely into learning materials so I’ll just continue with my lightweight emitter solution, lol. Hopefully NDC will be improved further to allow writing materials to user parameters as you can other types.
It works substantially better than widgets. Can have hundreds and hundreds of these on screen with basically no performance issues. Widgets however will eat performance like crazy. If only I could figure out a way to move healthbars to niagara, lol.
I could probably help you with the health bars! Likely all you’ll need is a green material with a red mask, and to move the mask in the material as they take damage. Let me know if you want help with this!
I get to use Snip again
So this is my nanite-grass material:
It has a tint over distance to fade into the landscape material. Using the gradient in red, and the blending over distance (the LERP) in green, that gets sent to the basecolor pin.
You can see currently it has a reference to an MPC (Material Parameter Collection). This is functionally equivalent to the next pic, which is likely what you are familiar with, using a 4-vector (or a 4vec-parameter), they do the same thing, where they come from is different.
Typically done in this manner:
A material parameter collection is a group of 1024 scalar values (1 value) AND 1024 4vec values (4 scalar values bundled together per the above pic). It’s just an isolated group of numbers you can adjust via code. When you make a material you can refer to these like you can with scalar/4vec parameters; they just live outside the material.
Hence when you update the MPC directly, via code, the value just automagically flows into the material since it’s like an external-reference for the material/shader-program. The shader never really knows/cares where or how or why it might be changing it just looks at ‘that-spot’ for a value and uses whatever is.
This allows you to use logic to drive things in a way that you cannot inside a material (or wouldn’t for the expense), and also as an isolated resource, it can be referred-to by multiple things, which is very handy. How much ‘snow’ do you have in the entire level, 0 to none to 1 to completely-snowed in, somewhere in between? Your weather system can refer to the same mpc value the landscape does, plants, etc, anything with a snowyness that needs to know how-much snow is in the world.
The upshot is you can refer to 2 of these in a given material. So instead of sending values or the material to the niagara system via some material-instance, point whatever stuff you were thinking of running from the material you are/were going to use, to instead use MPC values and then the material on whatever you are already rendering in niagara won’t miss a beat. From the same logic you need to update the state of whatever is causing the material to update, update the MPC instead, you will still get the same effect. The material will still be referring to the spot that gets changed in sync with your logic, so it all comes out in the wash. It’s almost like the two hands don’t know what they are doing, but still coordinated by the same mind/logic.
Of course, update material to point to the same MPC values..
Object-data is the same deal but you instead refer to a value sent along with the actual mesh-indstance. It’s limited to 32 scalar values (so 8 bundles of 4), but it’s very-effeciant and tied to te given mesh-instance. So like health, or the bendyness of a particular blade of grass spanwed by whatever (it’s a mesh instance!), or whatever you choose to store there, but works the same; the material always just sees a single scalar value (float) or a 4vec (4 floats). Hence, if you were spawning meshes in your niagara system, you might be able to leverage that as well.
In the end, they are all just-places to store data, some more-tightly couple with the mesh-instance (object-data) or widely-available.
some of these are for anyone just-reading the thread. ref:
- w/regards to the world-space gradient, read this, pay attention to the materials subsection: Large World Coordinates Rendering in Unreal Engine 5. | Unreal Engine 5.5 Documentation | Epic Developer Community
it will save you some of these:
I’ll give niagara health bars a shot when I’ve some time. Not sure yet if it’s worth doing though performance wise.
I appreciate it. That’s all still to much for me. So far lightweight emitters seam to be doing the trick fine. Have thousands of them with basically no problems. Certainly far far better than widgets at least.