Unreal - Spawn Particle based on Material Parameter?

This has been asked in the past, and I don’t think it’s possible but I’m bringing it up again just in case. Wanting to spawn a particle on a mesh surface based on a material parameter. For example if I have quad mesh with mask texture on the material, then I spawn particles from the surface of the quad where it is white and not where it is black. Wanting this to be dynamic, so as I change the mask in the material then the spawn points follow appropriately.

The “Skel Vert/Surf Location” module with the “Inherit UV” parameter and using “Dynamic Parameter” node in the material seem promising but I don’t know how to use them.

I know this can be done in PopcornFX, as I’ve done it before (not sure about the dynamic material part though), but my workplace is anti PopcornFX plugin (one of those, “It didn’t work this one time for what we wanted so it’s now considered broken forever” situations).

This will be made better in the future someday, but for now you could in theory do this with a little hacking.

Set up your skelmesh you are emitting from with a mask that maps to your UVs the way you want.
Make a system that reads from it using skel vert/surf locations.
Enable “inherit UV”.
In your particle, drop in a dynamic input. Set the 0 and 1 entries to “spawn time only” and “auto set”. Name them X and Y.
in your particle material, put in your dynamic parameter and append the 0 and 1 (X and Y) together to make a UV.
Use that UV to sample the same mask texture your mesh is.

If you had, say, a black and white mask, this would give you white particles where the white parts are, and black particles for the black parts.

Then, do some logic in the vertex shader to collapse any particles that are fully black to 0,0,0 or something and let the GPU cull the degenerates. It’s a hack, but could work OK depending on counts and need.

Going forward we’ll make this kind of thing worlds better in Niagara, but for now with Cascade this would be the only way to accomplish it.

14 Likes

Best hack i’ve heard so far!
Nice.

I’m mostly catching what you’re saying. When you say use the UV to sample the same mask texture as the mesh, do you mean, in the particle material, just plug in the appended XY dynamic parameter values in the UV’s of a Texture Sample with the same texture as the mesh mask?

Also, I’m not able to rename Param names of the Dynamic module in the particle system. It’s grayed out and the tool tip says “Read Only” at the end of the description.

I have the particles spawning from the mesh, but everything else about it is still broken.

PS With the Skel Vert/Surf Location module (along with this hack) are particles only able to spawn at vertex positions on the mesh? (As opposed to anywhere on a face)

How might one accomplish this in UE/Niagara nowadays?

Can a separate/hidden mask channel be used somehow so as to not interfere with a meshes ‘hero’ materials & UVs?

I haven’t found much reference, and have been poking around in a scratch module to see what I can come up with, but the analog I have in my head is Houdini’s scatter by attribute, which bursts particles only in a color-masked area, and not over the entire mesh.

How might one accomplish this in UE/Niagara nowadays?

I’m very curious about a solution to this as well. I haven’t been able to figure this out on my own.

Skeletal mesh location modules write uv’s to a transient parameter, so you can use it to to sample a textures (module also already exists) and then use a kill particles module with something like color.x > .1 to remove particles.

Except for that it is the same as what has been described before.

2 Likes

Sweet, thanks for the reply. Just found this tut which explains precisely.

I only need to do this on a StaticMesh, and the [Sample Static Mesh] Module provides the MeshUV Module Parameter akin to SampledUV in the [Skeletal Mesh Location] module. In fact, if you jump into the corresponding Niagara Module Scripts you will see they both use [Get Tri UV]. The [Sample Static Mesh] module outputs it as MeshUV while the [Skeletal Mesh Location] outputs it as SampledUV because it has to track the movement of of each Tri as the mesh animates/deforms (good ole bary centric coordinate maths)

Heh, so the catch here is you need to sample an image map, and since you manually assign a texture to a mesh it presumes you will do the same in Niagara. So I wondered if this kind of sourcing could be achieved with a procedural texture (ie material). The idea would be the same in so far as you have to sample the UVs on the mesh, and then feed those UVs to the shader… which can be done by plugging those sampled UVs into a DynamicMaterialParameter.

However, I believe this is designed to drive the material assigned to the SpriteRenderer so you can’t kill particles based on color as this isn’t the particles color. So I’m wondering if there might be a way to get that color onto the particle so you can?

I suppose alternatively, one could periodically write out the material to a render target and sample that.

Well, the gpu particles are technically a shader, so you can just recreate your material in niagara. Probably cheaper if the amount of particles doesn’t exceed the texel count of the rt.

Will this setup only work for GPU particles? If so, is there any kind of workaround for mesh particles? Like rocks or crystals spawning off a character’s mesh in the direction of the mesh’s normals, while using a texture for their spawn location?

Niagara mesh particles can use gpu compute sims if I’m not mistaken.
If you want a work around, skelMeshSample can sample the vertex color, so you can paint it in.

1 Like

Thank you! I’m guessing there’s also a way to feed in a skel mesh’s normals into a Niagara system too? So that you could point non-square sprites or geo in the same direction as the mesh face or vert normal?

Yeah, the skelmesh sampler modules has it as an output, just type output in the search of any vector input field

1 Like

Thanks again, I appreciate all the info and advice :slight_smile: I’ll definitely bookmark these for later, in case I forget :+1: