Wednesday, 11 January 2017

Procedural Generation Tutorial Brick Texture - Part 1 of 4

Procedural Generation Tutorial Brick Texture - Part 1 of 4



The end result of the full tutorial.


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



Before you start you should know these things:
  • Basics of Unity interface
  • Be competent with C# 
  • Create Texture variables
  • Manipulate textures using SetPixels

You should have gone through and completed all the ‘Checker Board Texture’ tutorial 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.

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

In this tutorial series, we will be creating a simple brick pattern texture using code, a slight variation from the simple checkerboard pattern. We will make the code flexible and learn some more programming principals.


We will:
  • Bootstrap our project by adding the basic pattern code from the checkerboard tutorial
  • Dynamically adjust a texture’s dimensions based on a larger texture and the squares in it
  • Find the required amount of pixel space a texture need to fit in a bigger texture


Step 1: Bootstrapping our code

To begin our project, we will take a short cut. With how we are approaching the pattern I find it easier to split the brick in half and alternate between the two pieces. This is like how the checker board pattern alternates between the black and white squares. There are other ways to do this but they will not be covered in this tutorial.

After creating a new project and scene, create a new ‘Plain’ or ‘Quad’ in that scene and call it ‘Brick Pattern’. Next create a script called ‘BasicBrickPatternTexture’ and put it on the ‘Brick Pattern’ game object. After this copy and paste the code from the ‘CheckerBoardPattern’ script into our new script, we will modify some of this later.

Code:

public Texture2D mainTexture;

public int mainTextureWidth;
public int mainTextureHeight;

public int squaresX = 4;
public int squaresY = 4;

public int blocksWidth = 4;
public int blocksHeight = 4;

public Colour32 colour0;
public Colour32 colour1;

public Colour32 [] colour0Arr;
public Colour32 [] colour1Arr;

void Start ()
{
   SetMainTextureSize();
   ConvertColourToArray(blockWidth * blockHeight);
   CreatePattern();
}

void SetMainTextureSize()
{
   mainTexture = new Texture2D(mainTexWidth, mainTexHeight);
}

void CreatePattern()
{
  for (int i = 0; i < squaresX; i++)
  {
    for (int j = 0; j < squaresY; j++)
    {
      if (((i+j)%2)== 1)
      {
        mainTexture.SetPixels32(i * blockWidth,
                                j * blockHeight,
                                blockWidth,
                                blockHeight,
                                colourArr0);
      }
      else
      {
        mainTexture.SetPixels32(i * blockWidth,
                                j * blockHeight,
                                blockWidth,
                                blockHeight,

                                colourArr1);
      }
    }
  }
  mainTexture.Apply();
  GetComponent<Renderer>().material.mainTexture=
                                    mainTexture;
  mainTexture.wrapMode = TextureWrapMode.Clamp;
  mainTexture.filterMode = FilterMode.Point;
}

void ConvertColourToArray(int arrSize)
{
  colourArr0.Length = new Color32[arrSize];
  colourArr1.Length = new Color32[arrSize];

  for (int i = 0; i < arrSize; i++)
  {
    colourArr0[i] = colour0;
    colourArr1[i] = colour1;
  }
}


Figure 1.0: This is what you should have.


In the next step, we will work on how create the left side of the brick and adjust the mortar size dynamically and chose the brick and mortar colour.

Step 2: - Creating the half brick texture dimention variables

To create a texture for the brick we are going to create two side of it as two textures. One texture for the left side and one for the right. For now, we will concentrate on the left side because the code alternates between two values. We could do the brick as one whole thing but that would be more complicated.

To create a texture for the left half of the brick we need to create a ‘Texture2D’ variable for it like we have for the ‘mainTexture’. Now when we create the texture variable we need to set the texture dimensions. We could hard code these variables at the start in the Inspector but we may not know what size to set it at, especially if we adjust a parameter of the main texture because everything needs to fit. Now, the most practical thing to do is dynamically set the texture size. This is because we want multiple copies to fit in the ‘mainTexture’ based on the number of bricks we want in it.

For this we need to do some simple maths. We need to set how many bricks we need in the scene, on both the X and Y axis. Then we create a function called ‘ConvertBricksToSquares’ because bricks are normally double if they are tall. Then we set the ‘squaresX’ and ‘squaresY’ variables to private (because we don’t need to see them any more) then reference the function in the start method after creating the main texture.


Code:

