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:
- Segment Assignment: Assign points to each curve segment based on its relative length.
- Time Parameter (t): Calculate the interpolation parameter
t
within each segment. - 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
-
InspirNathan’s Shader Topics: A fantastic starting point for ShaderToy.
-
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.
-
Inigo Quilez’s Shadertoy Page: A collection of impressive shader examples that demonstrate the power and versatility of Shadertoy. Explore Inigo’s Shadertoy.
-
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:
struct myDataType {
float occlusion;
vec3 color;
};
myDataType myData = myDataType(0.7, vec3(1.0, 2.0, 3.0));
Initialize arrays:
float[] x = float[](0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6);
Do conversions:
int a = 3;
float b = float(a);
Do component swizzling:
vec4 a = vec4(1.0, 2.0, 3.0, 4.0);
vec4 b = a.zyyw;
Access matrix components:
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. Use1.0
. - saturate():
saturate(x)
doesn’t exist in GLSL. Useclamp(x, 0.0, 1.0)
instead. - pow/sqrt: Please don’t feed
sqrt()
andpow()
with negative numbers. Addabs()
ormax(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.