Custom Unity Shader for a designer game

So I decided to work with a designer in creating a shader that achieves a visual style they want. In this case, the designer wanted to achieve a sort of low poly shader.
I previously did low poly somewhat recently for a game jam where I took the custom terrain generator that I followed from a tutorial and re-purposed it to output a low poly version, rather than a smoothed one.

From that...

To that...

But enough about the terrain, this blog is about the shader.

So the shader had to accomplish a similar visual style, without taking an existing mesh, changing the vertex rendering points for each triangle, and then taking those points and exporting it into a new mesh...

The Vertex shader simply computed the vertex lighting, since we have to calculate the normals in a slightly different matter.

float3 vertexLighting = float3(0, 0, 0);

for(int index = 0; index < 4; index++) {  
    float3 normalDir = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz);
    float3 lightPosition = float3(unity_4LightPosX0[index], unity_4LightPosY0[index], unity_4LightPosZ0[index]);
    float3 vertexToLightSource = lightPosition - mul(unity_ObjectToWorld, v.vertex);
    float3 lightDir = normalize(vertexToLightSource);
    float distanceSquared = dot(vertexToLightSource, vertexToLightSource);
    float attenuation = 1.0 / (1.0 + unity_4LightAtten0[index] * distanceSquared);

    vertexLighting += attenuation * unity_LightColor[index].rgb * _Color.rgb * saturate(dot(normalDir, lightDir));

There's a bit code here I had to borrow to figure it out, the whole unity_CallBuiltInFunction(_WithArguments) really confused me since there wasn't much documentation on it as well. Having little to no experience with this type of programming also didn't help much at all...

This is what I got from it,

From here, it was just a matter of supporting colours now. So I modified the Pixel shader and just turned everything blood red,

I just pulled the tree from Standard Assets in Unity and it looks a bit wonky with the shader, since I had to replace the one it came with. Here's another view of shader but making it a blackish grey.

And finally, the last iteration change was adding gradient support between three colours. And so the Pixel shader was modified and produces a lovely result as such,

The code for getting the gradient was simply just lerping between the three (or more) colours and having a _Middle value as well.

fixed4 colour = lerp(_ColorThird, _ColorSecond, IN.uv.y / _Middle) * step(IN.uv.y, _Middle);  
colour += lerp(_ColorSecond, _ColorFirst, (IN.uv.y - _Middle) / (1 - _Middle)) * step(_Middle, IN.uv.y);  
colour.a = 1;  

The shader also supports attaching an albedo to it. So the colours and low poly(ness) will use the albedo as a sort of guide to where to place things, otherwise you simply get the straight triangles as shown above of flat colour.

Another screenshot of the low poly terrain generator...

Tom Lynn

Read more posts by this author.