Wednesday 25 January 2017

Procedural Generation Tutorial Brick Texture - Part 3 of 4

Procedural Generation Tutorial Brick Texture - Part 3 of 4



The end result of the full tutorial.



At the end of Part 3 we will have produced this (See image 1).
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.

http://joseph-easter.blogspot.com/2016/11/procedural-generation-tutorial-brick_28.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 3 and the completed project file of Part 3.





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



We will:


  • Recode the brick function creating the right-side brick
  • Create a switch statement
  • Tidy up code, putting left and right brick in separate functions




Step 1:- The theory


This part will be quick simple compared to Part 2. Most of the code is done for creating the brick we just need to copy some of it and change a few variables. The complicated bit will come when choosing which brick texture to use and how to make it easy to switch between the two textures.

For the right side of the brick we still want to keep a space between the top and bottom of the texture showing the mortar. However, we need to leave the right edge blank and cover the left side instead. This is easy to do. See figure 1.0 for reference.

Figure 1.0

The difficult will be how we chose which brick texture to colour in the function and how to make it easy for other programmers to use. We will basically parse an enum to the function. Then that function will have a switch statement which will use the enum to decided which part of the function to run. When this is, all done, we will tidy up the code and put the left and right brick into different function and reference them.

Step 2:- Choosing Left or Right, Recoding the function

The first thing we will do is modify the ‘CreateBrickColour’ method. Now, it only creates the left side of the brick, we need it to create both textures on demand as we need them. We can do this by parsing a value to the function and a switch statement can decide what to do based on the parsed value. We will create a switch statement because if we want to add more settings we can add it to the code easily and it’s easier to read. We will keep the ‘leftBrickTexture’ as the first option.

When writing the switch statement, we need a variable with multiple settings, we could create an int or string to use, but because the function is specific this could confuse developers. For this reason, we will use an enum with specific descriptive settings. Create an enum called ‘brickHalves’ and add ‘left’ and ‘right’ to it. After this add an enum parse variable to the function and put the ‘leftBrickTexture’ code in the first switch statement brackets.

Code:

private enum brickHalves {left, right};
private brickHalves brickHalf;
...
void Start()
{
   SetMainTextureSize();
   ConvertBricksToSquares(brickX, bricksY);
   CreateMortarColour{leftBrickTexture);
   CalculateBrickAndMortarSpacing();
   CreateBrickColour(bricksHalves.left);
   ConvertColourToArray(blockWidth * 
                        blockHeight);
   //CreatePattern();
}
...
void CreateBrickColour(brickHalves bH)
{
   switch(bH)
   {
      case brickHalves.left:
           leftBrickTexture.SetPixels32(
                  mortarThicknessWidth,
                  mortarThicknessHeight,
                  brickColourWidth,
                  brickColourHeight,
                  colour1Arr);
           leftBrickTexture.Apply();
           break;
   }
}


Now this is good but we need to add the brick colour code to the ‘rightBrickTexture’ Texture2D variable in step three. This will be quite straight forward.

Step 3:- Creating the Right-Side Brick Texture

Before we do anything else we need to comments out the line where we assign the ‘leftBrickTexture’ to ‘mainTexture’ to avoid confusion.

Code:

void CreateMortarColour(Texture2D tex)
{
   ConvertColourToArray(tex.width *
                        tex.height);
   tex.SetPixels32(0, 0, tex.width,
                   tex.height,
                   colour0Arr);
   tex.Apply();
   //GetComponent<Renderer>().material.
                           mainTexture = tex;
}


Back to the ‘CreateBrickColour’ function. In the ‘CreateBrickColour’ function create a new case in the switch statement for ‘brickHalves.right’, this is the option for the right half of the brick. In the start function just under the first ‘CreateBrickColour’ reference add another one but parse ‘brickHalves.right’ instead of ‘brickHalves.left’. Also, we need to colour the mortar background of the texture as well. Add another reference to ‘CreateMortarColour’ and parse it ‘rightBrickTexture’.


Code:

