Shader Programming, Volume 2

A Diffuse Surface Shader

Sebastian Monroy
3 min readMay 29, 2016

Now that we have some sense of the vocabulary, let’s explore making the most basic of shaders: a diffuse shader. We’ll learn a bit more about the nuances of shader programming while we’re at it, too.

Chapter 2.1

Surface Shaders and Texture Mapping, Diffuse Shading

Starting again with a Standard Shader, we’re going to create a Diffuse shader by stripping out all the stuff we don’t need. It ends up looking like this:

The front right sphere is using our new Diffuse shader.

“As this shader has been refitted from a Standard Shader, it will use physically-based rendering to simulate how light behaves on your models. If you are trying to achieve a non-photorealistic look, you can change the first #pragma directive so that it uses Lambert rather than Standard. If you do so, you should also replace SurfaceOutputStandard with SurfaceOutput.”

Let’s take a look at some of the Shader structs we’ve seen.

The SurfaceOutput struct has the following properties:

  • fixed3 Albedo: the diffuse color of the material
  • fixed3 Normal: the tangent space normal, if written
  • fixed3 Emission: the color of the light emitted by the material
  • fixed Alpha: the transparency of the material
  • fixed Gloss: the specular intensity

The SurfaceOutputStandard struct has similar properties, with some differences:

  • fixed3 Albedo: the base color of the material (whether it’s diffuse or specular)
  • fixed3 Normal
  • half3 Emission: note that this has been declared as half3 instead of fixed3.
  • fixed3 Alpha
  • half Occlusion: default 1
  • half Smoothness: 0 = rough, 1 = smooth
  • half Metallic: 0 = non-metallic, 1 = metallic

The SurfaceOutputStandardSpecular struct doesn’t have the Metallic property, but instead has the Specular property:

  • fixed3 Albedo
  • fixed3 Normal
  • half3 Emission
  • fixed Alpha
  • half Occlusion
  • half Smoothness
  • fixed3 Specular: the specular color. This is very different from the Specular property in SurfaceOutput as it allows specifying a color rather than a single value.

Chapter 2.2

Surface Shaders and Texture Mapping, Using packed arrays

Here’s a cool thing: you can treat Cg’s packed arrays (such as float3 and fixed4) a little differently than you might be able to treat structs in C#.

For example, Cg is totally chill with you doing this thing called swizzling:

o.Albedo = _Color.rgb

instead of individually assigning the elements of the o.Albedo as you would in C# like

o.Albedo.r = _Color.r
o.Albedo.g = _Color.g
o.Albedo.b = _Color.b

which is a total buzzkill if you ask me. You can even do nutty things like reordering the elements of _Color when you pass it into Albedo.

o.Albedo = _Color.bgr

Note that this reads sort of like _Color.booger. Write that in your copybooks now.

Pass in as many or as few elements as you want. Go wild. (Within reason.)

o.Albedo.rg = _Color.rg;

The last trick the book reveals to us is that when you assign a single value to a packed array, it’s copied to all of its fields:

o.Albedo = 0;  // Black = (0, 0, 0)
o.Albedo = 1; // White = (1, 1, 1)

This is referred to as smearing. How pleasant.

Next we’ll be adding a texture to our shader which will make us feel pretty good about ourselves, I bet.

--

--