Page 10-3: GLSL and THREE

Page 10-3: GLSL and THREE

Box 1: GLSL

Part of writing shaders is that you have to work in a shading language, which is yet another programming language to learn. My experience is that the thing that is challenging for most students is the concept of shaders, the details of the language follow. In fact, in old assignments we used to make students translate shaders from one language to another to emphasize that the languages aren't that different.

GLSL is convenient: it is one shading language that works almost everywhere, and the compiler is built into the graphics drivers. Back in the old days, you had to worry about getting the compiler and hoping it worked with your graphics card.

While it is a bit of a pain to have "yet another" language to learn, the fact that GLSL is highly specialized for shaders means it has a lot of nice features for doing shader programming. It has excellent support for vectors and matrices (since graphics programming always has vectors and matrices). It has all kinds of convenient math functions built in.

Unfortunately, most documentation for GLSL spends its time explaining the concepts of shaders, and how to communicate with the host program. So, I don't have a great document to recommend (see the list on the index page). I think the best way to learn it is to try to read and write shaders, and then look up features in a reference card (for example The WebGL Reference Card, but other ideas are on the index page). Expect to make lots of mistakes (which is painful, since you don't get to see the errors until the compiler runs).

Here are a few things that will help you get started:

GLSL is C-like in syntax. It uses the same basic syntax, but uses different keywords and operators, has different built-in types, and a different feature set.

GLSL is strongly typed. Everything has a type, and is required to be that type. For example, integers are floats are different. 1 is an integer. 1.0 is a float. 1+1.0 is not 2.0 or 2, it is a type error.

GLSL has many vector and matrix types. In graphics, we use 2,3 and 4 vectors and 2x2, 3x3, and 4x4 matrices. GLSL has all of these built in. They are different. You cannot assign a vec2 to a vec3.

GLSL has very flexible constructors for matrices and vectors. You can construct a vec4 from a vec3 and a float, or two vec2s, or ... You do have to explicitly construct things. vec3 p = vec3(vec2(1,2),3).

GLSL has very flexible accessors for vectors. If you have a vec3 variable p, you can access the first component of the vector as p[0] or p.x or p.r (as in rgb). You can also refer to other subparts, like p.xy (which is a 2-vector), or even p.zy (which selects and re-orders the subparts). The ability to select and re-order vector parts is called swizzling.

Box 2: Tools for GLSL

Having good tools for GLSL programming makes writing shaders easier. You can write the shader in some tool, try it out on their sample shapes, and then move it to your real program. One catch is that the communication with the "sample" program built into the tool is never the same as communicating with your own program.

Since shaders tend to be small programs, web-based tools are very practical. Several tools let you put in small programs and show you what the results look like on sample geometry. One downside of using these tools is that how the shaders are connected to the tool (so you get the sample geometry and other support) is never exactly the same as when you put it into a real program.

Two tools that students have had good luck with in the past are:

One nice thing about these is that they show you your errors right away. You don't have to go digging through the console logs to identify the errors in your shaders.

I strongly recommend trying to use one of these when you write fancy shaders. It is tricky to get the variables you need from the host program (especially the attributes). But you can get things mostly working, and then move the programs into your THREE program. For class, everything you turn in must ultimately go into a THREE program.

Box 3: Shaders in THREE

For using shaders in THREE: there are tutorials out there. Not as many as for other topics because the built-in shaders for THREE are so good, that you usually don't need to write your own.

But, we want to write shaders because (1) you need to learn about them and (2) sometimes, you want to make your own shader (we'll see some examples in a bit).

Generally, THREE makes adding shaders easy. With the ShaderMaterial (see the documentation), you can give it shader code, and it adds GLSL declarations to the beginning so your program can access the information it needs (see the docs). It also takes care of converting between JavaScript and GLSL data types, putting your vertex information into buffers to send as attributes, and a host of other details you don't want to worry about.

One tricky thing: THREE has very fancy lighting. We can make many kinds of lights, and have many of them. Somehow we need to pass all of this information to our shaders (which actually compute the lighting). This is complicated. We have two choices: (1) we can read the documentation to see all the lighting information that gets passed, and implement our shaders very carefully to use it or (2) ignore THREE's lights, and do something simpler for ourselves. For class we'll choose option #2.

Box 4: Some Advice

Some GLSL/WebGL/THREE Gotchas:

Summary: Writing Shaders with THREE and GLSL

Hopefully, you have the basic ideas. Now let's try to write some interesting shaders on the next page.