public int bricksX = 2;
public int bricksY = 4;

private int squaresX = 4;
private int squaresY = 4;


void SetMainTextureSize()
{
   mainTexture = new Texture2D(mainTexWidth, mainTexHeight);

   ConvertBricksToSquares(bricksX, bricksY);
}
...
void ConvertBricksToSquares(int x, int y)
{
   squaresX = x * 2;
   squaresY = y;
}



Figure 1.1

This is what you should have (see figure 1.1). In simple terms this has doubled the number in the ‘bricksX’ variable and sent it to the ‘squaresX’ variable, and just sent ‘bricksY’ to ‘squaresY’. In the next step, we will use these variables to divide the ‘mainTexture’ dimensions into smaller values to be used as part of our brick half textures to fir into our main texture later.

Step 3:- Creating and Setting the Brick Texture Dimentions

Before we do anything else with our variables we need to create two new ‘Texture2D’ variables, one for the left side of the brick and one for the right side. We will call these ‘LeftBrickTexture’ and ‘RightBrickTexture’.

Code:

public Texture2D mainTexture;
public Texture2D leftBrickTexture;
public Texture2D rightBrickTexture;

Next up we need to tweak our ‘SetMainTextureSize’ method to set the dimensions of these textures as well. We will also rename it to ‘SetTextureSize’ as it’s setting multiple textures and update any references to it in our script.

In this method, we are basically creating two temporary int variables, ‘brickTexWidth’ gets the ‘mainTexWidth’ and divides it by ‘squares’ so the texture fits into the main texture. We do the same thing with the height by creating ‘brickTexHeight’ using ‘mainTexHeight’ and ‘squaresY’. After we do this we will set both ‘leftBrickTexture’ and ‘rightBrickTexture’ to new Texture2D dimentions. See image 1.1 for the result.



Code:

void SetMainTextureSize()
{
   mainTexture = new Texture2D(mainTexWidth, mainTexHeight);
   
   ConvertBricksToSquares(bricksX, bricksY);
   int brickTexWidth = mainTexWidth / squaresX;
   int brickTexHeight = mainTexHeight / squaresY;
   leftBrickTexture = new Texture2D(
                                brickTexWidth
                               ,brickTexHeight);
   rightBrickTexture = new Texture2D(
                                brickTexWidth
                               ,brickTexHeight);

}





As you can see we have created the basic texture variables, ready to be dynamically manipulated however we need. In part two we will work out how to use SetPixels32 to make them look like the left and right sides of a brick and how to dynamically adjust the thickness of the mortar in between the bricks.

Great, part one is finished. We have done some of the ground work.

We have learnt:


  • Convert one value to another simple value using simple maths
  • Adapt a method to fit another need
  • Resize a texture to fit into another texture
  • Find the required amount of space a texture need to fit in another larger texture

In Part 2 we will learn how to use SetPixels32 to make a texture look like a side of a brick, and set its mortar thickness dynamically. Click here for Part 2.


Wednesday, 4 January 2017

Procedural Generation Tutorial Checker Board Texture - Part 3

Procedural Generation Tutorial Checker Board Texture - Part 3


The end result of the full tutorial.



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


Before you start you should know these things:

You should have gone through and completed ‘Part 2’ of this tutorial 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.



https://joseph-easter.blogspot.com/2016/12/procedural-generation-tutorial-checker_81.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.

Links to Parts 1 - 3 of this tutorial series:

Part 1

Part 2

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


This tutorial will be split up into several parts. In this part we will continue from part two by:

  • Changing the number of squares on the texture independent of texture size
  • Adjust the size of the blocks dynamically independent of texture size
  • Change several pixels in one go using SetPixels32
  • Learn how to position said squares correctly using the width and height of the squares
In ‘Part 2’ we learnt how to set the texture to the material and how to make the texture less blurry round the edges at low resolutions. In this part we will learn how to make the texture more dynamic and flexible independent of texture size.

Step 1: -Difference Between SetPixel and SetPixels and SetPixels32:

In this step we will recode our ‘CreatePattern’ method in order to make it more flexible. At the moment the texture is ok and we have the foundations sorted. However, what if we want a texture that is bigger than 8 by 8? The pattern will repeat because each square is only a Pringles pixel, each square will get smaller and the pattern will appear grey. We want to be able to see the squares at higher resolutions.

