Shapes

This shader generates various geometric shapes based on UV coordinates, allowing for creative designs and patterns. It can be used for backgrounds, overlays, or decorative elements in your graphics.

The first step to create a shape is to calculate its signed distance field (SDF). SDF is a function or texture where each value represents the shortest distance from a point to the nearest surface, with the sign indicating whether the point is inside (negative) or outside (positive) the shape.

For example, to create a circle, you can use the following code:

float circleSdf(float2 uv) { 
  return length(uv - .5) * 2; 
}

Other shapes can be created similarly by defining their SDF functions. Here are some examples:

float triangleSdf(float2 uv) {
  uv = (uv * 2 - 1) * 2;
  return max(-uv.y * .5, uv.y * .5 + abs(uv.x) * 0.8660254038); // 0.8660254038 is height of equilateral triangle
}

float squareSdf(float2 uv) {
  uv = uv * 2 - 1;
  return max(abs(uv.x), abs(uv.y));
}

float rectangleSdf(float2 uv, float aspectRatio) {
  uv = uv * 2 - 1;
  return max(abs(uv.x * aspectRatio), abs(uv.y));
}

It is also possible to create polygon by defining number of sides. We use the polar coordinate system to calculate the distance from the center to the edge of the polygon:

#define TAU 6.28318530718
float polygonSdf(float2 uv, int sides) {
  uv = uv * 2 - 1;
  float angle = atan2(uv.x, uv.y) + TAU * .5;
  float radius = length(uv);
  float anglePerSide = TAU / float(sides);
  return cos(floor(.5 + angle / anglePerSide) * anglePerSide - angle) * radius;
}

When we have the SDF for a shape, we can use it to determine the color of each pixel based on whether it is inside or outside the shape. For example, to fill the shape with a color, we can use the following code:

float sdf = circleSdf(uv);
float inside = step(sdf, size); // 1 when inside the shape, 0 when outside
float3 color = lerp(bgColor, shapeColor, inside);

We can also use the SDF to create outlines or borders by using a threshold value:

float outline(float sdf, float s, float width) {
  float v = step(s, sdf + width * .5) - step(s, sdf - width * .5);
  return saturate(v);
}

...

float sdf = circleSdf(uv);
float outlineColor = outline(sdf, .5, .02);