Wednesday 1 March 2017

Procedural Generation Tutorial Brick Noise Texture - Part 4

Procedural Generation Tutorial Brick Noise Texture - Part 4


Before you start you should know these things:
  • Create Texture variables
  • Manipulate textures using SetPixels

You should have gone through and completed all the ‘Checker Board Texture’ and 'Brick Pattern Texture' tutorials before going any further. If you find yourself not understanding some of the terminology or code of the tutorial I would also recommend going through the previous tutorial to get up to speed. I will leave a link to it below to go through at your leisure.

http://joseph-easter.blogspot.com/2017/01/procedural-generation-tutorial-brick_60.html

If you follow this tutorial and find I am moving too fast or if you don’t know the things in the list above, I would recommend getting up to speed and then come back to this tutorial when you are ready.

With this tutorial if you want to convert this into JavaScript by all means do so but it may be easier for you to follow this in C# and stick with the language of the tutorial to make it easier.

PROJECT RESOURCES: At the bottom of the post there is a download link to a zip file. This files includes all files needed to follow Part 4 and the completed project file of Part 4.

In this tutorial series, we will be adding to the brick pattern texture using code by adding noise to the texture image.


In this tutorial series, we will be adding to the brick pattern texture using code by adding noise to the texture image.

We will:
  • Explain the theory
  • How to create 2D noise using the quads 'x' and 'y' position
  • How to off set a hash value
  • To add one int value to another when returning a result

Step 1: The theory



In this part we will cover how to make a 2D value noise pattern using the 1D approach and adding complexity to it. Thanks to this, this part will be relatively straight forward and quick.

What we will do is, copy the ‘RandomValue’ noise function, add another axis value to the mix (‘y’) and do the same thing we did to the ‘x’ axis. Then we will add the first axis hash value to the second axis hash value and return that. This will produce a less predictable hash algorithm where the pattern is harder to see.

Step 2: The basics

In this is quite very easy. Because we will be adding more complexity to our ‘RandonValue’ function the basics are already done. The first thing we need to do is amend the name of ‘RandomValue’ by adding ‘1D’ to the end.


Code:



using UnityEngine;

public static class NoiseLibrary()
{
   private static int [] hashValue = 
   {
     8, 1, 3, 4, 14, 7, 5, 12, 11, 2, 10, 
     13, 0, 9, 6
   };
   
   public static float RandomValue1D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      intX &= 15f;
      return hashValue[intX] / 15f;
   }
}

Next we copy the function ‘RandomValue1D’ and paste it below, then change its name replacing the ‘1D’ on the end with ‘2D’.


Code:



using UnityEngine;

public static class NoiseLibrary()
{
   private static int [] hashValue = 
   {
     8, 1, 3, 4, 14, 7, 5, 12, 11, 2, 10, 
     13, 0, 9, 6
   };
   
   public static float RandomValue1D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      intX &= 15f;
      return hashValue[intX] / 15f;
   }

   public static float RandomValue2D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      intX &= 15f;
      return hashValue[intX] / 15f;
   }
}


Now we have done this in the ‘Noise’ script, in the for loop of the ‘CreateNoisePattern’ change the reference to ‘NoiseLibrary.RandomValue’ to ‘NoiseLibrary.RandomValue2D’ so we can see the changes to our code.

Code:


public void CreateNoisePattern()
{
   ...
   for (int h = 0; h < resolutionH; h++)
   {
      CalculatePoint(leftSide, rightSide
                     h, normalizer);
      noiseTexture.SetPixel(w, h, Color.white * 
         NoiseLibrary.RandomValue2D(point,
         patternAlternationSpeed);
   }
   ...
}

Step 3: Introducing the 'Y' axis

In order to make this more interesting we need to add another variable into the mix. Like last time we will use the ‘y’ poisition variable. (You can use another if you like). We will do to ‘y’ what we did to the ‘x’ value. We will convert it to an integer. Create a new int variable called ‘intY’ and use ‘Mathf.FloorToInt’ on ‘point.y’. After this use the bitwise operator on ‘intY’ with the maximum value in the hash table.

Code:



using UnityEngine;

public static class NoiseLibrary()
{
   ...
   public static float RandomValue2D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      int intY = Mathf.FloorToInt(point.y);
      intX &= 15f;
      intY &= 15f;
      return hashValue[intX] / 15f;
   }
}

Step 4: Returning the value and seeing the result

You might be thinking ‘how will we return the hash value or both ‘intX’ and intY’ at the same time as one value. Well we won’t do this directly, but we will add the first int hash value to ‘intY’ then we will use this to index the hash table, this will offset the hash value of ‘intY’ by ‘intX’. This effectively does it a second time round. Then we use the bitwise operator on the hash values by the length of the hash table (so we don’t exceed it by accident). The end result will produce a pattern that when it repeats is slightly offset making the repetition a little less obvious. We need to make sure the hash value does not exceed the limits of the hash table.

Code:



using UnityEngine;

public static class NoiseLibrary()
{
   ...
   public static float RandomValue2D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      int intY = Mathf.FloorToInt(point.y);
      intX &= 15f;
      intY &= 15f;
      return hashValue[(hashValue[intX] + intY)
                      & 15f];
   }
}

After this we will multiply this value by a normalizer to get the value we need. The normalizer is ‘1f’ divided by the length of the ‘hashValue’ hash table so it doesn’t exceed the length of the table and make the value in the range of something useable in this context. Lastly we put the normalizer in brackets ‘(‘ and ‘)’ to say ‘we need the sum of this’.

Code:



using UnityEngine;

public static class NoiseLibrary()
{
   ...
   public static float RandomValue2D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      int intY = Mathf.FloorToInt(point.y);
      intX &= 15f;
      intY &= 15f;
      return hashValue[(hashValue[intX] + intY)
                      & 15f] * (1f / 15f);
   }
}



Resolution 256, pattern alternation speed 32.

When we look at this it appears very spontaneous. At a glance there are no repartitions. If you know where to look there are some repeating parts that are offset a little, but they not immediately noticeable unless you look at the vertical patterns. If you wanted to you could add more values in the hash table to the mix or shuffle them around but this is unnecessary work, and you would see loads of them if you knew where to find them. A better idea would be to spend your time using a completely different one. In the majority of cases though this is good enough to be convincing and one will only notice this if under very close inspection.

Great we know how to make 2D noise by using the ‘y’ value and adding the ‘x’ value to it. Essentially adding more complexity to what we already have.

We have learnt how to:
  • Create 2D noise
  • Add one hash value to another
  • Use a normaliser when returning a hash value
  • Use one has value to offset another in a hash array indexer
  • Multiply a hash value by normaliser to get an apparently random value from a hash table
  • Adding another dimension to ‘Random.Values’ merely requires adding another position value to what we already have

In Part 5 we will learn how to use the skills learnt here to create 3D noise using the ‘z’ value of the quad’s position and add the ‘x’ and ‘y’ values to it.



No comments:

Post a Comment