Random sprite from sheet per GPU particle in Cascade

First question, please advice if in wrong section or similar.

I’m creating a snow particle effect in Cascade. I’d like the individual snowflakes to look different, so I’ve made a 128x128 texture divided into four 64x64 areas, each containing one snowflake. The idea is to pick a random flake out of these four for each particle. Using GPU sprites seems like a good idea for having a large amount of snowflakes. I can’t find an elegant way to do this in Cascade without having four separate emitters. Any pointers or simply knowing it’s not possible would be appreciated.

Here are the steps taken:

1: Import texture with four snowflakes into Unreal.

2: Make material using the texture, using ParticleSubUV node so we can use SubUVs.

3: Create particle system.

4: Make it use GPU sprites.

5: Set “Sub Images Horisontal” and “Vertical” to 2x2.

6: Add a SubImageIndex module.

7: Now it would be great if the subImageIndex module could just choose an index between 0 and 3. I’ve tried setting it to the different distributions, but it only changes index over time. Am I missing something? I’ve seen posts saying this is the way to do it. I only want a single, random subImageIndex per particle over it’s entire life. So, what I do now is setting it to Uniform Distribution and “0”. This obviously gives all the particle the same snowFlake. I then duplicate the entire emitter and give it the next uniformly distributed index of “1”. This works, but would be a slight pain to extend to say 8x8 types of snowflakes.

Is this a limitation of GPU sprites? If I understand correctly they don’t store much data per particle?

An additional note: If you duplicate the emitter “Shared” (so they share all data, shown via the “+”-signs) it becomes easier to work with. You can then unlink the SubUVModules and set different SubUV indices for the emitters but share all the other data. If you do this it’s seems necessary to also unlink the “GPU Sprites” module itself (I can’t find a better way than to delete and recreate it) - otherwise the emitters will still only use one of the SubUV’s.

Some images attached. Thanks for any help!

Initial Color, and Color Over Life modules, only have an effect on particle appearance if a Particle Color node is used in the particle material. Since you don’t appear to be using it for something else, you can use an initial color module to select your SubUVs. Set initial color to Distribution Vector Uniform. You have 2 SubUVs in x and y, so set Min to 0,0,0 and Max to 2,2,0. Then set up your texture sampler like this.

Then you’ll get a random SubUV for each particle.

Hey xnihil0zer0, and thanks! That’s a really smart way to do it, have now tested and works perfectly. I guess it would still be nice to be able to do it without taking over Particle Color (say if you wanted to use particle color normally) but for my purposes this works great.

You can also use a Dynamic Parameter module(with two float uniform parameters), and a DynamicParameter node. or a ParticleRandom node(where each interval of 0.25 between 0 and 1 selects SubUV) to do the same thing. Particle Color is just the simplest to set up.

Hi, I have been trying to implement it on GPU particle but it doesn’t seem to be working; it doesn’t randomize sub UVs.

It perfectly works on CPU particle.

Any advice would appreciate.

Thanks,

Hello Kazu.

Did you follow excellent instructions above?

If I understand correctly (works for me):

  • GPU particles will ignore the subuv module.
  • Instead we have to use some other parameter.
  • As long as we can get a random number in some good range we can use it to drive subuvs.
  • In this case we use “particlecolor”, but could be something else as long as it’s sent to the material.
  • In the material we use the parameter that we get (particlecolor) and calculate subuvs “manually”.

Good luck!

/

Hi erikhedvall,

Yes, I tried using “Particle Color” and it didn’t work because Distribution Vector Uniform in the color modules didn’t seem to be working on GPU Particle.

Maybe it’s a known issue?

Hi again!

I went back and tested again, and it seems you’re right. I swear I got it working back in 4.13 or so when testing solution, but no luck now. Initialcolor sets all gpu particles to same color, but works for cpu particles like you said. Found some other threads about the same issue, and some official answer:

[Particle initial color param for GPU particles not working - FX - Epic Developer Community Forums][1]

So it seems we can’t use particle color anymore for gpu subuvs.

Looking for another solution, I found this helpful page about what parameters are supported for gpu particles:

[Creating Visual Effects in Niagara for Unreal Engine | Unreal Engine 5.1 Documentation][2]

So… we need ideally two parameters, x and y. They need to be per-particle, and not changing over life.

I made a test using particle size. In my snow system I randomize particle size between 1-2 for each particle. If you set “camera alignment” to “rectangle” you get them to be not-the-same. So great, we have a random parameter between 1 and 2 that are different for each particle (sadly they also affect size, but let’s try anyway!).

Here is the setup:

Ideas for improvement would be welcome. I don’t know how effecient it is, but I don’t think the calculations are very expensive.

Right now an annoying thing is that large snowflakes will have the same subuv, and small ones the same. Could probably be fixed with some math.

By the way: there’s a promising node called “ParticleRandom” that gives you a random value between 0 and 1, per particle, and works for gpu particles. Only problem is that you only get one value and not two, but with some math that could be a great method for randomising subuvs.

Hey again!

Just a follow-up: the method with ParticleColor doesn’t seem to be working anymore for gpu particles, se discussion below. Do you have any insight on this? Also I don’t seem to be able to add DynamicParameters to gpu systems, only cpu.

ParticleRandom however seems to work, I missed your suggestion about this before. Should be a clean and nice solution.

And here is a much cleaner solution using ParticleRandom.

It’s fixed to 2x2 uv’s in my test but should be no problem adjusting to larger ones. Notice the division with 1.99 instead of 2.0, I seemed to get flicker on some particles when using 2.0 (possibly due to 1.0 mapping to an invalid subuv, but not sure).

Hey erikhedvall, how would this look for an 8x8 sprite sheet?

Hi ! Nice that someone else is trying this stuff :slight_smile:

Hmm it was a while since I did this, but for starters we want numbers between 0 and 8 instead of 0 and 2 for both x and y right. We start with a random value from ParticleRandom in the range 0-1. The scalar of 1.99 above should become 7.99 I think, giving the Y-adjustment as an integer 0-7. The later division with 2.0 becomes a division with 8.0. Then there’s the problem of getting the fraction that I used for X-value to map to 0-7 as well. It starts off as 0-0.99, so maybe multiply by 8 and use floor?

The problem is getting two independent random numbers from one, that’s why I tried using the whole number for Y and the fraction for X. Not completely sure that it really works as I think it does, but it looked alright for 2x2.

Just going through it now I kinda feel maybe my solution is not the best :slight_smile: Please post if you find a better one, also adding parameters for the dimensions seems like a good idea… Good luck!

Thanks so much for this quick response. I’m going to keep playing with it, but I keep hitting road blocks. I find it really odd that they don’t allow you to simply choose a random sprite per particle like you can with the CPU particles.

Hey gang,

Thank you so much for this thread, it helped me sort out how to pull this off. I’ve also got framecounts other than 2x2 working. Below are images showing a 4x4 atlas randomizing.

Here’s one detail that tripped me up… might be worth explaining. After the particle random value node there’s a mulx4. I originally plugged that directly into the append, but you only got the numbers 1, 6, 11, 16 out of that. To fix that I had to come up with two independant numbers. So for the V channel, a mulx4 and a round gave between 1-4. that worked. Then, for the U channel… I multiplied again by 4x before the round, giving a 1-16 rounded. I’m a little fuzzy why this works, but it seems to disassociate the u and v random results. It’s all divided by four at the end of the chain.

dj

This works perfect !