How to change properties at runtime and prevent emitted particles from changing

I’ve created a dust and dirt effect for my racing game using the HDRP visual effects graph version 12.1.6 in Unity version 2021.3.0f1 LTS. I’ve set up a system where when a vehicle drives over a different ground texture, the properties of the effect change. Right now it only changes the color gradient and the color over lifetime but, because all the dust trail data is stored in scriptable objects, I can easily change more properties in the future.

The code that changes the properties looks something like this:

for (int i = 0; i < effectParameters.Length; i++)
{
    //If not over viable ground, continue
    if (!effectParameters[i].active)
        continue;

    //Set position of emitted effect
    effect.SetVector3(effectParameters[i].position, effect.transform.InverseTransformPoint(effectParameters[i].hit.point));

     //Get the ID of the trail properties that match with the texture
     int particleIndex = effectParameters[i].effect.GetDominantMask(effectParameters[i].hit.textureCoord);

     //If we find nothing, continue
     if (particleIndex == -1)
         continue;

     //Set parameters here
     effect.SetGradient(effectParameters[i].colorGradient, GameData.trails[particleIndex].colorGradient);
     effect.SetGradient(effectParameters[i].colorOverLife, GameData.trails[particleIndex].colorOverLife);

}

I only want the particles that are emitted over different types of terrain to only have the parameters I apply. However, when I apply new properties all the emitted particles change, as seen here:

dhpl6d

I feel like I’m missing something rather simple to fix this, but I haven’t been able to find anything. Is there a way to make this work or is this just how the VFX graph is designed?

The reason is you use the same data source for all your particles. If you set instance properties like you did (effect.SetGradient) they are not assigned in any way to particles.

Let’s start with something simple - single color for every particle. To recreate very fast what your system does I made following one:
Graph

8977132--1234651--GIF 27.04.2023 14-37-59.gif
The difference between our graphs is that you probably use SampleGradientOverLife inside update or output context, so in short, particles sample currently assigned gradient to graph instance every frame, while mine assigns color to particle attribute when initialized.

The problem is you use gradient not a single color, and particles are just small blitable structs - can’t hold huge amount of data. Actually, technically they could hold a gradient, but vfx graph does not allow that anyway. So there are two ways to handle it - put data into particles or sample data based on particle attrbutes.

First option is not possible unless you reduce amount of data, for example you can assign only single color per particle, not the whole gradient, or instead of using gradient struct you could use only two colors, start + end and lerp between them over lifetime.
Second option is to provide texture where each row of pixels represents single gradient over lifetime, then you sample it with UV based on lifetime and type of terrain - you would need to initialize particles with some float/int that indicates type of terrain.

1 Like

Yeah, I needed to initialize the particles with a colour or whatever properties I wanted to stick with the particle, that was rather obvious in hindsight. Using the Tex Index I was able to set the colour over lifetime for the particle (right now just for the alpha), but I was also able to use a little texture atlas of sorts to change the particle texture as well!
Overall everything works well, the contexts for a single trail looks something like this:

However, there’s one thing that’s still bugging me. The original implementation used gradient mapping to colour the texture, hence why the colour parameter was a gradient. Is there any way to say, fake the gradient mapping? Or sample the texture manually so I can initialize the particle with the right colours?


I am not sure I understood the question. If you meant gradient mapping option in the output context, then you would need to create your own custom shader I guess.