We can do this by changing how our methods work a little bit. First off we need to be able to change large groups of pixels quickly in one go. Now we can do this using ‘SetPixel’ but this is slow and inefficient. However there are two alternative functions we can use, ‘SetPixels’ and ‘SetPixels32’; these are the block versions of ‘SetPixel’. These functions are virtually the same apart from ‘SetPixels32’ a bit more efficient and faster. As we want our texture to render as quickly as possible we will use this one.

Step 2: – Implementing SetPixels32 and setting block size


‘SetPixels32’ works like ‘SetPixel’ where we state the ‘X’ and ‘Y’ position, but after this we need to set the width, and height of the block itself. We add these variables after setting the position of the block but before we set the colour. For ease of use we will create and use two int variables ‘blockWidth’ and blockHeight’ and set them to a value of ‘4’.

Code:


public int blockWidth = 4;
public int blockHeight = 4;

void CreatePattern ()
{
    for (int i = 0; i < mainTexWidth; i++)
    {
       for (int j = 0; j < mainTexWidth; j++)
       {
          if ()
          {
             mainTexture.SetPixels(i, j, 
                     blockWidth, blockHeight,
                     Color.black);
          }
          else
          {
             mainTexture.SetPixels(i, j, 
                     blockWidth, blockHeight,
                     Color.white);
          }
       }
    }
    ...
}


If we go back to Unity and let the code compile we will get four errors, but two of them are the same because we have repeated part of the code. Out of the errors the ones highlighted are the ones to worry about. This is because the not highlighted ones is saying what line the problem is on and is telling us how the function works but not the specific error. (See figure 1.0)

Figure 1.0

The hilighted ones are telling us what the error actually is. It is because ‘SetPixels’ uses a colour array and not just a single. This seems a little odd but when you know how it works it makes sense. We will go through this in the next step.

Step 3: – Setting the colours using arrays

When using ‘SetPixels32’ we need to use a colour array to colour the block of pixels. This is because set pixels works by putting each pixel selected into a temporary array (that you don’t see) and it starts from the bottom left to the top right pixel. It sorts through each pixel one by one, and to do this quickly it works with a for loop, assigning one pixel a single colour.


Now you might be thinking, why not set it to just one colour variable. That’s because it is designed to also work with GetPixels32 (I won’t go into more detail in another tutorial). Therefore, if you are grabbing pixels from one image and want to past it to another, it’s useful to hold all of those pixels an another array and sort through. If you wanted to you could create your own version of set pixels but I won’t cover that here because it’s very single use.

We need to do is change our code a little and create two new variables. We need to create two ‘Color32’ arrays, one called ‘colour0Arr’ and ‘colour1Arr’ under the other variables.

Code:


public Color32 colour0Arr;
public Color32 colour1Arr;

void CreatePattern ()
{
    for (int i = 0; i < mainTexWidth; i++)
    {
       for (int j = 0; j < mainTexWidth; j++)
       {
          if ()
          {
             mainTexture.SetPixels(i, j, 
                     blockWidth, blockHeight,
                     colour0Arr);
          }
          else
          {
             mainTexture.SetPixels(i, j, 
                     blockWidth, blockHeight,
                     colour1Arr);
          }
       }
    }
    ...
}

Now when we let our code compile we will notice two things. When we run our code we get an error and both arrays are set to zero meaning they have no elements. (See figure 1.1)

Figure 1.1

This basically means there are not enough elements in the array to colour each pixel because we have not resized it yet, it’s still set to ‘0’ elements. We can fix this using a little trick.

We will create a new function below ‘CreatePattern’ called ‘ConvertColourToArray’. The value we parse the function will be used to set it’s new length for both arrays (we will parse ‘blockWidth’ times ‘blockHeight’ to get the value we need). (See Figure 1.2 for the results in the inspector)

Code:

void ConvertColourToArray (int arrSize)
{
    colourArr0 = new Color32[arrSize];
    colourArr1 = new Color32[arrSize];
}

Figure 1.2

We need to do one more thing, if we run the code we will still get and error. (See figure 1.3)


Figure 1.3


This is happening because the iterators ‘i’ and ‘j’ are counting every pixel in the texture. However when we get near to the top right of the texture pixel count (remember SetPixels32 works from bottom left to top right) we start running out of pixels to cover and it can’t colour pixels that don’t exist.

