The important part of the vertex shader that moves the end of the swoosh is below:
// For screen shooshes smoosh the mesh flat on the Y axis v.vertex.y *= 1.0 - _ScreenSquish; // Add some random offset on the X and Z zxis for screen swooshes float2 divergence = _Divergence.xy * saturate( sin ( v.uv.x * UNITY_PI ) ); v.vertex.xz += divergence * _ScreenSquish; // Find the start position of the swoosh float3 worldOrigin = mul( unity_ObjectToWorld, float4(0,0,0,1) ).xyz; // Now figure out the end position relative to the start position float3 endOffset = _TargetPos - worldOrigin; // Get the world position of the vertex float3 worldPos = mul( unity_ObjectToWorld, v.vertex ).xyz; // Add the end offset to the vertex world position masked byt the uv coordinates worldPos += endOffset * v.uv.x; // Transform the world position to screen position o.vertex = mul(UNITY_MATRIX_VP, float4(worldPos,1)); // Smoosh the swoosh against the screen if it is a screen swoosh o.vertex.z = lerp( o.vertex.z, o.vertex.w, _ScreenSquish * 0.99 );_ScreenSquish is a float from 0-1 that is passed in from script telling the swoosh if it should be pressed against the screen, like the coin collect swooshes. This keeps is from being occluded by any opaque geometry while still being attached to a point in the world. It still follows a world space position but that position is attached to the screen.
_Divergence is a float2 passed in from script that adds some offset the the middle of the swoosh so screen swooshes don't overlap and follow a bit of a random path.
The pixel shader is pretty simple, here's the basic swoosh texture lookup with a bit of fade out on either end:
// texture coords for swoosh texture float2 swooshUV = saturate( IN.uv * _Tiling.xy + float2( lerp( _Tiling.z, _Tiling.w, _Ramp ), 0 ) ); half4 col = tex2D(_MainTex, swooshUV ) * _Color; // start and end fade in half edgeFade = saturate( ( 1.0 - abs( IN.uv.x * 2 - 1 ) ) * (1.0 / _FadeInOut ) ); edgeFade = smoothstep(0,1,edgeFade); // multiply together col *= edgeFade;_Ramp is passed in from script to control the swoosh travel progression.
_Tiling is set in the material and allows for control of the length of the swoosh and how _Ramp effects the swoosh travel.
_FadeInOut is lets you set how mush on the ends of the swoosh to fade out.
A material property block can be used to send the information right to the swoosh renderer without messing with the materials at all like so:
MaterialPropertyBlock MPB = new MaterialPropertyBlock (); Renderer thisRenderer = this.GetComponentNow a swoosh can be spawned anywhere, its script will drive _Ramp over a specified time, you know exactly when it will reach the end and what it will look like along the way. Even when moving the camera a screen swoosh will always start at its world position and end at the screen position, the shape is always smooth and movement always fluid. Lucky's tail swipe uses the same shader with an extra texture overlay to make it look more wispy. The tail swoosh is spawned at Lucky's position and rotation and then the end position is just updated to be Lucky's current position. If Lucky is jumping, the tail swoosh it will follow him in the air while maintaining its smooth shape. It's a subtle effect but helps tie it to Lucky. But we're not done yet. You can get really fancy with a geometry shader by turning each triangle into a little particle. Here one of the swoosh ribbons has the swoosh particle shader on it. This shader turned each triangle into its own quad and gave it some movement over its lifetime. Because this is just a shader you can play the whole effect backwards. And like the regular swooshes, the particle swooshes update their positions when the target moves. How exactly that all works may be a post for another day though.(); if (targetScreen) { MPB.SetFloat ("_ScreenSquish", 1.0f); MPB.SetVector ("_Divergence", new Vector2 (Random.Range (-screenDivergence, screenDivergence), Random.Range (-screenDivergence, screenDivergence))); } MPB.SetFloat("_Ramp", ramp); thisRenderer.SetPropertyBlock (MPB);
That game looks fab. If only it was in VR...
ReplyDelete