void Start()
{
   SetMainTextureSize();
   ConvertBricksToSquares(brickX, bricksY);
   CreateMortarColour{leftBrickTexture);
   CreateMortarColour{rightBrickTexture);
   CalculateBrickAndMortarSpacing();
   CreateBrickColour(brickHalves.left);
   CreateBrickColour(brickHalves.right);
   ConvertColourToArray(blockWidth * 
                        blockHeight);
   //CreatePattern();
}
...
void CreateBrickColour(brickHalves bH)
{
   switch(bH)
   {
      case brickHalves.left:
           leftBrickTexture.SetPixels32(
                  mortarThicknessWidth,
                  mortarThicknessHeight,
                  brickColourWidth,
                  brickColourHeight,
                  colour1Arr);
           leftBrickTexture.Apply();
           break;
      case brickHalves.right:
           break;
   }

}


Now in this new case we will use ‘SetPixels32’ on ‘rightBrickTexture’. A lot of the code will look very similar since a lot of it is doing the same stuff just right aligning the brick colour block. What we need to do is copy and paste the code from the above case but change the texture name to ‘rightbrickTexture’. This is because we already have the size and colour of the pixel area we need to cover and the position on the ‘Y’ axis to start at. What we need to change is where the ‘X’ starting position is. Because ‘SetPixels32’ works from the bottom left to top right, and we want the brick to have a space on the right edge of the texture we tell it to start from the bottom left pixel of the texture which is ‘0’. Then like last time we apply the changes to the texture using ‘rightBrickTexture.Apply’.Now in this new case we will use ‘SetPixels32’ on ‘rightBrickTexture’. A lot of the code will look very similar since a lot of it is doing the same stuff just right aligning the brick colour block. What we need to do is copy and paste the code from the above case but change the texture name to ‘rightbrickTexture’. This is because we already have the size and colour of the pixel area we need to cover and the position on the ‘Y’ axis to start at. What we need to change is where the ‘X’ starting position is. Because ‘SetPixels32’ works from the bottom left to top right, and we want the brick to have a space on the right edge of the texture we tell it to start from the bottom left pixel of the texture which is ‘0’. Then like last time we apply the changes to the texture using ‘rightBrickTexture.Apply’.

Code:

void CreateBrickColour(brickHalves bH)
{
   switch(bH)
   {
      case brickHalves.left:
           leftBrickTexture.SetPixels32(
                  mortarThicknessWidth,
                  mortarThicknessHeight,
                  brickColourWidth,
                  brickColourHeight,
                  colour1Arr);
           leftBrickTexture.Apply();
           break;
      case brickHalves.right:
           rightBrickTexture.SetPixels32(
                  0, mortarThicknessHeight,
                  brickColourWidth,
                  brickColourHeight,
                  colour1Arr);
           rightBrickTexture.Apply();
           break;
   }

}


Now this is ok but we want to see our texture on the plain itself to check for imperfections. To do this we will assign ‘rightBrickTexture’ to the ‘mainTexture’ of our game objects material. We will add this temporally in the case of the switch statement when we colour it and after applying changes. (You can remove or comment this line out after wards because we are just checking for mistakes on a big level). (See image 1.1 and 1.2).

Figure 1.1

Code:

void CreateBrickColour(brickHalves bH)
{
   switch(bH)
   {
      case brickHalves.left:
           leftBrickTexture.SetPixels32(
                  mortarThicknessWidth,
                  mortarThicknessHeight,
                  brickColourWidth,
                  brickColourHeight,
                  colour1Arr);
           leftBrickTexture.Apply();
           break;
      case brickHalves.right:
           rightBrickTexture.SetPixels32(
                  0, mortarThicknessHeight,
                  brickColourWidth,
                  brickColourHeight,
                  colour1Arr);
           rightBrickTexture.Apply();
           GetComponent<Renderer>().material.
              mainTexture = rightBrickTexture;
           break;
   }

}


Figure 1.2

Step 3:- Creating the Right-Side Brick Texture

What we have is good for now. However, we could make this a little neater, also if we add more to this function the code will be harder to read. The good thing about this function is that it’s no more than 20 lines. Although it does two separate things; it chooses what to do based on a value using a switch statement, it uses ‘SetPixels32’ on a texture and applies those changes. We can do a little better than that and make the code easier to read. The best thing to do is create a function for the Left brick and the Right brick and reference those functions in the switch statement case. That is what we will do here.

