Visual Scripting – UI Implementation

This week I added Menu to the tool so that the user can configure various Generation settings with sliders and such, the settings are:

  • Seed
  • Maximum Slope
  • Snowy biome height
  • Water Height
  • Tree Density

It is a little slow to generate as there is lots of room for optimisation however for demonstration purposes it’s fine.

Here is some footage of it working in the editor.

Most of my time getting it working was spent trying to communicate between the HUD blueprint and the Level blueprint I settled on having a reference to the HUD on the Camera object and searching for the camera in the level blueprint. From there I used an event dispatcher to allow the Menu Widget on the HUD to call the generate event. Figuring out how to set up the event dispatcher took a while as most of the forum posts explaining them would contain two screenshots of the node setup but not which blueprint should contain what.

Visual Scripting – Notable Problems

This post covers a few of the most notable problems I have had with UE4 regarding random crashes and compiling issues. I am less so concerned about the crashes themselves but more of the lack of supporting documentation surrounding fixes for what to me seems like a fairly common use of the engine.

There was a point where I had spent the day trying to debug a function that did not appear to be getting called. I went through my usual process of placing Breakpoints only to find that none of my variables had been declared, upon further investigation it became clear that the Compiler had taken issue with some pointer arrays, decided the function changed nothing and optimised it all away. There were no errors showing that there was an issue and it took an entire day to figure out the source of the problem and to fix it.

I wanted to move all of my generation code from the level blueprint and into its own class, either a blueprint or a C++ class but I just ended up spending hours trying to fix obscure linker and compile errors informing me that functions I had previously using did not exist. Also, whenever I compiled the code using the button in the editor it would crash without warning. The Documentation says nothing about fixing what I would assume are common errors nor how to properly set up the build file or even which header files should be included when working with certain classes. Furthermore it’s incredibly difficult to debug your code as it is not easy to tell if the error is coming from C++ or from Unreal Engine. It is also often the case that errors will be reported after one compile that will be gone after the next compile without a trace which is possibly more infuriating.

Finally I’d like to mention for anyone else who wishes to work with landscapes in the future. The editor will crash if you are creating a blueprint and try to set a child actor’s class to a Landscape;  the editor will freeze for a second and then crash and present the error reporting window, the same as the compile bug mentioned earlier. If you have a lightning fast computer this might not be that much of a problem but if like me it takes you the best part of 5 minutes to launch UE4 this can really eat up your time and it certainly drained my motivation to continue.

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

AverageMan_ToonRampShading

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

AverageMan_Ramps

AverageMan_MeshSetup

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.

AverageMan_BothRamped

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.
AverageMan_NormalIntensity

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.
Toon_Sponza

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.

TreesSlopesWater

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.

TreesSlopesWater_before

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.

TreesSlopesWater_Improvement

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.

TreesSlopesWater_after

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.

SpawningTrees_HeightMap

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];
            up.Normalize();
            FVector right = thisPos - positions[y * size + (x + 1)];
            right.Normalize();

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

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

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

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

            // 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.

Normals_AboveNormals_Side

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.