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\$ Commented Mar 18, 2017 at 4:29

1 Answer 1


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


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .