Another cool thing about distance functions: everything you've learn so far generalises to 3D! Using a technique called raymarching we can draw out a 3D distance function entirely in a fragment shader.
We've hidden the code that does this because it can be a lot to take on at once, but you can find a bunch of examples online. To name a few:
{"bannedTokens":[],"prefix":"uniform vec2 iResolution;\nuniform float iGlobalTime;\n\nfloat getDistanceFromPoint(vec3 point);\nvec3 draw_line(float d);\nfloat draw_solid(float d);\nvec3 draw_distance(float d, vec2 p);\n\nmat3 calcLookAtMatrix(vec3 origin, vec3 target, float roll) {\n vec3 rr = vec3(sin(roll), cos(roll), 0.0);\n vec3 ww = normalize(target - origin);\n vec3 uu = normalize(cross(ww, rr));\n vec3 vv = normalize(cross(uu, ww));\n\n return mat3(uu, vv, ww);\n}\n\nvec3 calcNormal(vec3 pos, float eps) {\n const vec3 v1 = vec3( 1.0,-1.0,-1.0);\n const vec3 v2 = vec3(-1.0,-1.0, 1.0);\n const vec3 v3 = vec3(-1.0, 1.0,-1.0);\n const vec3 v4 = vec3( 1.0, 1.0, 1.0);\n\n return normalize( v1 * getDistanceFromPoint( pos + v1*eps ) +\n v2 * getDistanceFromPoint( pos + v2*eps ) +\n v3 * getDistanceFromPoint( pos + v3*eps ) +\n v4 * getDistanceFromPoint( pos + v4*eps ) );\n}\n\nvec3 getRay(vec3 origin, vec3 target, vec2 screenPos, float lensLength) {\n mat3 camMat = calcLookAtMatrix(origin, target, 0.0);\n return normalize(camMat * vec3(screenPos, lensLength));\n}\n\nfloat intersectPlane(vec3 ro, vec3 rd, vec3 nor, float dist) {\n float denom = dot(rd, nor);\n float t = -(dot(ro, nor) + dist) / denom;\n\n return t;\n}\n","suffix":"float beckmannDistribution(float x, float roughness) {\n float NdotH = max(x, 0.0001);\n float cos2Alpha = NdotH * NdotH;\n float tan2Alpha = (cos2Alpha - 1.0) / cos2Alpha;\n float roughness2 = roughness * roughness;\n float denom = 3.141592653589793 * roughness2 * cos2Alpha * cos2Alpha;\n return exp(tan2Alpha / roughness2) / denom;\n}\n\nfloat cookTorranceSpecular(\n vec3 lightDirection,\n vec3 viewDirection,\n vec3 surfaceNormal,\n float roughness,\n float fresnel) {\n\n float VdotN = max(dot(viewDirection, surfaceNormal), 0.0);\n float LdotN = max(dot(lightDirection, surfaceNormal), 0.0);\n\n //Half angle vector\n vec3 H = normalize(lightDirection + viewDirection);\n\n //Geometric term\n float NdotH = max(dot(surfaceNormal, H), 0.0);\n float VdotH = max(dot(viewDirection, H), 0.000001);\n float x = 2.0 * NdotH / VdotH;\n float G = min(1.0, min(x * VdotN, x * LdotN));\n\n //Distribution term\n float D = beckmannDistribution(NdotH, roughness);\n\n //Fresnel term\n float F = pow(1.0 - VdotN, fresnel);\n\n //Multiply terms and done\n return G * F * D / max(3.14159265 * VdotN * LdotN, 0.000001);\n}\n\nvoid main() {\n float time = iGlobalTime * 0.025;\n vec2 uv = 2.0 * gl_FragCoord.xy / iResolution - 1.0;\n vec3 ro = vec3(sin(time), 1.0, cos(time));\n vec3 ta = vec3(0);\n vec3 rd = getRay(ro, ta, uv, 2.0);\n\n float t = -1.0;\n float mind = 0.01;\n float maxd = 10.0;\n float latest = 1.0;\n for (int i = 0; i < 30; i++) {\n if (latest < mind || t > maxd) break;\n t += (latest = getDistanceFromPoint(ro + rd * t));\n }\n\n float tPlane = intersectPlane(ro, rd, vec3(0, 1, 0), 0.0);\n\n if (tPlane > -0.5 && tPlane < t) {\n vec3 pos = ro + rd * tPlane;\n gl_FragColor = vec4(draw_distance(getDistanceFromPoint(pos) - 0.0125, pos.xz), 1);\n } else\n if (t > maxd) {\n gl_FragColor = vec4(0, 0, 0, 1);\n } else {\n vec3 pos = ro + rd * t;\n vec3 normal = calcNormal(pos, 0.002);\n vec3 ldir = normalize(vec3(0, 1, 0.2));\n float mag = max(0.2, dot(normal, ldir));\n\n mag = pow(mag, 0.3545);\n mag *= 1.75;\n //mag = 0.0;\n\n gl_FragColor = vec4(mag * vec3(0.95, 0.45, 0.15), 1);\n gl_FragColor.rgb += cookTorranceSpecular(ldir, -rd, normal, 1.0, 3.25) * 1.5;\n }\n}\n\nvec3 draw_line(float d) {\n const float aa = 3.0;\n const float thickness = 0.0025;\n return vec3(smoothstep(0.0, aa / iResolution.y, max(0.0, abs(d) - thickness)));\n}\n\nfloat draw_solid(float d) {\n return smoothstep(0.0, 3.0 / iResolution.y, max(0.0, d));\n}\n\nvec3 draw_distance(float d, vec2 p) {\n float t = clamp(d * 0.85, 0.0, 1.0);\n vec3 grad = mix(vec3(1, 0.8, 0.5), vec3(0.3, 0.8, 1), t);\n\n float d0 = abs(1.0 - draw_line(mod(d + 0.1, 0.2) - 0.1).x);\n float d1 = abs(1.0 - draw_line(mod(d + 0.025, 0.05) - 0.025).x);\n float d2 = abs(1.0 - draw_line(d).x);\n vec3 rim = vec3(max(d2 * 0.85, max(d0 * 0.25, d1 * 0.06125)));\n\n grad -= rim * clamp(1.25 - d, 0.0, 1.0);\n grad -= 1.0 - clamp(1.25 - d * 0.25, 0.0, 1.0);\n grad -= mix(vec3(0.05, 0.35, 0.35), vec3(0.0), draw_solid(d));\n\n return grad;\n}\n","question":"//\n// In this example, the sphere's origin is (0, 0, 0).\n//\n// Change it so that the sphere resets directly on top of\n// (0, 0, 0) based on the radius.\n//\nfloat getDistanceFromPoint(vec3 point) {\n float radius = (sin(iGlobalTime * 0.1) * 0.5 + 0.5) * 0.25;\n\n return length(point) - radius;\n}\n","solution":"float getDistanceFromPoint(vec3 point) {\n float radius = (sin(iGlobalTime * 0.1) * 0.5 + 0.5) * 0.25;\n return length(point - vec3(0, radius, 0)) - radius;\n}\n","name":"11-add-a-dimension"}