Wednesday, 26 April 2017

Procedural Generation Tutorial Basic Cell Pattern Texture - Part 5

Procedural Generation Tutorial Basic Cell Pattern Texture - Part 5


The end result of the full tutorial.

At the end of Part 5 we will have produced this (See image 1.0).
Image 1.0


Before you start you should know these things:
  • Create Texture variables
  • Manipulate textures using SetPixels
  • Create a basic texture pattern
  • What noise is and hot to use it with a texture pattern

A Quick Announcement:

Hi every one, a quick announcement. Starting next week on (enter date) I will be taking the next two weeks off, meaning there will be no new posts on (add date and add date). After this I will be back and these posts will resume as normal starting (enter date). I need some time to catch up on a few projects which need attention and I will be writing up a new tutorial on something new. I hope I haven't disappointed any one and I'll see you back in a fortnight with a new tutorial.



You should have gone through these tutorials before going further:

  • Checker Board Texture
  • Brick Pattern Texture
  • Brick Pattern Noise Texture

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.

Part 4:


http://joseph-easter.blogspot.com/2017/04/procedural-generation-tutorial-basic_26.html
Checker Board Pattern Texture http://joseph-easter.blogspot.nl/2016/12/procedural-generation-tutorial-checker.html

Brick Texture Tutorial http://joseph-easter.blogspot.co.uk/2017/01/procedural-generation-tutorial-brick.html

Brick Noise Texture Tutorial http://joseph-easter.blogspot.nl/2017/02/procedural-generation-tutorial-brick_8.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 5 and the completed project file of Part 5.

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 creating a very simple pattern using a cellular texture using code. This tutorial will use and build upon what we have learnt from the previous texture tutorials, by creating two textures, one for the background, and one for the foreground, dividing the foreground into cells and adding an image into those cells then combining those textures. Later we will add variation to it by deciding whether to show a cell based on it noise value in the texture space, then using that noise to position it with in the cell itself using bombing.

We will:
  • Explain the theory
  • Use and enum to quickly switch settings in the inspector
  • Use a switch statement to switch between patterns
  • Interpolate images position in a cell basic on noise
  • Combine multiple pattern types

Step 1: The theory


In this part, we will work on two things. The first thing we will do is create an enum and a switch statement within our ‘for’ loops. This is how we chose how we use our noise with our texture pattern. The first setting will be, what we first worked on, should it show the image that that cell. The second will show all the cells but will vary the images position with in them. The third setting will combine these effects together.

The second thing we will do is, using our noise values when we show a cell of the image from the ‘topLayerTexture’ we will find a way to vary the position of it with its cell. We will use interpolation to help us achieve this effect on the ‘x’ and ‘y’ axis while keeping the image in the confines of the cell.

In the final case of the switch statement we will add code from the both existing cases.

Step 2: Pattern Type Settings in the Inspector

Before we do anything, we will set up our project so the developer and designer can quickly change the pattern type in the inspector at will. We will create a public enumeration variable called ‘PatternType’ in ‘BasicCellPatternCreator’ with three values, ‘showCell’, ‘cellPosition’ and ‘both’.


Code:


public enum PatternType {showCell,
                         cellPosition, both}
public PatternType patternType;


Now in ‘CreatePattern’ we will create a switch statement that will use this enum. We will initially create one case for ‘showCell’ and place our existing ‘SetPixels32’ lines in there. The case will be ‘PatternType.showCell’.


Code:

void CreatePattern()
{
   ...
   for (int j = 0; j < squaresY; j++)
   {
      noiseScr.CalculatePoint(
             noiseScr.leftSide, 
             noiseScr.rightSide,
             j, normalizer);
      float noiseVal = noiseDimention(
                       noiseScr.point,
         noiseScr.patternAlternationSpeed);
      float val = noiseVal * 10f;
      switch(patternType)
      {
      case PatternType.showCell:
         if (val >= noiseTolerance)
         {
            topLayerTexture.SetPixels(
                      i * blockWidth + 
                      middleOfCellWidth,
                      j * blockHeight + 
                      middleOfCellHeight,
                      imageTexture.width,
                      imageTexture.height,
                      imagePixels);
         }
         break;
      }
   ...
   }
}
Image 1.0

Step 3: Interpolating the image's x position in the cell


To position the image within each cell, we will use interpolation or the 'Lerp' function of the ‘Vector3’ class and use the ‘i’ and ‘j’ iterators from last time for the ‘t’ value. This is quite straightforward. We will create two local integers, one for the ‘x’ and ‘y’ axis. With both variables, we will interpolate between to values, using the ‘Mathf.Lerp’ method. For the ‘x’ axis we will interpolate between the left side of the cell which is ‘i’ times ‘blockWidth’, and the right side of the cell which is ‘i’ times ‘blockWidth’ plus ‘middleOfCellWidth’ times two. We do this because ‘SetPixels32’ starts at the bottom left pixel, that’s why we make the centre of the cell the right most side. We use ‘noiseVal’ as our ‘t’ value for the interpolation. This is good, now replace ‘i * blockWidth + middleOfCellWidth’ with ‘x’. We will do this for ‘y’ in a moment, I wanted to keep this explanation to one axis to make things more straightforward. Another note we cast the function as an integer because this is the type we are assigning it to, but we cast the other variables ‘Mathf.Lerp’ because this function works best with ‘float’ point variables.

Code:

void CreatePattern()
{
   ...
   for (int j = 0; j < squaresY; j++)
   {
      ...
      switch(patternType)
      {
      case PatternType.showCell:
         if (val >= noiseTolerance)
         {
            topLayerTexture.SetPixels(
                      i * blockWidth + 
                      middleOfCellWidth,
                      j * blockHeight + 
                      middleOfCellHeight,
                      imageTexture.width,
                      imageTexture.height,
                      imagePixels);
         }
         break;
      case PatternType.cellPosition:
         int x = (int)Mathf.Lerp(
         (float)i * blockWidth,
         (float)i * (float)blockWidth + 
         ((float)middleOfCellWidth * 2f),
         val);
         topLayerTexture.SetPixels(
                   xj * blockHeight + 
                   middleOfCellHeight,
                   imageTexture.width,
                   imageTexture.height,
                   imagePixels);
         break;
      }
   ...
   }
}


Image 1.0

Note: This is handy as the image does not accidentally go outside the cell itself. (In some engines, if an image did this, the offending parts of the image would be clipped off and not rendered). 

Step 4: Interpolating the image's y position in the cell


The principal here is the same as in ‘Step 3’, but on the ‘y’ axis. Create a local variable ‘y’ and use ‘Mathf.Lerp’ again but instead of casting ‘i’ cast ‘j’ as this is the axis we are dealing with (plus it will give a more varied result as these iterators are often on different values). Also change the variables ‘blockWidth’ to ‘blockHeight’ and ‘middleOfCellWidth’ to ‘middleOfCellHeight’. Everything else can stay the same.

Then change ‘j * blockHeight + middleOfCellHeight’ to ‘y’.

Code:

void CreatePattern()
{
   ...
   for (int j = 0; j < squaresY; j++)
   {
      ...
      switch(patternType)
      {
      case PatternType.showCell:
         if (val >= noiseTolerance)
         {
            topLayerTexture.SetPixels(
                      i * blockWidth + 
                      middleOfCellWidth,
                      j * blockHeight + 
                      middleOfCellHeight,
                      imageTexture.width,
                      imageTexture.height,
                      imagePixels);
         }
         break;
      case PatternType.cellPosition:
         int x = (int)Mathf.Lerp(
         (float)i * blockWidth,
         (float)i * (float)blockWidth + 
         ((float)middleOfCellWidth * 2f),
         val);
         int y = (int)Mathf.Lerp(
         (float)j * blockHeight,
         (float)j * (float)blockHeight + 
         ((float)middleOfCellHeight * 2f),
         val);
         topLayerTexture.SetPixels(
                   x, y * blockHeight + 
                   middleOfCellHeight,
                   imageTexture.width,
                   imageTexture.height,
                   imagePixels);
         break;
      }
   ...
   }
}

Image 1.2

Step 5: Combining these two settings

One last thing, we have three options ‘showCell’, ‘cellPosition’, and ‘both’, yet we only have two cases in our switch statement. We will create a third case which will use ‘both’. As the name suggests, it will combine these effects together, making the pattern less predictable.

We will copy the ‘if’ statement from ‘showCell’ and paste it into the ‘both’ case, then we will replace everything in the switch statement curly brackets with the code in the ‘cellPosition’ case.

Code:

void CreatePattern()
{
   ...
   for (int j = 0; j < squaresY; j++)
   {
      ...
      switch(patternType)
      {
      case PatternType.showCell:
         if (val >= noiseTolerance)
         {
            topLayerTexture.SetPixels(
                      i * blockWidth + 
                      middleOfCellWidth,
                      j * blockHeight + 
                      middleOfCellHeight,
                      imageTexture.width,
                      imageTexture.height,
                      imagePixels);
         }
         break;
      case PatternType.cellPosition:
         int x = (int)Mathf.Lerp(
         (float)i * blockWidth,
         (float)i * (float)blockWidth + 
         ((float)middleOfCellWidth * 2f),
         val);
         int y = (int)Mathf.Lerp(
         (float)j * blockHeight,
         (float)j * (float)blockHeight + 
         ((float)middleOfCellHeight * 2f),
         val);
         topLayerTexture.SetPixels(
                   x, y * blockHeight + 
                   middleOfCellHeight,
                   imageTexture.width,
                   imageTexture.height,
                   imagePixels);
         break;
      case PatternType.both:
         if (val >= noiseTolerance)
         {
            int x = (int)Mathf.Lerp(
            (float)i * blockWidth,
            (float)i * (float)blockWidth + 
            ((float)middleOfCellWidth * 2f),
            val);
            int y = (int)Mathf.Lerp(
            (float)j * blockHeight,
            (float)j * (float)blockHeight + 
            ((float)middleOfCellHeight * 2f),
            val);
            topLayerTexture.SetPixels(x, y,
                      imageTexture.width,
                      imageTexture.height,
                      imagePixels);
         }
         break;
      }
   ...
   }
}

Image 1.3

Great, part five is finished. Our basic cell pattern is complete for now. We have three types of irregular pattern one randomly show some cells, one altering the position of an image with in those cells and another combining these two effects. With procedural generation one can do quite a lot with these simple tools to make interesting effects. Often combining them in interesting ways can achieve surprising results.

We have learnt how to:
  • Use and enum to quickly switch settings in the inspector
  • Use a switch statement to switch between patterns
  • Interpolate images position in a cell basic on noise
  • Combine multiple pattern types

If you enjoyed this tutorial and would like me to add some extra content to it, like and share this tutorial on here and social media and leave a comment below. If you didn’t like this tutorial please leave a comment below saying why.





Wednesday, 19 April 2017

Procedural Generation Tutorial Basic Cell Pattern Texture - Part 4

Procedural Generation Tutorial Basic Cell Pattern Texture - Part 4


The end result of the full tutorial.

At the end of Part 4 we will have produced this (See image 1.0).
Image 1.0


Before you start you should know these things:
  • Create Texture variables
  • Manipulate textures using SetPixels
  • Create a basic texture pattern
  • What noise is and hot to use it with a texture pattern

You should have gone through these tutorials before going further:

  • Checker Board Texture
  • Brick Pattern Texture
  • Brick Pattern Noise Texture


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.

Part 3:


http://joseph-easter.blogspot.com/2017/04/procedural-generation-tutorial-basic_12.html
Checker Board Pattern Texture http://joseph-easter.blogspot.nl/2016/12/procedural-generation-tutorial-checker.html

