Vertex Position Shader not updating in VFX

Hey, I intend to implement a swarm of birds using VFX graph and I’m kind of stuck with it. Initially tried to accomplish such using Blend Shapes (but gave up after some online search as I couldn’t find any feasible way to animate them in VFX graph).
7723771--969517--upload_2021-12-10_0-55-52.png
So I made a very simple shader graph (tried Unlit URP adding VFX as target and same shader as a VFX Shader Graph) but after applying it a mesh Output in the Graph itself it doesn’t seem to animate at all.


7723771--969508--upload_2021-12-10_0-53-39.png
I assume that changing vertex position is not available with the VFX graph. If so, how could I accomplish this animation without baking into a flipbook sprite animation?

7723771--969508--upload_2021-12-10_0-53-39.png

Vertex displacement should be available in Unity 2021.2, old versions does not support that.
However the important note - it works only when your shader graph has “Support VFX” enabled (checkbox in graph settings). Visual Effect target does not support it.

Oh ok, sadly I’m constraint to using Unity’s version 2020. I’ll figure out a different approach then :confused:

Dunno if you still need this but I came up with my own custom solution. I don’t think blendshapes is the right way to go about it and sounds terribly expensive, lol. My technique is pure math and vertex shader logic and it can support hundreds of thousands of animated birds on my oldest laptop which has an old GTX 1080 … on my desktop with an RTX 3080Ti the birds can black out the whole screen and it still runs smoothly lol. You just need to be super efficient with the meshes, textures and approach.

The way I do it is (to give a high-level explanation) is to create a UV set for the bird where the non-animated parts (i.e., most of the body) are beneath a certain V-axis threshold. In mine, this was about 0.35f on the V (aka “Y” or “up”) axis. Then, the bird’s wings are UV mapped such that they stretch out horizontally toward the min/max of the U-axis and almost (but not quite) meet in the center (0.5f). So one wingtip nearly touches 0.0 and the other 1.0 of the U-axis (same as “X” or “horizontal” in tangent/texture space). Then, the vertex shader applies displacement to vertices and masks and weights it with the help of this UV layout to decide on a final “strength” of the transformation. This is accomplished like so:

  • Mask out everything below the V-axis threshold (about 0.35f in my UV set), so you end up with a black strip at the bottom from 0.0 to 0.35 and then everything above that is 1.0 (white).

  • Next, we see how far from the middle of the UV map the vertex UV point is: such as abs( vert.U - 0.5f ) or something, which basically creates a gradient effect where the middle of the UV/texture coords is solid black (0,0,0,0) and turns into white at the edges (0.0 and 1.0). That gives us the “vert displacement strength” mask.

  • The final part is to use some kind of oscillation or wave, like a sine/cosine wave, Gerstner wave or Forrier or whatever – and I did this with birds but it can also be translated to fish, insects or just about anything that has a repeating motion of the limbs (you can also encode more complex movement data into textures and sample them for really crazy stuff lol). A simple amplitude * sin( time * freq ) formula will work here though to get a nice, controlled repeating wave you can adjust, where “amplitude” is the wave height/intensity and “freq” is the frequency or speed.

In the case of our birds, amplitude will control the height or movement range of wing beats and freq will be the speed of the wing beats, which makes it controllable in a material instance (and they also won’t be stuck with the same timing of wing beats and look like a creepy hivemind swarm moving in perfect unison, just randomize these values a bit for each instance, lol). You then simply multiply each vertex by a float called “vertOffset” or “wingStroke” or whatever you wanna call it: computed as the wave output value times the horizontal mask times the vertical mask. The horizontal mask causes the vertices closest to the body to be offset none/least, and the wing tips to move up/down the most. And the vertical mask ensures that anything which isn’t a wing vertex is left alone. Final part of the vertex shader or graph is simply split/swizzle current position and add vertOffset + vertex.Y, then combine it to a new float3/vector3 position and return it.

Hopefully this makes sense and isn’t overly-technical or complicated, but I suspect most people will go glazed-eyed trying to comprehend it since shaders confuse most people, lol. For that reason, I plan to upload an asset to the store soon with a few versions of this for different creatures and movements with some low-poly creature models/samples supplied and documentation on how to UV map and assign materials to new ones. :slight_smile: