Usual tricks in Shadertoy / GLSL

Ever figured the ‘?’ icon at the bottom-right of the source area 🙂 ?
And the “shader Inputs>” on top-left ? 🙂
These are, respectively, a GLSL ES summary, and a list of the Shadertoy variable.

GLSL already knows vectors and matrices

  • comprising operations like length, distance, normalize, dot, cross and mat*vec
  • Many operations directly work on vectors (acting on each components)
  • Some special operations do boolean operations on vectors (all, any, lessthan…)
  • Many operations implictely expend floats to vectors ( v+2., v/=2., step(0.,v)… )
  • and constructors are also casters ( e.g. V=vec4(x>y, 0, vec2(x)) ).
  • GLSL already knows 3D graphics operations such as reflect, refract, faceforward
  • GLSL provides many goodies like clamp, mix (linear interpolation), smoothstep (Hermite weighting)

NB: Complex calculus easily implements as vector and matrices :

  • Use vec2 for definition,  + – between complexes,  + – * / with a float
  • complex multiplication of z1 by z2 is mat2(z1,-z1.y,z1.x) * z2
  • complex division of z1 by z2 is z1 * mat2(z2,-z2.y,z2.x) / dot(z2,z2)

C tricks are good for GLSL perfs and programming ease

  • pow(x,y) is doing exp(y*log(x)): costly, not valid for x<0, not perfect precision.
    • for x^2, do prefer x*x !
    • for 2^x use exp2(x).  the reverse log2 also exist (both in most langages 🙂 ).
  • atan API also includes the 2 parameters version doing atan2(y,x)
  • x = cond ? v1 : v0 can be useful, especially for cascaded small expressions.
  • There should be a law punishing people using if cond then x=true else x=false. Just do directly x= cond 😉
  • macros can be a convenient substitutes for templates (e.g. expressions valid for floats, vec2, vec3, vec4).

Uncomplete integer operations

Many integer operations are missing. Sometime the simplest is to do them on floats then cast (or not). But be careful to precision loss. Still,

  • integers up to 16,777,216 are exactly represented by IEEE floats on 32bits
  • + – * will thus be exact… But not the division: x/x might not be exactly 1.
  • fract and log2 are directly reading the mantissa and exponent so are lossless
  • In particular, << and >> can be represented by *exp2(n) and *exp2(-n)
  • mod on int-in-floats has precision bugs.
    You can do mod directly on ints with  a % b = a-a/b*b
  • Note that you can loop on floats to avoid loads of casts.

GLSL run pixels in parallel

  • So it can computes derivative of any variable for free ! dFdx, dFdy, fwidth
    (The precision is approximate, though: uncentered finite differences within 2×2 blocks)
  • Think parallel. Doing long initializations and definition of arrays won’t be factored through pixels since the whole shader is called at every pixels. So most of the time you save code, memory, registers, by merging the initialization and action loops.
  • A reminder that local memory and number of registers is an ultra-critical resource on GPU.
  • Think procedural: to draw 1000 objects on screen, don’t draw and clamp all of them in your shader – i.e. full set checked at each pixel. Try to find the one(s) that cover the pixel, then render only this one.

Texture tricks (GLSL or Shadertoy)

  • MIPmap is simply activated by switching the texture mode. Still,
    • You can bias it (force less or more blur) via a third parameter at texture call.
    • At parameterization discontinuity the automatic estimation on the LOD might be very wrong. => you can force it using texture…LodEXT
    • Note that MIPmap can be used to approximate integrals.
  • texture…gradEXT directly computes the texture derivative
  • Noise color texture: G and A channels are R and B translated by (37.,17.) , if no vflip. This allows to fake interpolated 3D noise.
  • tex15 is an ordered Bayer matrix : first made for easy half-toning (just threshold it with the grey level), it also provides a permutation table in [0,63].
  • Shadertoy buffers can be used to precompute data.
    More generally, in a multi-buffer algorithm if the result of a buffer is not expected to change do the computation only at iFrame==0  (or up to a delay, if asynchroneous data such as images are used).
  • Note that sound texture includes the FFT of the music.
  • Check for the magic keyboard matrix 🙂

More “touchy” tricks (e.g. for code golfing)

  • The final alpha is ignored, so you can work directly on pixelColor or do vec4(myGreyShader).
  • The final color is naturally clamped (your screen pixel won’t be negative or surbright 🙂 ) so for the final image operation you can forget the last clamp.
    ( Of course this can be wrong for intermediate calculations, and buffers do store unclamped floats. )
  • You must initialize variables, comprising out parameters (such as pixelColor).
    But v -= v will work 99.9999% of the times. The only theoretical issue is when the reused register occurred to value NaN by chance (which I’ve never seen occurring up to now).

Advanced super-tricks

You want to use your own texture ? Open the javascript console in your browser and type (or copy-paste) :                                                                                ( thanks Limeth )
gShaderToy.SetTexture(0, {mSrc:'URLofMyImage', mType:'texture', mID:0, mSampler:{ filter: 'nearest', wrap: 'clamp', vflip:'true', srgb:'false', internal:'byte' }});
But it won’t save and others people won’t see it if they don’t do the same insert.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s