The effect you are trying to reproduce recomputes the velocity each frame based on the mesh normal, like so:
function void Eval()
float3 normal = Shape.sampleNormal(ProjCoords);
Velocity = lerp(float3(0), normalize(cross(normal, scene.axisUp())) * 2, LifeRatio) + Velocity.0y0;
(I assume you already have the effect file of the original effect?)
The reason the original effect works and yours doesn't is because it recomputes the Velocity each frame as being tangent to the mesh (actually, it's the vector perpendicular to the plane defined by the mesh normal and the 'up' axis, that's what the 'cross' function computes)
whereas yours reuses the previous frame's velocity. The original effect forces the velocity to rotate around the mesh on the horizontal plane, but your version keeps it going in whatever direction it goes, so it ends up being stuck.
Note that the original effect would also exhibit stuck particles if the hat was rotated 90 degrees and its sharp edges were vertical instead of being horizontal.
This artefact is inherent to the way the projection evolver works: when your particle goes on a sharp edge and moves away from that edge, it will try to find an approximate location on the mesh where it should reproject it. For sharp edges like the hat borders, it's usually the same place (or close to) on that same edge, so the particle ends up being stuck here.
Some more details about the script above:
the 'lerp' is just to make the velocity gradually larger as the particle ages.
the '+ Velocity.0y0' is here to keep a small nonzero vertical component in case the projection evolver modified the velocity when projecting it onto the surface.
If you don't want the movement to rotate on the horizontal plane, or have a more complex mesh with hard creases, you can approach the problem differently:
- Have two sets of position: one "simulation" position, and one "snapped" position
- have the simulation position rotate the way you want
- copy the sim position into the snapped position field
- run the projection evolver so it reprojects the snapped position, NOT the sim position
- setup your renderers to use the snapped position
This method will ensure your particles never get stuck, but it suffers from two main issues:
- Performance: the further away your positions are from the projection mesh, the more expensive projection becomes (the maximum cost is reached and stays constant when the particles are outside the mesh bbox, so perf doesn't degrade indefinitely, if that can be a relief :) )
Highest performance is reached when the particles are already on the mesh surface, or very close to it
- Accuracy: the further away your positions are, the less accurate it becomes, and particles can jump around the mesh as they rotate around it.
Basically, as the projection evolver is mostly a hack, you'll have to try out different methods see which one best fits the effect you're trying to achieve.
Something else that could help is to add a turbulence to the particle velocity, to jitter the velocity around, it might help make particles move around more and not get stuck.
Hope this helps !