Individual Learning – Toon Shader

This week I continued some work I started over Christmas that consisted mainly of reading through Unity’s Shader documentation and downloading a few assets from Turbosquid to play with as I start writing shaders.

I have decided on using Unity’s “Surface Shader” which combines Vertex and Pixel shaders into one, and does some clever compilation behind the scenes to create the individual vertex and pixel programs. They also allow you to use either built in lighting models or to write your own lighting functions, which I have used for the following shaders.

After a little bit of messing around set out with the goal of creating a toon/cel-shader. Toon shaders come in many forms but commonly they feature more flat shading and hard borders between light areas and shadow. I wrote two shaders: a colour ramp shader which samples a ramp texture, usually a gradient, and no diffuse texture to determine what a fragment colour should be when lit; the second shader I wrote uses hard coded light levels to create the effect while still sampling a diffuse texture.

Colour Ramp


Here you can see a a mesh on the left using a more standard Diffuse/Specular lighting model (lambert), and on the right, my modified mesh using a series of different ramps to colour the individual mesh parts. The ramp texture works by using the light’s intensity at each pixel to sample a texture, the brighter the intensity, the further left is sampled and the darker tones are found on the right.

The colour Ramp approach requires separating a mesh into multiple parts so that different materials can be applied for each ramp. You can see the individual ramps I created below and how I modified the mesh in 3DS Max



One the one hand I like how minimal and simplistic the mesh looks using just the colour ramp however as the mesh had one, I added a normal map to the shader which massively improved the look of the material. I also added it to the standard material on the left for comparison along with some colourful point lights to test how the lights tinted the surface.

This slideshow requires JavaScript.

Textured Toon

Next, I replaced the Lambert light function on the standard shader with my own custom function, which hard codes 3 light levels (full bright above 50%, half bright above 25% and a quarter below that) that are multiplied by the diffuse texture to create a similar but textured effect on the left.


While i was testing the the shader on other meshes i realized that the normal maps could be too strong and cause the surface to look ugly and noisy. To fix this I added a slider to the shader that lets me set the strength of the normal map the same way as Unity’s built in standard shader.

As you can see this gives me artistic control over how the normal map is affecting the surface.

Bonus Fun

For a bit of fun and as a bit of testing i dragged over the Sponza mesh from my Rendering Engine, threw some garish point lights into the scene and slapped my Textured Toon shader onto the walls, which, to me, looks pretty cool.

My Thoughts

I think that both shaders look interesting and give a unique feel each however they both have some technical annoyances that may get in the way. Firstly, the textured shader, while it does not require multiple Ramp textures and can use a mesh without being edited does currently have everything related to the lighting hard coded so if I want to tweak any of the settings I have to change magic numbers in the shader code. I could probably fix this by creating a grey-scale Light ramp similar to the ramped shader.

Secondly the Colour Ramped shader requires a number of individual textures to be created for a mesh, dependent on the number of colours that it requires which is a pain for this simple mesh but would be impractical for a more detailed object. However the artist can do any number of things with a ramp, including shifting the hue of the colour as it moves towards the darker shades or even use completely different colours which could lead to a number of interesting effects.

In the future I would like to delve into Unity’s GUI Editor scripts which allow you to set how the properties are laid out in a material and I imagine even add a gradient field to it which would remove the need to create the ramp textures externally.

Visual Scripting – Spawning Trees

This week I started actually spawning trees on my landscape instead of my debug cubes. I did this like before by using the position array and spawning one at each point, however I used the normals that I generated previously to determine the slope angle  (dot product of the normal and a vector pointing straight up) and only spawning the tree if the angle was less than a certain value

I have also included a water plane which determines the minimum height that the trees can be placed at.


There are now far fewer objects being spawned on the terrain so the performance is quite bearable while using a lower LOD, so i can now spawn the trees using a greater detail mesh meaning that the Forrest I can generate looks far more realistically dense.


Next I used the highest detail mesh to spawn the trees however i used a seeded Random number generator to only spawn a tree at 10% of the points. I also varied the sizes and orientations that the trees spawn at. All together this leads to a far more realistic and pleasing forest being generated.


