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.


2 comments:

  1. I followed the tutorial for the Checker Board texture so I thought I would go through this. Because this directly follows from the Checker Board one, a lot of the code can be reused and the tutorial states this and points out the existing code can be adapted with a few tweaks. This saves a lot of time without repeating the same steps again. The first step is dedicated to explaining bootstrapping. This helps with the general pattern. The tutorial also explains creating the left and right side of the brick as separate textures to work with the checkerboard logic. It also explains how to create these textures dynamically and automatically.

    ReplyDelete
  2. I initially read the checkerboard tutorial and decided to read this one. I am glad this explains what bootstrapping is at the beginning and the benefits of it. Because if you have already done the work once, why do it again. I like how it explains how to adapt it to work for the current project, this saves a lot of time. Dividing the brick into two textures for both halves is clever and alternating between them makes a lot of sense. This must be easier than creating one texture and shifting it left or right for each corresponding row. Also automatically resizing the texture to fit into a larger one is a smart approach. This way you do not have to adjust the left and right brick textures every time you adjust the resolution of the main texture. This is smart!

    ReplyDelete