Created: 2014-05-18 21:44
Updated: 2018-05-23 22:13

Testing shaders with three.js. See this live at

Run it

$ google-chrome index.html

Make changes

$ npm install
$ sudo npm install -g grunt-cli
# if you change shaders, update index.html with:
$ grunt
# or grunt watch to do this automatically.



  • Reproduce the PS3 shimmering flakes
  • Flake snowfall with shader animation (rotation, gravity, maybe fluid lateral movement) and specular lighting. Or more like Minecraft snow
  • TV screen, phosphor elements curved CRT style
  • Add colormap


You can't have a varying attribute. If you want to pass an attribute or uniform through to fragment, you'll need to declare a separate varying.

THREE does a lot of hidden 'prefixed' shader work on your behalf. You can avoid this using RawShaderMaterial.

Passing very large numbers into your shader is a bad idea. You can lose precision. Example: If you pass as a uniform float time and perform sin(time) in your shader, you're going to have a bad time. LITERALLY.

Pixel shaders

Shadertoy is for pixel shaders. Tutorials like are for pixel shaders.

U and V are axes used for the X-Y of your texture, because X-Y-Z are already taken.

UV coords are 0,0 (top left) to 1,1 (bottom right). So for a quad 600px in width, the first pixel would be defined as spanning from U coord 0 to U coord (1 / 600).

Pixel shaders A pixel shader works exactly like CRT scanlines. Sweeps from topleft across the top row, incrementing by one pixel U value each time. On the top row V is zero. Once the top row is done V gets incremented to the vertical pixel amount and we go left-right again. The shader program runs on every pixel, for every frame. That's a lot of executions.

A pixel shader is a fragment shader. There are only four vertices and they're constant (the screen corners).

You are given a pixel and asked what to do with it. When given an input image, you can choose to return something based on pixels elsewhere. So a blurring shader could average out the nearby values. Or you could just sample the pixel to the left, resulting in a horizontal shift of the image.

If you divide the UV you're given, you end up sampling it multiple times and scaling up the input texture. e.g. getPixelFromInputTexture(U * 0.25, V) will return pixel X=1 for U values 0, 1, 2, 3. If you multiply it, you end up scaling it down.

Post-processing shaders. These are pixel shaders that run on the rendered image itself! Scanning every pixel and manipulating it.

Why the unfriendly name vUv? It's a varying, so people prefix with v. And unfortunately it's the UV coordinate, which doesn't have a friendlier expression. Hence the cryptic vUv.

Getting your shaders into JS

There is no elegant way to do this, given 1. JS has limited support for multiline strings and 2. You're in a browser and can't do inline includes easily. After much experimentation this is the cleanest:

  1. Define your shaders in their own files
  2. Put a placeholder token in HTML, viz. index-template.html
  3. Use grunt-replace to push the files into the template. Automate this with grunt-contrib-watch.

Alternatives that weren't good:

  • browserify and brfs to inject the text. Functional, but browserify will hide all your globals! Ha ha.
  • glslify. Nope, this is specifically for non-three projects.


  • Shift out the R, G, B elements to create a Teleglitch-style 'broken display' effect.
  • Scanlines.
  • "Multiply is much faster than divide, so do x * 0.5 rather than x / 2." Not sure I believe this.


THREE will define a color shader variable, but it's undocumented.

Sometimes colors are defined in your material. BasicMaterial has a single color property. Sometimes colors are defined in your object. Geometry has an array colors. It appears the object can store color data which should be honoured. See

In my testing a Mesh with a ShaderMaterial does not pass Geometry.colors to the vertex shader - you just get #ffffff in the color attribute every time.

API doc for Geometry.colors:

Array of vertex colors, matching number and order of vertices.
Used in ParticleSystem and Line.
Meshes use per-face-use-of-vertex colors embedded directly in faces.
To signal an update in this array, Geometry.colorsNeedUpdate needs to be set to true.

A Face3 has a vertexColors array. The example uses this array to set colors face by face, as mentioned in the doc above. The example does not use any of the 'needsUpdate' flags associated with color.

Coloring a Line

I confirmed this works:

lineGeometry.colors.push(new THREE.Color( 0x00aa00 ));
lineGeometry.colors.push(new THREE.Color( 0xffffff ));
lineMaterial.vertexColors = THREE.VertexColors;

So if we push eight colors into myCube.geometry.colors and use a ShaderMaterial, why aren't they honoured in the vert shader?


  • When using a ShaderMaterial, how does the attribute color get its value?
  • What's the point of the ShaderMaterial.vertexColors flag?
  • Should Geometry.colors ever be used with a Mesh, or just ParticleSystem and Line?

Misc TO DO

shader - need a texture that shows no rotation

look into module loading

render a texture

what's the relationship between THREE shader chunks and your shader? How does it get merged?

figure out that three.js ShaderMaterial color behaviour

difference between uv and uv2?


  • rotate individually
  • light individually
  • texture individually


efficient noise

write shader guide

  • basics
  • pixel shaders
  • how to set up a basic project


Cookies help us deliver our services. By using our services, you agree to our use of cookies Learn more