To fix this we need to count how many squares we want on the texture itself both on the ‘X’ and ‘Y’ axis using the iterators ‘i’ and ‘j’ in the for loops. We will do this by creating two new variables ‘squaresX’ and ‘squaresY’ and replace ‘mainTexWidth’ with ‘squaresX’ and ‘mainTexHeight’ with ‘squaresY’.

Code:


public int squaresX = 4;
public int squaresY = 4;

void CreatePattern ()
{
    for (int i = 0; i < squaresX; i++)
    {
       for (int j = 0; j < squaresY; j++)
       {
          if ()
          {
             mainTexture.SetPixels(i, j, 
                     blockWidth, blockHeight,
                     colour0Arr);
          }
          else
          {
             mainTexture.SetPixels(i, j, 
                     blockWidth, blockHeight,
                     colour1Arr);
          }
       }
    }
    ...
}

When we compile and run the code, this is what we get. (See figure 1.4)

Figure 1.4


The next things to do are colour the arrays. We could do this manually in the ‘Inspector’ but this would be boring, take too long and defeat the point.

For this reason we will do this using a for loop and create to new variables, which we’ll assign to the colour arrays.

Also when we reference the function, we need to parse it the ‘blockWidth’ multiplied by ‘blockHeight’. This with give us the area of pixels or the total number of pixels per block.

Code:

public Color32 colour0;
public Color32 colour1;

void ConvertColourToArray (int arrSize)
{
    colourArr0 = new Color32[arrSize];
    colourArr1 = new Color32[arrSize];

    for (int i = 0; i < arrSize; i++)
    {
       colourArr0[i] = color0;
       colourArr1[i] = color1;
    }
}

Grate we have created a function to automate this process for us. Now if we let the code compile and we set both ‘colour0’ and ‘colour1’ to two different colours and then save and run we will see the results. (See figure 1.5)

Figure 1.5: Far left image has the properties of the far right image. The centre image shows the one square per pixel.

What we have is ok but only if you want one square per pixel, anything other than that and you get the image in figure 1.5.1. We will fix this in the next (and final step). Now we need to do one more things and that’s it (for now).


Step 4:- Fixing the spacing

We have this overlapping effect. This is because it is still positioning each square one pixel apart but keeping the dimensions, therefore overlapping them. This is a straight forward fix.

Even though the for loops are counting the squares in each iteration ‘SetPixels32’ Is being parsed ‘i’ and ‘j’ for the starting X and Y position a bit like it’s counting the pixels of the texture. This is why the squares are drawn one pixel apart on the bottom left on the X and Y coordinates. This is also partly why there is the wired over lapping effect with the upper and right most edges and why the squares only appear to work properly at one pixel high and wide or we can’t have the same amount of pixels as squares with larger pixels.

We need to do two things, first we need to reposition the blocks correctly. When we do this, they need to be one blocks worth of pixels apart from each other on both the X and Y axis. We could replace the I and I iterations with the ‘blockWidth’ and ‘blockHeight’ vars but then the blocks would stack on top of each other. We need to multiply these values by the correct amount each time to space them out and by a varying degree each time.

We do this by modifying the function a little. Because we already have an integrator for both axis we multiply them by the appropriate variable, ‘i’ by the width ‘blockWidth’ and ‘j’ by the height ‘blockHeight’.

Code:

void CreatePattern ()
{
    for (int i = 0; i < squaresX; i++)
    {
       for (int j = 0; j < squaresY; j++)
       {
          if ()
          {
             mainTexture.SetPixels(i * 
                    blockWidth, j * 
                    blockHeight
                    blockWidth, blockHeight,
                    colour0Arr);
          }
          else
          { 
             mainTexture.SetPixels(i * 
                     blockWidth, j * 
                     blockHeight
                     blockWidth, blockHeight,
                     colour1Arr);
          }
       }
    }
    ...
}

Now enter ‘Play’ mode and see the results. (See Figure 1.6)

Figure 1.6

For your project you can adjust the variables for you needs but it’s pretty satisfying to look at. (Quick note: If a square exceeds the pixel count of the texture, it will not be drawn and you will get another ‘SetPixels32’ array error, but the rest will draw).

Great, part 3 and the checkerboard is finished.

We have learnt how to:
  • Use SetPixels to set a large group of pixels at once
  • Learnt how to resize and recolour a colour32 array quickly and easily
  • How to set block positions that don’t over lap each other using width times the integrator


If you would like more tutorial leave a comment below. If you want any extra refinements to this tutorial let me know and I will add more to it.

Download resources and project files.