learn GLSL from zero
ToolsCreate with shadersShader MakerFree online shader builderToolkitShader works ready for your siteSketcher LabPaint your landing’s hero with shaders3D StudioThe Three.js editor in your browser
GamesPlay with shadersOnomatoShaderType a word, blow it upThe WatcherAn eye that follows youAetherLiquid glass with an eye insideBloomcoreA word grows a garden of lightPyrokineThrow fire at the wallVoltaicThe pyramid throws lightningSurfSurf a shader ocean

Lesson 5 of 10 · Shader animation

Morph

Circle mutates into hexagon. The shape cannot decide.

Two textures, two worlds. You want one to transform into the other. Not a fade, a mutation.

The trick: two different domain warps and a mix() controlled by time. When t = 0, you see material A. When t = 1, material B. In between: something that is neither.

mix() between two worlds. Matter mutates.

Morph with mix()mix(warpA, warpB, t) interpolates between two domain warps. The result is a mutation, the structure changes, not just the appearance.
TryChange 0.5 (morph speed) to 0.1 for ultra slow transition. Change 0.35 (shared radius of both shapes) to 0.5 and the shapes grow. Add + 1. to T * 0.5 and the morph starts from the other side.

The code

void main(){
  vec2 p = (2.*gl_FragCoord.xy - R) / min(R.x, R.y);
  float t = sin(T * 0.5) * 0.5 + 0.5;
  float r = 0.35;
  float circ = length(p) - r;
  vec2 ap = abs(p);
  float hex = max(ap.x * 0.866 + ap.y * 0.5, ap.y) - r;
  float d = mix(circ, hex, t);
  float shape = smoothstep(0.02, -0.02, d);
  vec2 sp = abs(p + vec2(.05, -.08));
  float shd = mix(length(p+vec2(.05,-.08))-r, max(sp.x*.866+sp.y*.5,sp.y)-r, t);
  float shadow = smoothstep(0.0, 0.3, shd);
  vec3 col = vec3(0.02, 0.04, 0.05) * shadow;
  col += mix(vec3(0.2,0.9,0.7), vec3(0.1,0.6,0.9), t) * shape;
  col += vec3(0.1, 0.5, 0.5) * exp(-max(d,0.)*5.) * 0.4;
  gl_FragColor = vec4(col, 1.);
}
close