I also created a Material for the terrain that applies either a grass or a stone texture depending on the current slope of the terrain. I did this both as an experiment but also so that it is easier to see where the trees should be spawning. It also has the added benefit of making it easier to see the shape of the terrain.


Going forward, I would like to use Noise to determine the tree distribution instead of what i am doing currently because random number generation can look unnatural whereas a noise algorithm such as value or Perlin noise will give a far more natural and configurable look.

As an experiment I implemented Terrain generation in Monogame using fractal value noise. This was useful as it allowed me to have an attempt at implementing a noise generator; Unreal Engine does not have a built in noise generator like other engines do so when i come to use noise for the tree distribution i already know how to implement it.


Visual Scripting – Generating Normals

I got rather carried away with actually developing this next feature so this post covers 2 weeks of development . I have since completed more work which i’ll cover in the next post.

Generating Normals

The task for the next feature was to start adding trees to my landscape but only where the slope of the landscape below was suitable, this requires knowing the normals of the mesh so i started here.

My plan was to look at all of the points adjacent to another and use the cross product with 2 adjacent points at a time and then average them. In the first week my attempt was very problem filled, at one point the compiler had decided that the entire function had no purpose and optimised all of it away, making debugging the problem rather difficult. I also had a problem where the normals that were returned to me were just incorrect.

What did not help was that I had decided to use a complicated method to get the normals with the hope that it would run fast. This was a mistake and i should have started with a simpler approach and optimised it later if needed. I do this often and in future i’ll be assuring i don’t do it. KISS: Keep It Simple, Stupid.

My second approach worked immediately, further hammering down the KISS “methodology”. First i initialise my blank array of normals to face along the z axis, this is so that all of the edge cases are handled. Then for each point that is not on an edge i calculate the normal for the positions above and right, then the positions below and left giving me two normals, then i can average these out. I only need to work out the two opposing normals as all four adjacent positions are factored into the calculation.

TArray<FVector> UMyFunctionLibrary::GenerateNormals(const TArray<FVector> positions)
    // Output array
    TArray<FVector> Normals;

    // Set every vector to point up
    for (size_t i = 0; i < positions.Num(); i++)
        Normals.Add(FVector(0.f, 0.0f, 1.0f));

    size_t size = sqrt(positions.Num());

    // For each point that is not on the edge
    for (size_t y = 1; y < size - 1; y++)
        for (size_t x = 1; x < size - 1; x++)

            FVector thisPos = positions[y * size + x];

            // Up and Right
            FVector up = thisPos - positions[(y + 1) * size + x];
            FVector right = thisPos - positions[y * size + (x + 1)];

            FVector normalA = FVector::CrossProduct(up, right);

            // Down and Left
            FVector down = thisPos - positions[(y - 1) * size + x];
            FVector left = thisPos - positions[y * size + (x - 1)];

            FVector normalB = FVector::CrossProduct(down, left);

            // Mean of both normals
            FVector normalAvg = (normalA + normalB) / 2;

            // Set ths normal in the array
            // Negated because Unreal uses an inverted y axis
            Normals[y * size + x] = -normalAvg;

    return Normals;

Here’s some renders using the line renderer to visualise the normals.


Final Group Project Dev Log – 23/02/2018

This week is the final week on this project, and this post marks the end of the rapid prototyping module.

I spent my time this week writing a report comparing Waterfall to Agile using my experiences from the last two rapid prototyping. I would have appreciated having more time to work on it, i know that it takes me a long time to write documents and i would normally take extra time however my week is already packed with the other modules i have a including the 24 hours a week i schedule to development work. It’s difficult to find time to work on these documents without compromising my other modules.

At times it feels very much like the written documents are expected to be completed in extra time; I can understand that this is common in a professional environment however in an educational environment, where there’s multiple projects running in parallel it becomes very stressful trying to keep on top of everything in such a way that you are not compromising any grades.

I spent about 4 hours adding the new artwork to the game as it came in so that it was in the final build. I did not plan a sprint this week so that i could finish the report, however, I did not feel like I could ignore this task and as i needed to submit a final build i did not want it to be missing the beautiful art my artist had created. I also disabled my Live banner advert as I could not successfully get test ads to display. I’m now using the Banner Ad id that google provides which only serves fake adverts.

