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 9 of 10 · Fractals in GLSL

Orbit trap

Do not count the escape: measure how close the orbit passed.

So far we colored by when z escapes. The orbit trap colors by where it passed. On each iteration, z hops across the plane drawing an orbit; we measure the minimum distance of that orbit to a trap, here a ring.

Where the orbit grazes the ring, the frag lights up. You get veins of light snaking inside and outside the set, a geometry completely different from the escape rings.

trap = min(trap, abs(length(z) - 0.8))Each step we compare the distance of z to a ring of radius 0.8 and keep the smallest of the whole orbit. That minimum distance is the color: near the trap = bright; far = dim.
TryMove the radius in length(z)-0.8 to 0.3 and the veins reorganize. Raise the sharpness in 1.0-trap*1.5 to 3.0 for finer filaments.

The code

precision highp float;
void main(){
  vec2 uv=(gl_FragCoord.xy*2.0 - R)/R.y;
  float zoom=1.4;
  vec2 c=uv*zoom+vec2(-0.6,0.0);
  vec2 z=vec2(0.0);
  float trap=1000.0;
  bool esc=false;
  const int IT=120;
  for(int i=0;i<IT;i++){
    z=vec2(z.x*z.x-z.y*z.y, 2.0*z.x*z.y)+c;
    trap=min(trap, abs(length(z)-0.8));
    if(dot(z,z)>256.0){ esc=true; break; }
  }
  float vein=pow(clamp(1.0-trap*1.5,0.0,1.0),2.0);
  vec3 col=0.5+0.5*cos(6.2831*(trap*0.7+vec3(0.0,0.33,0.66)));
  col=col*0.35 + vec3(1.0,0.9,0.7)*vein*0.95;
  gl_FragColor=vec4(col,1.0);
}
close