Hello Community,
am working to convert a relatively simple object-based system into a particles based system to increase performance.
To be exact it’s this fish (and bird) swarm simulator here: https://assetstore.unity.com/packages/3d/characters/animals/nvjob-simple-boids-flocks-of-birds-fish-and-insects-164188

The actual swarming\movement mechanics can be converted nicely to the job\burst system (and I’ll likely offer a pull request on their Github once done). It more than doubles the max frames.
What I’m struggling with is porting a neat extra feature included: A shader that undulates the unanimated fish mesh as if it were swimming.
This shader does work on separate meshes but breaks when applied to mesh particles.
Here on the top-left is an object with regular mesh renderer. The tripplets of fishes are particles:
https://www.dropbox.com/s/yzvo9ftlw1djtec/Fish%20Shader%202.avi?dl=0
The effect is obviously applied wrongly. Not only to the wrong axis it seems but also awkwardly scale with the distance from the particle systems origin.
Renderer Configuration for the particles:

This is the original vertex transformation code that works with regular meshes:
void vert(inout appdata v) {
UNITY_SETUP_INSTANCE_ID(v);
float3 wp = mul(unity_ObjectToWorld, half4(1, 1, 1, 1)).xyz;
float timeY = _Time.y;
half sinT = sin((timeY + sin(wp.y * 0.5) + _ScriptControl) * _SwimmingSpeed);
half flap = sinT * _SwimmingPower;
half zf = (v.vertex.z * v.vertex.z) - (v.vertex.z * _WaveBody);
v.vertex.x += sin(zf / _SwimmingScale) * flap;
v.vertex.y += sin(zf / 10) * flap * _Wobble;
v.vertex.y += sin((timeY + sin((wp.x + wp.y) * _WaveY * 0.6)) * _WaveYSpeed) * _WaveY;
}
Now I have tried different tips read across the internet for this problem but cannot quite bend my mind around it.
Especially from this thread, it says to apply the “_Camera2World” matrix retrieved through C#:
https://discussions.unity.com/t/531927
So I wrote this which attempts to convert to world space, perform the undulation and then convert back:
UNITY_SETUP_INSTANCE_ID(v);
float3 wp = mul(unity_ObjectToWorld, half4(1, 1, 1, 1)).xyz;
float4 worldSpaceVertex = mul(_Camera2World, v.vertex);
float timeY = _Time.y;
half sinT = sin((timeY + sin(wp.y * 0.5) + _ScriptControl) * _SwimmingSpeed);
half flap = sinT * _SwimmingPower;
half zf = (worldSpaceVertex.z * worldSpaceVertex.z) - (worldSpaceVertex.z * _WaveBody);
worldSpaceVertex.x += sin(zf / _SwimmingScale) * flap;
worldSpaceVertex.y += sin(zf / 10) * flap * _Wobble;
worldSpaceVertex.y += sin((timeY + sin((wp.x + wp.y) * _WaveY * 0.6)) * _WaveYSpeed) * _WaveY;
v.vertex = mul(_World2Camera, worldSpaceVertex);
Unfortunately the result did not seem to point in the right direction at all. It only makes distortions more extreme.
Is something similar the solution to the recurring problem?
Something interesting from that thread:
What are “instanced mesh particles”? I can only find information about GPU instancing when I’m searching this, but I doubt that’s what they meant.
It would be nice if there were a way to make the mesh particles behave like an instance (just without the gameobject and mesh renderer overhead).
Anybody have an idea or questions?
Huge thanks!