Brick Texture Tutorial http://joseph-easter.blogspot.co.uk/2017/01/procedural-generation-tutorial-brick.html

Brick Noise Texture Tutorial http://joseph-easter.blogspot.nl/2017/02/procedural-generation-tutorial-brick_8.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 creating a very simple pattern using a cellular texture using code. This tutorial will use and build upon what we have learnt from the previous texture tutorials, by creating two textures, one for the background, and one for the foreground, dividing the foreground into cells and adding an image into those cells then combining those textures. Later we will add variation to it by deciding whether to show a cell based on it noise value in the texture space, then using that noise to position it with in the cell itself using bombing.


We will:
  • Explain the theory
  • Understand alpha composition
  • How to use alpha composition when combining two textures
  • Use 'Color32.Lerp' interpolation of achieve this effect
  • Normalise the alpha value correctly with 32 bit variables
  • Understand antialiasing a little bit to remove jaggys


Step 1: The theory

In this part, we will make our pattern texture more interesting by using noise. Our cellular texture uses a repeating tiled pattern. If this what you need for your project, then great. However, it would be more interesting if we add some irregularities to it. One way to do this would by choosing which cells should show the image from the top layer and which ones should not.

This can be done is one of two ways, either by storing each cell in an array of integers, and using ‘Random.Range’ to choose a select number of cells and using an array to say how many cells. This is OK but it’s completely random each time and you may find you want something a bit more controlled or pseudo-random. This is where the ‘Noise’ script comes in.

We will use the methods already created in the ‘Noise’ class and reference them in the ‘for’ loop of the ‘CreatePattern’ function. The noise value is determined by our quads position and interpolated by the cell’s position multiplied by the normalizer. This in turn will turn our quads position and cell position into values we can use. This is the method we will use in today’s tutorial.

Step 2: Noise Setup


A lot of this is like what we did back in 'Brick Noise Texture Pattern’. For this reason, I won’t go into what these functions do in much details apart from describe their general functions since I’ve already explained it. I will quickly explain any alterations in the code but that’s it. There is little point in explaining what the code already does when we have already gone over it in an earlier tutorial. If you need a refresher on what the code does, go back to that part of the ‘ Brick Noise Texture Pattern’ tutorial and read what you need to.

A lot of this is bootstrapping. We need a noise delegate from ‘NoiseLibrary’ static class to obtain the correct noise value from the right noise function. If you remember we have three noise value functions. From one dimensional hashing to three-dimensional value hashing. This is what the ‘NoiseDelegate’ is for. It’s stored locally in the script for when we need it.

You might be thinking ‘why include multi-dimensional noise functions?’. I’m including them here so we have more freedom to experiment with different types of noise complexities with cellular textures. This way we can get some interesting results.


Code: 


void CreatePattern()
{
   ...
   NoiseDelegate noiseDimention = 
          NoiseLibrary.randomValueFunction[
          noiseScr.noiseDimentions - 1];
   ...
}


We need to obtain the world coordinates of the quad (including the four points or corners that give its position). This will give us the base values for our pseudo-random noise before hashing them in the noise functions. We do this outside of the first ‘for’ loop. (Also make sure the ‘Noise’ is assigned to the ‘noiseScr’ variable in the ‘CellPattern’ script in the inspector).


Code: 



void CreatePattern()
{
   ...
   NoiseDelegate noiseDimention = 
          NoiseLibrary.randomValueFunction[
          noiseScr.noiseDimentions - 1];
   float normalizer = 1f / mainTexWidth;
   noiseScr.WorldCoordinates();
   ...
}

In the first ‘for’ loop we need to reference ‘LeftAndRightSides’ from ‘noiseScr’. This method interpolates the point between the left and right side of the quad to help interpolate the noise value. Because this function needs to have the points of the quad to operate we need to parse in a lot of variables. Luckily these points are already stored in ‘noiseScr’ so all we must do is reference them from the save script we are referencing the method from. (If any of this is unclear, it is in bold in the next code snippet below).

