Recently, I took part in Arm’s Shadertoy hackathon, where my team won the only Professional Award out of 11 teams. Here, I’ll document the projects I created and experimented with on Shadertoy.

Drawing Chinese Characters with Bézier Curves

By utilizing the signed distance field (SDF) of Bézier curves—which include start and end points, start and end thickness, and curvature—we can create smooth, intricate lines. This technique is ideal for drawing the complex strokes of Chinese characters.

For a closer look at this shader, check out the demo on Shadertoy: Shadertoy Demo.

Fireworks Forming Chinese Characters

The initial idea was to generate fireworks that form Chinese characters by sampling from the sdfCurvedLine function to define basic shapes. However, two main challenges arose: slow rendering, which impacted real-time performance, and rough character shapes, leading to poor visual quality.

To address these issues, I implemented importance sampling to distribute points more evenly across the strokes.

Key Steps:

  1. Segment Assignment: Assign points to each curve segment based on its relative length.
  2. Time Parameter (t): Calculate the interpolation parameter t within each segment.
  3. Position Calculation: Use the start point, end point, curvature, and t to compute the exact position of each point.

The result is a more accurate and efficient rendering of characters formed by fireworks.

For a detailed demonstration, see the shader on Shadertoy: Shadertoy Demo.

Mid-Autumn Fireworks

For a detailed view of this shader implementation, check out the demo on Shadertoy: Shadertoy Demo, or watch the video.

Resources for Learning Shadertoy

  1. InspirNathan’s Shader Topics: A fantastic starting point for ShaderToy.

  2. Inigo Quilez’s Dist Function Articles: A deep dive into signed distance functions (SDF), which are essential for creating smooth shapes and curves. Check out Dist Functions 2D and Dist Functions.

  3. Inigo Quilez’s Shadertoy Page: A collection of impressive shader examples that demonstrate the power and versatility of Shadertoy. Explore Inigo’s Shadertoy.

  4. The Book of Shaders: An excellent online resource for learning the fundamentals of shaders. Visit The Book of Shaders.

Guide for Shadertoy

This guide covers the parts of GLSL ES relevant for Shadertoy. For the complete specification, refer to the GLSL ES Specification.

Arithmetic Operators

  • () + - ! * / %

Logical/Relational Operators

  • ~ < > <= >= == != && ||

Bit Operators

  • & ^ | << >>

Comments

  • // for single-line
  • /* */ for multi-line

Types

  • void
  • bool
  • int
  • uint
  • float
  • vec2, vec3, vec4
  • bvec2, bvec3, bvec4
  • ivec2, ivec3, ivec4
  • uvec2, uvec3, uvec4
  • mat2, mat3, mat4
  • sampler2D, sampler3D, samplerCube

Format

  • float a = 1.0;
  • int b = 1;
  • uint i = 1U;
  • int i = 0x1;

Function Parameter Qualifiers

  • in, out, inout

Global Variable Qualifiers

  • const

Vector Components

  • .xyzw, .rgba, .stpq

Flow Control

  • if, else, for, return, break, continue, switch/case

Output

  • vec4 fragColor

Input

  • vec2 fragCoord

Preprocessor Directives

  • #
  • #define
  • #undef
  • #if
  • #ifdef
  • #ifndef
  • #else
  • #elif
  • #endif
  • #error
  • #pragma
  • #line

Built-in Functions

Function Description
type radians (type degrees) Converts degrees to radians
type degrees (type radians) Converts radians to degrees
type sin (type angle) Computes sine
type cos (type angle) Computes cosine
type tan (type angle) Computes tangent
type asin (type x) Computes arcsine
type acos (type x) Computes arccosine
type atan (type y, type x) Computes arctangent
type atan (type y_over_x) Computes arctangent of y/x
type sinh (type x) Computes hyperbolic sine
type cosh (type x) Computes hyperbolic cosine
type tanh (type x) Computes hyperbolic tangent
type asinh (type x) Computes hyperbolic arcsine
type acosh (type x) Computes hyperbolic arccosine
type atanh (type x) Computes hyperbolic arctangent
type pow (type x, type y) Computes x raised to the power of y
type exp (type x) Computes e raised to the power of x
type log (type x) Computes the natural logarithm
type exp2 (type x) Computes 2 raised to the power of x
type log2 (type x) Computes the base-2 logarithm
type sqrt (type x) Computes the square root
type inversesqrt (type x) Computes the inverse square root
type abs (type x) Computes the absolute value
type sign (type x) Computes the sign of x
type floor (type x) Rounds down to the nearest integer
type ceil (type x) Rounds up to the nearest integer
type trunc (type x) Truncates to the nearest integer
type fract (type x) Computes the fractional part of x
type mod (type x, float y) Computes the modulo
type modf (type x, out type i) Decomposes x into integer and fractional parts
type min (type x, type y) Returns the minimum of x and y
type max (type x, type y) Returns the maximum of x and y
type clamp (type x, type minV, type maxV) Clamps x to the range [minV, maxV]
type mix (type x, type y, type a) Computes a linear interpolation between x and y
type step (type edge, type x) Performs step function
type smoothstep (type a, type b, type x) Performs smooth interpolation
float length (type x) Computes the length of x
float distance (type p0, type p1) Computes distance between p0 and p1
float dot (type x, type y) Computes the dot product
vec3 cross (vec3 x, vec3 y) Computes the cross product
type normalize (type x) Normalizes x
type faceforward (type N, type I, type Nref) Computes the forward face
type reflect (type I, type N) Computes reflection
type refract (type I, type N, float eta) Computes refraction
float determinant (mat? m) Computes the determinant
mat?x? outerProduct (vec? c, vec? r) Computes the outer product
type matrixCompMult (type x, type y) Computes component-wise matrix multiplication
type inverse (type inverse) Computes the inverse of a matrix
type transpose (type inverse) Computes the transpose of a matrix
vec4 texture (sampler?, vec? coord [, float bias]) Samples a texture
vec4 textureLod (sampler, vec? coord, float lod) Samples a texture at a specific level of detail.
vec4 textureLodOffset (sampler?, vec? coord, float lod, ivec? offset) Samples a texture at a specified LOD with an offset.
vec4 textureGrad (sampler?, vec? coord, vec2 dPdx, vec2 dPdy) Samples a texture using derivatives for gradient computation.
vec4 textureGradOffset (sampler?, vec? coord, vec2 dPdx, vec2 dPdy, vec? offset) Samples a texture with gradients and an offset.
vec4 textureProj (sampler?, vec? coord [, float bias]) Projects a texture.
vec4 textureProjLod (sampler?, vec? coord, float lod) Projects a texture at a specific level of detail.
vec4 textureProjLodOffset (sampler?, vec? coord, float lod, vec? offset) Projects a texture at LOD with an offset.
vec4 textureProjGrad (sampler?, vec? coord, vec2 dPdx, vec2 dPdy) Projects a texture using gradients.
vec4 texelFetch (sampler?, ivec? coord, int lod) Fetches a texel from a texture.
vec4 texelFetchOffset (sampler?, ivec? coord, int lod, ivec? offset) Fetches a texel with an offset.
ivec? textureSize (sampler?, int lod) Returns the size of a texture.
type dFdx (type x) Computes the derivative in the x direction.
type dFdy (type x) Computes the derivative in the y direction.
type fwidth (type p) Computes the sum of absolute derivatives in x and y.
type isnan (type x) Checks if x is NaN.
type isinf (type x) Checks if x is infinite.
float intBitsToFloat (int v) Converts int bit representation to float.
uint uintBitsToFloat (uint v) Converts uint bit representation to float.
int floatBitsToInt (float v) Converts float bit representation to int.
uint floatBitsToUint (float v) Converts float bit representation to uint.
uint packSnorm2x16 (vec2 v) Packs a normalized signed 2D vector into 16 bits.
uint packUnorm2x16 (vec2 v) Packs a normalized unsigned 2D vector into 16 bits.
vec2 unpackSnorm2x16 (uint p) Unpacks a normalized signed 2D vector from 16 bits.
vec2 unpackUnorm2x16 (uint p) Unpacks a normalized unsigned 2D vector from 16 bits.
bvec lessThan (type x, type y) Checks if x is less than y.
bvec lessThanEqual (type x, type y) Checks if x is less than or equal to y.
bvec greaterThan (type x, type y) Checks if x is greater than y.
bvec greaterThanEqual (type x, type y) Checks if x is greater than or equal to y.
bvec equal (type x, type y) Checks if x is equal to y.
bvec notEqual (type x, type y) Checks if x is not equal to y.
bool any (bvec x) Checks if any component of x is true.
bool all (bvec x) Checks if all components of x are true.
bvec not (bvec x) Computes the logical NOT of x.

Here’s the formatted version for the conversions and Shadertoy inputs/outputs in Markdown:

Conversions

  • Int to Float: int(uv.x * 3.0)

How to

Use structs:

1
2
3
4
5
struct myDataType { 
float occlusion;
vec3 color;
};
myDataType myData = myDataType(0.7, vec3(1.0, 2.0, 3.0));

Initialize arrays:

1
float[] x = float[](0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6);  

Do conversions:

1
2
int a = 3; 
float b = float(a);

Do component swizzling:

1
2
vec4 a = vec4(1.0, 2.0, 3.0, 4.0); 
vec4 b = a.zyyw;

Access matrix components:

1
2
3
4
mat4 m; 
m[1] = vec4(2.0);
m[0][0] = 1.0;
m[2][3] = 2.0;

Be careful!

  • The f suffix for floating point numbers: 1.0f is illegal in GLSL. Use 1.0.
  • saturate(): saturate(x) doesn’t exist in GLSL. Use clamp(x, 0.0, 1.0) instead.
  • pow/sqrt: Please don’t feed sqrt() and pow() with negative numbers. Add abs() or max(0.0, x) to the argument.
  • mod: Please don’t do mod(x, 0.0). This is undefined on some platforms.
  • Variables: Initialize your variables! Don’t assume they’ll be set to zero by default.
  • Functions: Don’t name your functions the same as some of your variables.

Shadertoy Inputs

Type Name Description
vec3 iResolution Image/buffer: The viewport resolution (z is pixel aspect ratio, usually 1.0)
float iTime Image/sound/buffer: Current time in seconds
float iTimeDelta Image/buffer: Time it takes to render a frame, in seconds
int iFrame Image/buffer: Current frame
float iFrameRate Image/buffer: Number of frames rendered per second
float iChannelTime[4] Image/buffer: Time for channel (if video or sound), in seconds
vec3 iChannelResolution[4] Image/buffer/sound: Input texture resolution for each channel
vec4 iMouse Image/buffer: xy = current pixel coords (if LMB is down). zw = click pixel
sampler2D iChannel{i} Image/buffer/sound: Sampler for input textures i
vec4 iDate Image/buffer/sound: Year, month, day, time in seconds in .xyzw
float iSampleRate Image/buffer/sound: The sound sample rate (typically 44100)

Shadertoy Outputs

Image shaders:

fragColor is used as output channel. It is not mandatory, but recommended to leave the alpha channel to 1.0.

Sound shaders:

The mainSound() function returns a vec2 containing the left and right (stereo) sound channel wave data.