As the character in Chameleon Run runs, a water-like blur effect is created. I would really appreciate some guidelines on how I could create this effect in SpriteKit and Unity. Please see the image below.

enter image description here

  • \$\begingroup\$ @Bálint just updated the question \$\endgroup\$ – Hilarious404 Mar 18 '17 at 4:29

It looks to me like this could be done with a TrailRenderer. This leaves a ribbon of 3D geometry behind a moving object, onto which we can assign a material to control the way it renders.

We can use a custom shader incorporating a GrabPass to take a snapshot of the frame buffer, sampling it with a distortion offset, to get a refractive watery look:

Shader "Unlit/DistortionTrail"
        _Intensity ("Intensity", Range(-1, 1)) = 1
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}
        LOD 100

        GrabPass {"_Refract"}

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;

            struct v2f
                float2 uv : TEXCOORD0;              
                float4 projected : TEXCOORD1;
                float4 vertex : SV_POSITION;

            sampler2D _Refract;         
            float2 _Refract_TexelSize;

            float _Intensity;

            v2f vert (appdata v)
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.projected = o.vertex;

            // Some video settings flip the captured image - flip it back.
            #if UNITY_UV_STARTS_AT_TOP
                o.projected.y *= sign(_Refract_TexelSize.y);

                return o;

            fixed4 frag (v2f i) : SV_Target
                // Convert interpolated vertex position in device coordinates
                // into a texture coordinate in the range 0...1
                float2 screenUV = (i.projected.xy / i.projected.w) * 0.5f + 0.5f;

                // Ripple the distortion across the width of the trail.
                // (squaring y makes the ripples look a bit less rigid/uniform)
                float distortion = sin(i.uv.y * i.uv.y * 3.141592653589f * 5.0f);

                // Fade the distortion along the length of the trail.
                distortion *= 1.0f - i.uv.x;

                // Control max distortion using material parameter.
                distortion *= _Intensity;

                // Offset our lookup coordinates using the distortion.
                screenUV += distortion * float2(0.5, 1);

                // Sample the captured snapshot of the frame.
                fixed4 col = tex2D(_Refract, screenUV);

                return col;

Here's an example of this in motion:

enter image description here

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.