Wednesday 15 March 2017

Procedural Generation Tutorial Brick Noise Texture - Part 6

Procedural Generation Tutorial Brick Noise Texture - Part 6


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_27.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 6 and the completed project file of Part 6.

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
  • Learn to create a Perlin Noise hash table

Step 1: The theory


In todays tutorial we will cover how to create a mask variable which holds the length of our hash table so we don’t have to keep changing our code when we add to it. We will also create Perlin noise and find out how to avoid hashing our values a second time when returning the hash indexer which happened a lot when in use.

What we will do first is create a constant which will hold the length of our hash table, and replace all references to the literal value used in our code to save us a headache. Then we will replace the values in our hash table with the values Ken Perlin used when he created Perlin noise.

After this we will learn how to avoid the need to hash a second time using quite a simple trick.

Step 2: Adding a Mask Value

At the moment when we use the bitwise operator on our hash values we are masking them so they fit in with the current hash table length. This is set to a specific value of 15 so when our values are hashed a second time round, they stay with in the values of our hash table and do not get unruly.

What if we decide we need to increase the number of values in our hash table because we need to increase the texture size and get rid of potential pattern tiling? In this case we will define and use a constant int. We will call it ‘hashValueMask’ and set it to private because we don’t need to access it anywhere else. Then replace the number we hash by referencing the constant name (which happened to be 15 in our case).


Code:


using UnityEngine;


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

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

   }

   public static float RandomValue3D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      int intY = Mathf.FloorToInt(point.y);
      int intZ = Mathf.FloorToInt(point.z);
      intX &= hashValueMask;
      intY &= hashValueMask;
      intZ &= hashValueMask;
      return hashValue[(
                      hashValue[intX] + intY)
                      & hashValueMask
                      intZ) hashValueMask
                      * (1f / hashValueMask);

   }
}

Step 3: Creating Perlin Noise


At the moment, if we want our noise texture to be larger we only have 15 distinct noise values. This is ok, but at some point it will be obvious that we only have 15 values and the pattern will repeat and have a tilling effect. It’s not as visible when combined with another texture but still visible, if it was on it’s own we would notice it more. Our current hash table will still produce a repeating pattern on a large scale, but again because it’s on a large scale, we have a large sample of it.

We need to avoid this and we can. The best was to do this is by adding more values. We could simply copy the values, but because we have so few of them, it would tile and this would be pointless. We could replace these values entirely with 256 new values. This way the number should be enough on any scale (especially a small one). Also we need to change the ‘hashValueMask’ to 255.

Code:


using UnityEngine;



public static class NoiseLibrary()
{
   private static int hashValue =
   {
     151, 160, 137, 91, 90, 15, 131, 13, 201,
     95, 96, 53, 194, 233, 7, 255, 140, 36,
     103, 30, 69, 142, 8, 99, 37, 240, 21, 10
     , 23, 190, 6, 148, 247, 120, 234, 75, 0,
     26, 197, 62, 94, 252, 219, 203, 117, 35,
     11, 32, 57, 177, 33, 88, 237, 149, 56, 
     87, 174, 20, 125, 171, 168, 68, 175, 74,
     165, 71, 139, 48, 27, 166, 77, 146, 158,
     231, 83, 111, 229, 122, 60, 211, 133, 
     , 230, 220, 105, 92, 41, 55, 46, 245, 40
     , 244, 102, 143, 54, 65, 25, 63, 161, 1,
     216, 80, 73, 209, 76, 132, 187, 208, 89,
     18, 169, 200, 196, 135, 130, 116, 188, 
     159, 86, 164, 100, 109, 198, 173, 186, 
     3, 64, 52, 217, 226, 250, 124, 123, 5, 
     202, 38, 147, 118, 126, 255, 82, 85, 212
     , 207, 206, 59, 227, 47, 16, 58, 17, 189
     , 28, 42, 223, 183, 170, 213, 119, 248,
     152, 2, 44, 154, 163, 70, 221, 153, 101,
     155, 167, 43, 172, 9, 129, 22, 39, 253, 
     11, 98, 108, 11, 79, 113, 224, 232, 178,
     185, 112, 104, 218, 246, 97, 228, 251,
     34, 242, 193, 238, 210, 144, 12, 191, 
     179, 162, 2241, 81, 51, 145, 235, 249, 
     14, 239, 107, 49, 192, 214, 31, 181, 
     199, 106, 157, 184, 84, 204, 176, 115, 
     121, 50, 45, 127, 4, 150, 254, 138, 236,
     205, 93, 222, 114, 67, 29, 24, 72, 243, 
     141, 128, 195, 78, 66, 215, 61, 156, 108
   };
   
   private const int hashValueMask = 255;
   ...
}






If your render looks a little bit difference to mine, in the function in the ‘Noise’ script where we create the texture. With the ‘SetPixel’ method, change ‘Color.white’ to ‘Color.grey’ or ‘Color.gray’.

With this hash table even though it will repeat itself if we get a large enough sample size, it still won’t be easily visible (only if you know where to look). In a few cases we can’t see the pixels because they are so tiny. If we wanted to we could use a few tricks to increase the length between each line, or add even more values to the mix however this is enough in most situations.

Step 4: Removing the need to mask twice

At the moment we are hashing our values twice. Once after we cast it, and once when we use as an iterator for returning the mask value from the hash table. You might be thinking ‘why don’t we just do if after adding these values to the hash when returning the value. This is a good point, as this most cases would actually be enough. In the majority of cases, including out in the field, this won’t happen at all. In the event this would happen though the maximum value that is returned would be 510 (255 + 255). This clearly exceeds our hash table.

There are a few ways we can fix this, one by copying the hash table’s contents and pasting it back in, effectively repeating the sequence and doubling the length. In this case the the value of the indexer after the hash mask wraps around with out the need for any complex mathematic operations when returning the value. In other words, index 0 to 255 is exactly the same as 256 to 511.

The next thing to do is remove the bitwise operator and ‘mashValueMask’ variable when hashing the second time round, when indexing the ‘hashValue’ table.

Code:


using UnityEngine;


public static class NoiseLibrary()
{
   public static float RandomValue1D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      intX &= hashValueMask;
      return hashValue[intX] * (1f / 
                            hashValueMask);

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

   }

   public static float RandomValue3D (Vector3 
point, float patternAlternationSpeed)
   {
      point *= patternAlternationSpeed;
      int intX = Mathf.FloorToInt(point.x);
      int intY = Mathf.FloorToInt(point.y);
      int intZ = Mathf.FloorToInt(point.z);
      intX &= hashValueMask;
      intY &= hashValueMask;
      intZ &= hashValueMask;
      return hashValue[(hashValue[intX] + 
                      intY)intZ)
                      * (1f / hashValueMask);

   }
}




Now if we let our code compile and test we we can see the result. It’s pretty good for what we have. With how our code is, you could modify it to suit your needs, such as the colour of the noise pixels or anything really.

Great we know how to make Perlin noise we don’t need to hash a value a second time in the hash index by repeating the hash table values.

We have learnt how to:
  • Create Perlin Noise
  • Repeat a set of hash table values as to not hash the value a second time in the hash index

This is the final segment of the noise texture tutorial. I hope you enjoyed this tutorial and much as I enjoyed making it. If you like it and want more follow my blog, share it on social media and leave a comment below saying what you liked. If you didn’t like it or think it’s needs improving leave a comment below saying what and why.


Keep an eye on my blog as I have more coming up soon, I might soon release an extra bit for this tutorial, and have a follow up for this as well.

No comments:

Post a Comment