The only thing we really need to change here are the two last values at the end. Because our interpolations values are not based on a simple pixel of the texture but the current cell and position of it we need to parse it the iterator of the current ‘for’ loop ‘i’. We also need to parse it the current ‘normalizer’ so the iterator value parsed to it can be multiplied correctly within the interpolation function and stay with the texture confines.

Code: 



void CreatePattern()
{
   ...
   NoiseDelegate noiseDimention = 
          NoiseLibrary.randomValueFunction[
          noiseScr.noiseDimentions - 1];
   float normalizer = 1f / mainTexWidth;
   noiseScr.WorldCoordinates();
   for (int i = 0; i < squaresX; i++)
   {
      noiseScr.LeftAndRightSides(
                noiseScr.pointLL, 
                noiseScr.pointLR,
                noiseScr.pointUL,
                noiseScr.pointUR, i, 
                normalizer);
      ...
   }
   ...
}

The last thing we need to do here is calculate the final precise point in the texture. We do this by referencing the function ‘CalculatePoint’ from ‘noiseScr’ again as the code is already there. We need to parse it the ‘Vector3’ variables ‘leftSide’ and ‘rightSide’ from the same script again.

Next, like ‘LeftAndRightSides’ we need to parse it another integer to interpolate with and normalizer value to multiply it with. The integer is the precise cell we want it to interpolate with. We will use the iterator ‘j’ within the second ‘for’ loop as this tells us which cell is referencing on the ‘Y’ axis of the texture. The ‘normaliser’ does the same job as it did with ‘LeftAndRightSides’.

Code: 



void CreatePattern()
{
   ...
   NoiseDelegate noiseDimention = 
          NoiseLibrary.randomValueFunction[
          noiseScr.noiseDimentions - 1];
   float normalizer = 1f / mainTexWidth;
   noiseScr.WorldCoordinates();
   for (int i = 0; i < squaresX; i++)
   {
      noiseScr.LeftAndRightSides(
                noiseScr.pointLL, 
                noiseScr.pointLR,
                noiseScr.pointUL,
                noiseScr.pointUR, i, 
                normalizer);
      for (int j = 0; j < squaresY; j++)
      {
         noiseScr.CalculatePoint(
                noiseScr.leftSide, 
                noiseScr.rightSide,
                j, normalizer);
      }
   }
   ...
}

Great, the bootstrapping is complete. The noise values are set up and this will make our lives easier when getting the values, we need.

Step 3: Setting up the noise tolerance and showing the image

Great, we can generate a noise value. Now we need to get it and use it in our script. To use our noise value, we need to obtain it from the ‘NoiseDelegate’ ‘noiseDimention’ and store the value it returns locally in the function as a float.

We do this by creating a local variable of type ‘float’ called ‘noiseVal’ (the name is on the nose but being explicit is handy here). Assign it ‘noiseDimention’, doing this assigns the variable this delegate's return value (it must be of the same type though). (Note: you can do this with functions as well). While doing this we parse ‘point’ from ‘noiseScr’ and ‘patternAlternationSpeed’ to the delegate as well. This essentially performs a calculation using the point in the texture, multiplies it by the frequency of the noise pattern and masks the value along with some other calculations. This is how we get our noise value.

Code: 



void CreatePattern()
{
   ...
   NoiseDelegate noiseDimention = 
          NoiseLibrary.randomValueFunction[
          noiseScr.noiseDimentions - 1];
   float normalizer = 1f / mainTexWidth;
   noiseScr.WorldCoordinates();
   for (int i = 0; i < squaresX; i++)
   {
      noiseScr.LeftAndRightSides(
                noiseScr.pointLL, 
                noiseScr.pointLR,
                noiseScr.pointUL,
                noiseScr.pointUR, i, 
                normalizer);
      for (int j = 0; j < squaresY; j++)
      {
         noiseScr.CalculatePoint(
                noiseScr.leftSide, 
                noiseScr.rightSide,
                j, normalizer);
         float noiseVal = noiseDimention(
                          noiseScr.point,
            noiseScr.patternAlternationSpeed);
      ...
      }
   }
   ...
}