We will create a function below ‘CreateBrickColour’ called ‘LeftBrickColour’. Then cut and paste the code from the ‘brickHalves.left’ case to the ‘LeftBrickColour’ function.

Code:

void LeftBrickColour()
{
   leftBrickTexture.SetPixels32(
   mortarThicknessWidth,
   mortarThicknessHieght,
   brickColourWidth,
   brickColourHeight,
   colour1Arr);
   leftBrickTexture.Apply();

}


Now create another function below that and call it ‘RightBrickColour’. Then do the same thing but with the code from ‘brickHalves.right’ in the ‘CreateBrickColour’ function to the new ‘RightBrickColour’ function.

Code:

void RightBrickColour()
{
   rightBrickTexture.SetPixels32(
   mortarThicknessWidth,
   mortarThicknessHieght,
   brickColourWidth,
   brickColourHeight,
   colour1Arr);
   rightBrickTexture.Apply();

}


Reference these new functions where the code was previously in the case statements.

Code:

void CreateBrickColour(brickHalves bH)
{
   switch(bH)
   {
      case brickHalves.left:
           LeftBrickColour();
           break;
      case brickHalves.right:
           RightBrickColour();
           break;
   }

}

Great, part three is finished. The most of the basic building blocks are done. We need to put them all together now into a pattern.

We have learnt how to:
  • Write and use a switch statement
  • Perform a task based on a given switch statement case
  • How switch statements can be easier than using multiple if statements
  • How to use a custom enumeration (enum) and parse it to a function
  • How an enumeration can make multiple settings easier to implement 
  • How to tidy up our code and give a function one specific task

In part 4 we will learn how to get and set pixels form one texture to another using GetPixels and SetPixels together. We will then use this to create our large brick pattern based on the checker board code and the two textures we have created ‘leftBrickTexture’ and ‘rightBrickTexture’ and finish this segment.

Click here for Part 4.

Download resources and project files.

Wednesday 18 January 2017

Procedural Generation Tutorial Brick Texture - Part 2 of 4

Procedural Generation Tutorial Brick Texture - Part 2 of 4



The end result of the full tutorial.


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



Before you start you should know these things:

You should have gone through and completed ‘Part 1’ 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.



http://joseph-easter.blogspot.com/2016/11/procedural-generation-tutorial-brick.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 2 and the completed project file of Part 2.



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



We will:


  • Learn the basic theory of how to easily add mortar to our texture
  • Put theory into practice and add to our texture
  • Colour an entire texture easily
  • Layer different colours easily
  • Position the brick colour correctly
  • Dynamically change how thick the mortar is in the texture
  • Calculate the area to be covered using mortar and texture variables


Step 1: - Explaining the theory

In this part, we will focus on colouring the ‘LBrickTexture’. Before we start, we need to understand the theory of how we will do this. There are a few ways but this is the most efficient way I have found.

First off, we need two things, the colour of the brick and the mortar. Then we need to create another variable to say how thick we want the mortar to be (in pixels). After this we need to know how to colour the pixels with both the brick and mortar colour.

The most practical way to do this I have found is to colour the mortar first, treating it like a background colour because it goes around the brick. Then place the brick colour inside it but covering a smaller area of the texture (using the mortar variables) leaving only the top, bottom and left edges of the texture alone. See figure 1.0 for reference.

Figure 1.0

Step 2:- Adding the Mortar Colour

Before we do anything with the mortar variables we will add the mortar colour first as mentioned in step 1. This is quite quick and easy to do. First off we need to create a function called ‘CreateMortarColour’, this will colour the background of the texture which we will lay the brick colour over. Then we reference it in the ’Start’ method just after the ‘ConvertBricksToSquares’ method.