Group Project Dev Log – 16/02/2018

This week I implemented Firebase Analytics into the project tracking metrics such as Session length, Score and via which route the player fails. I struggled somewhat with integration due to the Documentation and Getting Started guide being somewhat lacking in detail.

The Analytics task was estimated to take most of the week; it was an 8 point task, however, i managed tom complete it in a short amount of time allowing me to move quickly onto Integrating Google AdMob and add the banner ad. Unfortunately i have been unsuccessful setting up my phone as a test device so google is currently serving live ads because of this i will have to disable the live ads.

The essay on Development Management is consuming far more time than originally expecting, causing it to become a burden and risk on the project.

Artwork did not live up to my expectations as it came in, despite my careful planning I should have asked for one complete asset at a time (vertical slice) to review and give feedback to help steer art towards my vision in a more iterative approach. As more assets are completed i will be more careful to review and steer it in the right direction.

Moving forwards i will have to resolve the issue with ads so that i i can safely play-test the game without having to make a separate build with ads disabled. I now also know to allocate more time to writing tasks so that i do not find myself in the same situation again.

Visual Scripting – Sorting things out

Before I am able to place vegetation on the terrain I need to know the slope angle at each point so I can determine whether it is too steep or what kind of plants i want to appear in those circumstances. I could get the tangent/normal data from the FRawMesh from last week however i that would require removing duplicates again which would be both slow and I could become a pain if they don’t match up after the sorting process. I decided to go the easier route and calculate them by sampling the adjacent points.

The first issue is that blueprints only support 1D arrays but i need to address elements with 2D Coordinates, To help with this i wrote a macro that uses the formula i = y * width + x which will do just that.


To test that it worked I set the cube at that index to a red material, sadly I do not have a screenshot of this but there were red cubes.


In the testing, the cubes at (0, 0) and (width, height) were in the correct positions in the array; however, due to the way I was removing the duplicate vertices, they were not all sorted causing some rows to be jumbled with the next. I changed the debug cube to also have a Text Renderer that I show the position in the array on.


My original instinct was to implement my own sorting algorithm in blueprint or C++, in theory i would be able to use the same indexing formula as my comparison for checking, however this would be very time consuming. Instead i found that TArray already has the function TArray::Sort() so I wrote a C++ function that would use it and return the sorted array.

TArray UMyFunctionLibrary::Sort(TArray points)
    // use TArray::Sort using my predicate to sort the array
    return points;

// Function that TArray::Sort can use to compare FVectors
bool UMyFunctionLibrary::SortPredicate(const FVector & a, const FVector & b)
    if (a.Y < b.Y)
        // if a's y is less we know it has to be before b
        return true;
    else if (a.Y == b.Y && a.X < b.X)
        // if they're at equal y, if a's x is less than b's x, true
        return true;
        // else b is before a
        return false;

It’s worth noting that for simplicity’s sake I used multiple if statements in my predicate function and not the more elegant formula. It is possible that using the formula could be faster but it was quicker to write and is more easily read when using this solution.


Here you can see the successfully sorted array, ready for me to start calculating the slope data.

Group Project Dev Log – 09/02/2018

This week has been productive; all tasks have been completed on time and effective sprint planning and daily scrums have kept the project on track. Some tasks had underestimated story points assigned to them, an example would be Issue #26 as it took longer to complete than expected as i had wasted time attacking the problem from the wrong angle.

Feedback from the art doc was good, I am confident that my vision is well defined in the Style Guide and that the asset list is concise. No art has been completed this week due to time constraints on the artist however it is scheduled to be completed over the weekend.

I worked on fixing/completing the Loop Detection code, Previously it was inconsistent and unfair however now it works better and allows for a the grace period to be after the song too, allowing the player to be slightly late and still register the tap as looping.

Next week I will be continuing the daily scrums with my course leader (producer), I will be adding in the new artwork as it rolls in. Top priority is starting the process of attaining the rights to use the music in the game. Finally I will be adding the analytics functionality into the project as well as implementing Ads.

Sprint 3