We need to use our ‘noiseVal’ now to decide whether we will show the image in the cell or not. To do this we will create a new variable and put the ‘SetPixels32’ comment for ‘topLaterTexture’ in a ‘for’ loop. We will use a public variable called ‘noiseTolerance’ and we will compare ‘noiseVal’ with it. If ‘noiseVal’ is greater than or equal to ‘noiseTolerance’ the image will be show in the cell. This way we can adjust the likelyhood of the image showing in the cells.


Code: 



public float noiseTolerance = 0.1f;
...
void CreatePattern()
{
   ...
   NoiseDelegate noiseDimention = 
          NoiseLibrary.randomValueFunction[
          noiseScr.noiseDimentions - 1];
   float normalizer = 1f / mainTexWidth;
   noiseScr.WorldCoordinates();
   for (int i = 0; i < squaresX; i++)
   {
      noiseScr.LeftAndRightSides(
                noiseScr.pointLL, 
                noiseScr.pointLR,
                noiseScr.pointUL,
                noiseScr.pointUR, i, 
                normalizer);
      for (int j = 0; j < squaresY; j++)
      {
         noiseScr.CalculatePoint(
                noiseScr.leftSide, 
                noiseScr.rightSide,
                j, normalizer);
         float noiseVal = noiseDimention(
                          noiseScr.point,
            noiseScr.patternAlternationSpeed);
         if (noiseVal >= noiseTolerance)
         {
            topLayerTexture.SetPixels(
                      i * blockWidth + 
                      middleOfCellWidth,
                      j * blockHeight + 
                      middleOfCellHeight,
                      imageTexture.width,
                      imageTexture.height,
                      imagePixels);
         }
      ...
      }
   }
   ...
}

Image 1.1



Now if we set ‘noiseTolerance’ to anything lower than ‘1’ all the cells with show an image from the ‘topLayerTexture’. If we set it higher than 0.9, none of the cells show. This is regardless of the quads position, rotation and scale. Let’s find out why this is happening. ‘print’ or use ‘Debug.Log’ on the variable ‘noiseVal’ just after it’s created and assigned.


Code: 



public float noiseTolerance = 0.1f;
...
void CreatePattern()
{
   ...
   NoiseDelegate noiseDimention = 
          NoiseLibrary.randomValueFunction[
          noiseScr.noiseDimentions - 1];
   float normalizer = 1f / mainTexWidth;
   noiseScr.WorldCoordinates();
   for (int i = 0; i < squaresX; i++)
   {
      noiseScr.LeftAndRightSides(
                noiseScr.pointLL, 
                noiseScr.pointLR,
                noiseScr.pointUL,
                noiseScr.pointUR, i, 
                normalizer);
      print(noiseVal);
      for (int j = 0; j < squaresY; j++)
      {
         noiseScr.CalculatePoint(
                noiseScr.leftSide, 
                noiseScr.rightSide,
                j, normalizer);
         float noiseVal = noiseDimention(
                          noiseScr.point,
            noiseScr.patternAlternationSpeed);
         if (noiseVal >= noiseTolerance)
         {
            topLayerTexture.SetPixels(
                      i * blockWidth + 
                      middleOfCellWidth,
                      j * blockHeight + 
                      middleOfCellHeight,
                      imageTexture.width,
                      imageTexture.height,
                      imagePixels);
         }
      ...
      }
   }
   ...
}


Image 1.2

This appears to be happening because we either went too high or too low. These are the values the position has generated. We could use this information for setting the noise tolerance in future, knowing the value range. Although we would have to go through this process every time we change the object’s transform I some way. Dealing with values this small and finicky means we must be precise when using it in another project to get the right results. A more practical solution would be to multiply ‘noiseVal’ by 10 getting it in a more user-friendly value range (e.g. 0 to 10). Then we can use this value in the is statement comparison instead of ‘noiseVal’.

