Jelly Shader, Part 6: Omni-Directional Movement Axis

Michael Sanders
4 min readMar 2, 2018

--

Part 6 — Omni-directional Movement Axis

This is article 6 in our multi-part series on developing a custom shader for Unity 3D. In this article we will add even more life to our sine wave by giving it a more dynamic movement axis.

Currently, our waves only move along the x-axis. While we could make this work inside Unity using rotations, the better and more robust solution is to allow the shader to handle any potential axis. To do that, we’ll need to use a little trigonometry-magic.

First we need to provide our shader with some more information. Let’s pass along the location in world space where our mouse click collided with the model and the location in world space of the model’s center. Add the following lines right after we set controlTime to zero.

This time, instead of using SetFloat we’re using SetVector because we’re passing along the a 3 dimensional vector and not a float. It should be noted _ModelOrigin and _ImpactOrigin don’t actually exist yet in our shader, let’s fix that. As usual, define the shader variables in the standard way; once in the properties section and once inside the sub shader.

Great! Now we have access to the model’s position and the impact position. Next, let’s create a new float4 vector called direction that represent the direction our wave will travel across the model. Add this line near the top of the vert function.

_ModelOrigin_ImpactOrigin will give us a wave that moves from the impact location towards the center of the model.

Our origin definition now needs a significant change. We’re going to take the basic formula we’re applying to the x component currently, and apply it to whole vectors. The “1.0” we were using as the start of our wave can now be represented by _ImpactOrigin. _ControlTime * _ImpactSpeed can stay largely the same, except they’re just scalars, so to bring them into 3D space and to give them a direction, multiply them by our direction vector. We also replaced the “-” in the formula with a “+” as the direction information is now included inside of direction. This gives us this final formula.

float4 origin = _ImpactOrigin + _ControlTime * _ImpactSpeed * direction;

There’s one more step of intermediary work we need to get to. Currently our _ImpactOrigin and directionvectors are in world space, for the next section we’re going to need those variables in object space, so let’s convert them.

Just like we used unity_ObjectToWorld earlier to bring our vertex position into worldspace, we’re now doing the opposite and using unity_WorldToObject to bring our world position coordinates into model space.

At the beginning of this section I mentioned “trigonometry magic.” Our vertex modification statement currently looks like this.

Notice the v.vertex.x part of the formula? This all works great as long as we only want our waves to move along that x axis. To free of ourselves of that, we need a value that represents the axis our wave is traveling along from impact point to model origin. We’ll call that axis value impactAxis. It’s value is equal to the following formula.

Trigonometry Magic

Explaining what’s going on with this formula is unfortunately way outside the scope of this article. Nor would I be able to explain it in a satisfactory manner if it were. But if you are intensely curious, the formula was adapted from this StackOverflow answer. With P represented by v.vertex, D represented by l_direction, and A represented by l_ImpactOrigin.

Now that we have this impact axis, we no longer need to rely on v.vertex.x inside our vertex modification function. So let’s replace it with our new impactAxis.

At this stage you should be able to fire up Unity and test out the app. Click anywhere on the sphere and a new wave should appear from that location.

Invisible Sphere

If when you first fire up the app your sphere has vanished, click where the sphere should be and it should reappear. This just means your _ImpactOrigin is starting at (0,0,0,0). To fix this, select the sphere inside the Unity editor, expand the JellyMaterial component near the bottom of the Inspector, and change the Impact Origin to be (-5,0,0,0).

The final code for your shader should look like this.

Part 7 of this series can be found here.

Originally published at heliosinteractive.com on March 2, 2018.

--

--

Michael Sanders

Director of Interactive Development at Helios Interactive. And part-time Pirate.