In this function, we will be using SetPIxels32 on ‘leftBrickTexture’ and colouring it using ‘colour0Arr’ which I have set to a grey colour. We will set it’s X and Y starting position to ‘0’ and ‘0’ and tell it cover the entire texture  using the textures width variable so we don’t have to hard code it. We do this using ‘leftBrickTexture.width’ and ‘leftBrickTexture.height’. Now we could continue like this but we will need to use this later for the right side of the brick without writing the same line again. Because we want our code to be as reusable as possible instead of specifying the texture, we could parse the ‘leftBrickTexture’ to our function and modify it based on that. We will call the parsed Texture2D ‘tex’. After doing this, parse ‘leftbrickTexture’ to the reference in the ‘Start’ function.

Code:


void Start()
{
   SetMainTextureSize();
   ConvertBricksToSquares(brickX, bricksY);
   CreateMortarColour(leftBrickTexture);
   ConvertColourToArray(blockWidth * blockHeight);
   CreatePattern();
}
...
void CreateMortarColour(Texture2D tex)
{
   tex.SetPixels32(0, 0, tex.width,
                         tex.height,
                         colour0Arr);
}


We have two more things to do in this step. If we run our code, we will get another ‘SetPixels32 failed’ error. This is because ‘colour0Arr’ doesn’t have enough elements to cover all the pixels of ‘leftBrickTexture’ in ‘CreateMortarColour’. This is quite an easy fix. In ‘CreateMortarColour’ just before we use ‘SetPixels’ we will reference ‘ConvertColourToArray’ and parse it ‘tex.width’ and ‘tex.height’ to get the area we need for the parsed texture. After we do this we need to apply the changes to the Texture2D variable. We do this by applying the changes using ‘tex.Apply()’ after we use ‘SetPixels32’. (See figure 1.1).

Figure 1.1

Code:


void Start()
{
   SetMainTextureSize();
   ConvertBricksToSquares(brickX, bricksY);
   CreateMortarColour(leftBrickTexture);
   ConvertColourToArray(blockWidth * blockHeight);
   CreatePattern();
}
...
void CreateMortarColour(Texture2D tex)
{
   ConvertColourToArray(tex.width * tex.height);
   tex.SetPixels32(0, 0, tex.width,
                         tex.height,
                         colour0Arr);
   tex.Apply();
}

Now if we want to see the results on a bigger scale we can temporally set this texture to our plain after applying the changes. We do this by using ‘GetComponent’ on the renderer and assigning this texture to the ‘mainTexture’ of the game object’s material. If you like you can copy and paste the line from the ‘CreatePattern’ function and change the assigned texture to ‘tex’ and comment out ‘CreatePattern’ for now in the ‘Start’ method. (See figure 1.2).

Code:


void Start()
{
   SetMainTextureSize();
   ConvertBricksToSquares(brickX, bricksY);
   CreateMortarColour(leftBrickTexture);
   ConvertColourToArray(blockWidth * blockHeight);
   //CreatePattern();
}
...
void CreateMortarColour(Texture2D tex)
{
   ConvertColourToArray(tex.width * tex.height);
   tex.SetPixels32(0, 0, tex.width,
                         tex.height,
                         colour0Arr);
   tex.Apply();
   GetComponent<Renderer>().material.mainTexture
                                          = tex;
}


Figure 1.2

When you have finished seeing the result comment out ‘the ‘GetComponent’ line in ‘CreateMortarColour’. In step three we will work out how dynamically change the brick size and calculate the variables.

Step 3: - Colouring in the brick


Now we have coloured in the mortar we need to colour the brick portion of the texture. As discussed in the previous steps we will fill in the brick colour by covering a smaller area of the texture, overlaying the mortar colour. The space not covered by the brick colour will leave the mortar colour visible. This sounds complicated but it is not.