Code: 



public float noiseTolerance = 0.1f;
...
void CreatePattern()
{
   ...
   NoiseDelegate noiseDimention = 
          NoiseLibrary.randomValueFunction[
          noiseScr.noiseDimentions - 1];
   float normalizer = 1f / mainTexWidth;
   noiseScr.WorldCoordinates();
   for (int i = 0; i < squaresX; i++)
   {
      noiseScr.LeftAndRightSides(
                noiseScr.pointLL, 
                noiseScr.pointLR,
                noiseScr.pointUL,
                noiseScr.pointUR, i, 
                normalizer);
      
      for (int j = 0; j < squaresY; j++)
      {
         noiseScr.CalculatePoint(
                noiseScr.leftSide, 
                noiseScr.rightSide,
                j, normalizer);
         float noiseVal = noiseDimention(
                          noiseScr.point,
            noiseScr.patternAlternationSpeed);
         float val = noiseVal * 10f;
         if (val >= noiseTolerance)
         {
            topLayerTexture.SetPixels(
                      i * blockWidth + 
                      middleOfCellWidth,
                      j * blockHeight + 
                      middleOfCellHeight,
                      imageTexture.width,
                      imageTexture.height,
                      imagePixels);
         }
      ...
      }
   }
   ...
}

Now when we test our code we get this (See image 1.3). If yours looks different to Image 1.3, check it has the same settings. These are annotated under Image 1.3.

Image 1.3: PatternAlternatioSpeed: 512, position: X: 0.4, Y: 0, Z: 0. 
Noise tolerance: 2f, resolution: 512 by 512, squaresX: 8, squaresY: 8.


If the pattern generated by the code is too regular e.g. only a small block of cells is not showing, generally it’s because the ‘patternAlternationSpeed’ is too low. A good idea is to make sure it’s in the hundreds (when dealing with a large texture with a lot of cells).

Step 4: A few refinements

We will do one thing to this. It is OK entering the value for the noise tolerance manually with a keyboard, but what is the user sets the value too low or too high. They may not know the value range the noise work with and they will wonder why the results are undesirable.

We can do this by adding a range value slider. This way the designer can enter the value via the keyboard if they know the precise value, but they can easily tweak it with a slider and stay in range.

When I have tested this usually a minimum value of 1 and a maximum value of 10 do the trick. The results of the noise values in this range create interesting and varies patterns. If you need to tweak this for you project though, do so. We do this by finding ‘noiseTolerance’, then on the line above it add the ‘Range’ attribute to it parsing ‘1’ and ‘10’ as the minimum and maximum values. (An attribute can be added to a class, function or property to give it extra functionality or more data for whatever reason. You add them by enveloping a pare or square brackets on both sides of it).

Code: 



[Range(1f, 10f)]
public float noiseTolerance = 0.1f;
...

Image 1.4: This shows the ‘Range’ attribute in action in the inspector.


Great, part four is finished. We have got the basics of an irregular pattern which only shows certain cells based on noise values. We can also adjust the noise tolerance and roughly manipulate how many cells show an image.



We have learnt how to:

  • Use our quad's position to generate a noise value
  • Combine this value with the cell position in the texture
  • This this value to decide weather to show a cell or not
  • Use noise tolerance to control what values show a cell
  • Adjust the noise tolerance in the inspector
  • Use a range slider in the inspector

In Part 5 we will create an enum to switch between different pattern modes. We will also use noise and the cell position to adjust the images position with in each cell. Then we will create a third setting that combines these modes.


Download project resources and files here.



Go to Part 5, click here.


If you enjoyed this tutorial and would like me to add some extra content to it, like and share this tutorial on here and social media and leave a comment below. If you didn’t like this tutorial please leave a comment below saying why.