First off, we need to create function which will fill in the brick colour, ‘CreateBrickColour’. Then just to get the function started we will use ‘SetPixels32’ on ‘leftBrickTexture’ setting ‘X’ and ‘Y’ to ‘0’. To get the effect described in the paragraph above we need a dynamic way to make it leave a little bit of the texture untouched. For the time being we will take away ‘1’ from the width and height variables (just to demonstrate the point, we will improve this in a bit). Then set the colour variable to ‘colour1Arr’, and apply the changes. (Make sure the ‘Colour1’ variable is set to a solid red. (See figure 1.3).

Code:


void Start()
{
   SetMainTextureSize();
   ConvertBricksToSquares(brickX, bricksY);
   CreateMortarColour(leftBrickTexture);
   CreateBrickColour();
   ConvertColourToArray(blockWidth * blockHeight);
   //CreatePattern();
}
...
void CreateBrickColour()
{
   leftBrickTexture.SetPixels32(0, 0,
                       leftBrickTexture.width - 1,
                       leftBrickTexture.height - 1,
                       colour1Arr);
   leftBrickTexture.Apply();
}


Figure 1.3


Step 4: - Calculating the covered area


Now this is ok, but what if we want to change the thickness of the mortar. We could change how much we take away from the texture width and height as it’s hard coded. This would be fiddly and we need to change it quickly and easily in the inspector, and as it’s procedural this would defeat the point. We should create a few variables which we can set as the area to cover and these variables will be calculated by another function. Create a new function called ‘CalculateBrickAndMortarSpacing’.

Next, we want to set the thickness of the mortar as an ‘int’, create two new public ‘int’s at the top called ‘mortarThicknessWidth’ and ‘mortarThicknessHeight’, set them to ‘1’ for now. Just under this we will create two private ‘int’s called ‘brickColourWidth’ and ‘brickColourHeight’ which are the width and height it will cover. (Why have two variables for mortar thickness? You don’t need to do this. I did it to make it more customizable in case a pattern needs more mortar on one axis without affecting everything else).

In the function, we will calculate the area using two equations, one for width and height. For now, we will assume that the area covered for the brick is the same on both sides (this will also make the equation easier for us as we won’t have to calculate it once). The first equation will work out the width to cover. We do this by assigning ‘brickColourWidth’ to ‘leftBrickTexture.width’ minus ‘mortarThicknessWidth’. Then below it we will do the same but with ‘brickColourHeight’, ‘leftBrickTexture.height’ and ‘mortarThicknessHeight’ but times two.

We multiply the mortar height by two because the value will subtract this from the top and bottom of the texture. If we don’t do this there will not be enough space for it and there needs to be at least equal space between the top and bottom.

Code:


public int mortarThicknessWidth = 1;
public int mortarThicknessHeight = 1;

private int brickColourWidth;
private int brickColourHeight;
...
void Start()
{
   SetMainTextureSize();
   ConvertBricksToSquares(brickX, bricksY);
   CreateMortarColour(leftBrickTexture);
   CalculateBrickAndMortarSpacing();
   CreateBrickColour();
   ConvertColourToArray(blockWidth * blockHeight);
   //CreatePattern();
}
...
void CalculateBrickAndMortarSpacing()
{
   brickColourWidth = leftBrickTexture.width -
                         mortarThicknessWidth;
   brickColourHeight = leftBrickTexture.height -
                    (mortarThicknessHeight * 2);
}


Great, now we need to add these variables into ‘CreateBrickColour’ replacing the old ones in ‘SetPixels32’. Then we need to change two little things, the starting positions for the ‘X’ and ‘Y’ axis. Set ‘X’ to ‘mortarThicknessWidth’ and ‘Y’ to ‘mortarThicknessHeight’. We already have these variables to hand so there’s no point in creating new ones for this purpose. It will position them away from the bottom left by the amount of the mortar thickness for us. See figure 1.4.

Code:


void CreateBrickColour()
{
   leftBrickTexture.SetPixels32(
                       mortarThicknessWidth,
                       mortarThicknessHeight,
                       brickColourWidth,
                       brickColourHeight,
                       colour1Arr);
   leftBrickTexture.Apply();
}


Figure 1.4





Great, part two is finished. We have laid down more foundations to the frame work.


We have learned how to:
  • Easily cover an entire textureusing SetPixels32
  • Easily layer colours for a pattern in a texture
  • Use simple mathematics with a texture's variables and custom variables
  • Dynamically cover part of a texture using said variables
  • Position the brick colour correctly using the mortar variable available


In part 3 we will learn how to create the right side of the brick using the skills we have, how to position the brick colour correctly and change the brick function to make it easier to use for both bricks.