Wednesday 25 March 2015

Procedural Generation Tutorial for Unity


Simple Brick Texture Code

No Shader Code

Hi every one! This post is the fist part in a series about different forms of procedural generation or procedurally generated content. I like to experiment every so often and procedural generation interests me. I purchased a book on procedural generation called ' Texturing and Modeling: A Procedural Approach (The Morgan Kaufmann Series in Computer Graphics)'. Here is a link to buy the book (http://www.amazon.co.uk/Texturing-Modeling-Procedural-Approach-Kaufmann/dp/1558608486/ref=sr_1_1?ie=UTF8&qid=1426513371&sr=8-1&keywords=procedural+generation).

This book is a good starting point for procedural generation because it eases you into the topic. It explains how shaders work and how they render lighting and textures, what procedurally generated content and how it differs from non-procedurally generated content, and the different types of procedurally generated content as well as different algorithms. It explains everything, like complex concepts in a down to earth, broken down manner, with out being patronizing (this makes a change from some programming books).

The book shows code in the C language for some examples and 'RenderMan' for other examples. You can use the code in the book if you know how to use both of those languages. However it is stated early on in the first chapter that the book is just meant to provide programming principles, concepts and methods that can be used in any languages or platform.

Why have I created this tutorial?

I decided to create this tutorial for a number of reasons. I found a few tutorials that used concepts such as Perlin Noise in Unity projects for things like textures. However, there was very little (if anything) in the way that showed how to create basic patterns using an algorithm (such as how to create a simple brick pattern). Most of these involved using shaders like Unity's 'ShaderLab' language, which if you are familiar with that then fine, but this tutorial is not about shader code. It's about creating textures using code.

Because there is nothing in the way of creating a texture using C# (or javaScript) code in Unity with out writing a new shader I decided to create this tutorial. This particular will be in 2 parts to start off, this post will get the ground work done and teach the basics. In future posts we will refine the project and improve it, and I may even cover other areas of procedural generation.

What Do I Need and What Skill Level is This Aimed For?

You need to have the Unity engine installed on your machine. This project should work with Unity 4.6 and above.

A text editor, such as MonoDevelop, Sublime, NotePadd++ or what ever you feel comfortable with.

A working knowledge of Unity (or at least know your way around the basics). If you are a beginner with Unity or do not know how to use it at all, this tutorial is NOT for you. Find a tutorial that will teach you the basics.

You should know how to code at least a little bit. Preferably a working knowledge of javaScript (aka UnityScript) or C#. I will be writing the tutorial initially in C# and will be showing the examples in it, but if enough people ask for javaScript examples, I will come back to it and add them in. However Unity technologies appear to be creating their video tutorials in C# a lot often in C# then javaScript, leaving javaScript out in the cold more often.

Also the code examples can be converted into javaScript easily enough if you know your way around well enough.

Also you should also know of the different types of procedural generation before you start this tutorial.

Right, requisites over. On to the actual tutorial.

Key:

The code can be copied and pasted into a text editor that you are using and should work inside Unity.


Any code I write will be formatted differently to the instructions.

When showing code as an example, I will write 'Code:' and the code following it. The code will be in a different font and be formatted correctly, so you will be able to tell when the code example ends. The font of the code will be in green, this will help to differentiate between the instructions and the examples.

When I have added a new piece of code or have modified/ changed preexisting code in a large block, I will put the changed code in bold like so. This will help to make it easier for you to see what is going on.

Tips:


I would save after completing each step in the tutorial just to save you a head ache or every 10 minutes. This is standard practice in the IT community. If not not just save often.



Step 1:

Open Unity, create a 'New Project' and call it 'Procedural Generation Brick Texture' . Don't add in any packages to this project, the are unneeded.

Click 'Create Project'.

In the 'Scene' view create a 'Quad' game object. If you want to you can make a cube, or a plain, but I'm using a quad for convenience.

Position the quad at 0 along the X, Y, and Z axis in the transform component. Make sure the quad is facing up, this can be done by setting it's rotation along the 'X' axis to '90', keeping the Y and Z axis at zero.

Position and rotate the scene Camera so the quad is in the players view in the 'Play' window.

Now save the scene. I'm calling the scene 'Brick Texture 1', but you can call it what you like.

Step 2:

In the 'Project' tab, create a new folder called 'Scripts' inside the 'Assets' folder. Inside the 'Scripts' folder create a new C# script (or if you are following along, and know how to convert to javaScript, create a javaScript). Call the script 'Brick Stretcher Texture'. Before we do anything else if you haven't already, attach the script to the quad game object.

Open the script file in an editor such as MonoDevelop, NotePad++, or sublime.

First off we need to create a texture and set it's X and Y resolution. We do this in the 'void Start' function because we want this to run only once and on the first frame the Scene starts. If it was in the 'Update' function there would be no point because it won't change and would be very resource intensive making the game crash.

Code:

public int resolution = 256;

public Texture2D wallTexture;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   renderer.material.mainTexture = wallTexture;
}

Let's break down the code. Above the start function I made a public variable called 'wallTexture' as a 2D texture. We don't want a 1D texture and a 3D texture is unnecessary. We only need a 3D texture for things like noise if we wanted it. This variable creates the texture and stores it as a variable so we can access it when we need to and we can manipulate it as needed.

public Texture2D wallTexture;

Next off we need to set the resolution on the texture, setting the amount of pixels along the X and Y axis. We could use two different numbers here, but for simplicity and as good practice goes power of two is the next approach (keep X and Y the same as each other). Above the 'wallTexture' variable there is an integer variable called 'resolution' and we have by default set this to 256. This stores the resolution. We have made this public so we can set the size easily in the inspector if we need to.



public int resolution = 256;


In side the 'Start' function we set the resolution properties of the texture along the X and Y axis at the same time. We set these to resolution for the reason I explained in the paragraph above. In C# you have to tell it it's a new texture property.


wallTexture = new Texture2D (resolution, resolution);

It sets the new properties you are specifying and places the old ones (if any). You also have to set them all at once.


This is all good but we need to examine the last line.


renderer.material.mainTexture = wallTexture;

We have created our texture, but we need to set the 'mainTexture' variable variable in the material to the 'wallTexture' variable.


The line sets the main texture variable of the material attached to the object to the 'wallTexture' just after the texture has been created. This makes it easier because we don't have to set it in the inspector ourselves. It sets the texture for us so it is rendered and the player can see it.


Great, now save the script, go back to Unity, let it compile and press play.



This is the default colour the pixels will be.

At the moment the pixels are blank because we haven't set them any values. We can see this in the 'Inspector' panel with the variable. You don't have to set the texture variable to public for this example, but I did for this one so it's easier to see what we are doing and can see the results.

Currently the texture is blank or grey because this is the default for pixels. We need to add colour to them.

Step 3:


Below the 'wallTexture' variable we will create another Texture2D variable called 'l_halfBrickTex'. This will create a square texture of the left half and right half of the brick.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   renderer.material.mainTexture = wallTexture;
}

Then we need to set the dimensions of the brick and brick texture. Under the variable resolution we need to create some more variables.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   renderer.material.mainTexture = wallTexture;
}

First off we need the dimensions of the brick itself both width and height. These are represented as 'brickWidth' and 'brickHeight'. Then we need the mortar all the way around the brick itself. This is down as 'mortarThickness'. Because these will all be done by pixel counts I have set these numbers as integers.


Next we need to create a temporary integer variable. This will store half of the bricks width (brickWidth divided by 2), plus the mortar thickness multiplied by 2. The code is as follows.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   renderer.material.mainTexture = wallTexture;
}

The code here is concise. If we left out the brackets the equation and result would change. We need to double the mortar thickness since the mortar is on both sides of outer brick. The variable 'halfBrickWidth' is temporary and we don't need it to be seen in the inspector since it's performing calculations the designer doesn't need to see behind the scenes.


The next thing we need to work out is the total height of the brick (including double the mortar). We need to do another calculation similar to the 'halfBrickWidth' one. We have to double the 'mortarThickness' value then add it to the 'brickHeight' value.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;


void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   renderer.material.mainTexture = wallTexture;
}

Next up we need to create the 'l_halfBrickTex' texture and set it's X and Y resolution like the wall texture.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   renderer.material.mainTexture = wallTexture;
}



The width (X) of the texture is 'halfBrickWidth' since we want the left half of it and the height (Y) is the 'brickMortarHeight'. We want the brick texture to have the dimensions of half a brick.

Before we start adding colour to the pixels of the 'l_halfBrickTex' texture variable we need to tell the material to render the 'l_halfBrickTex' temporarily instead of the 'wallTexture'. We do this by commenting out the render command for the 'wallTexture' and tell it to render the 'l_halfBrickTex'.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);

   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}

The reason we are doing this is that when we create the texture and set it's pixels we want to make sure we can clearly see the pattern in case we make any mistakes. If we go straight for creating the pattern, it can be more difficult to see what is going on because there will be a lot of distractions from the other parts. We're basically laying one brick down at a time as perfectly as we can before going on to the next bit. (You don't have to do this part, but from my experience (and programmers I know) it makes things easier if it goes wrong).

Press save, go back to Unity and let it compile, then press play. The same thing has happened like last time. The pixels have no colour.

Step 4:

To set the colours of the left brick texture we need to do a few things. The easiest and most 
efficient way to do this is to set the mortar colour first as one block of pixels. The mortar colour goes around the brick and the inside of the mini texture will actually be inside the brick and this will be the bricks actual colour.

So firstly the mortar colour will cover all of the pixels of the 'l_halfBrickTex' texture.We do this by using SetPixels, then telling it to start adding colour from the bottom left of the texture, then saying what proportions of the texture width and height need to be covered. Then we use a 'Color' array to tell it what colour we want those pixels set to. (NOTE: a non-array for the colours will NOT work because SetPixels works by assigning each pixel to a element of the colour array, left to right, bottom to top.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

public Color [] mortarColor;


void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}


Now save the script, and let Unity compile it. To to the 'Inspector' panel and find the array. Click on the carrot (or triangle thing). Where it says 'Elements', type '1'. Then click on the element and make it some shade of grey.


In the 'Inspector' when you have a public array a carrot (triangle) appears on the left of the name. Clicking it shows elements in the array. You can manually size the array like the box outlined in green. Elements can be changed manually, e.g. the other box outlined in green.

Save the scene and press play. The texture will stay at the default grey colour, but this error will come up.



This error means the array size is not large enough. The number if elements it has needs to be larger.


This basically means the array element size is not large enough to cover at least all the pixels because if you remember all pixels will be assigned an array. If the element does not exist, the engine will freak out because the pixel doesn't have anything to pigment itself with. The element size can be larger than the number of pixels in the texture but NOT lower. We could do this manually but that is tiresome, and we want this to be done automatically so we don't have to think about it and waste time.

Before the array is actually used we need to re-size it. We do this by recreating the array in the start function above the line where the SetPixels command is used. To tell it how many elements we want it to have we enter a value inside the square brackets (parenthesis). Because we want it to cover the pixels in the 'l_halfBrickTex' we set it to 'halfBrickWidth' multiplied by 'brickMortarHeight'. This will perform the calculation for us no matter how many pixels the 'halfBrickTex' texture contains if we re-size it.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   
   mortarColor = new Color (halfBrickWidth * brickMortarHeight);
   
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}


The next thing we need to do it apply the changed to the texture itself. At the moment we have told the texture to set the pixels, but these have only been applied in memory. We need to apply the hanged we have made to the texture in order to see the results in real time. To do this we need to apply the changes to the selected texture 'l_halfBrickTex'. The 'Apply ()' command applies the previous SetPixels or SetPixel command that was used on a texture.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   
   mortarColor = new Color (halfBrickWidth * brickMortarHeight);
   
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.Apply ();
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}

If we go back to Unity and run this code, it will work but not in the way you may expect.






This will happen, the picture is completely black. This is because when we re-sized the 'mortarColor' array in the Start function, we recreated it from scratch. So the previous values it held no longer exist. The reason they no longer exist is because is because we did not give each element a colour value on creation, so they want to the default blank value (black).

If you click play again and look at the array in the 'Inspector' panel and view it's elements, you can see the results here. All black.



All the cells are now black. The elements are NOT null, but have not been given colour values and default to black.


To fix this we need to two things. After the 'mortarColor' array has been re-sized but before it is actually used we need to assign each element in the array a new colour value. We could do this one by one but this would be arduous and take up more lines of code than necessary. For this reason we are going to use a 'for' loop to do the work for us.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

public Color [] mortarColor;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      
   }
   
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.Apply ();

   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}

In this for loop you may be wondering why I have written 'halfBrickWidth * brickMortarHeight'? Well that is because we want the for loop to go through the entire array in one go and the array size is 'halfBrickWidth' multiplied by 'brickMortarHeight'. We could do some complex maths and break it down into two for loops and so fourth, but that is unnecessary.

You may be thinking "can a condition in a for loop perform a calculation, I thought it would be easier to put it into one value and use that in the for loop instead?". We could do that, but this way takes up marginally fewer lines and is easier to understand what is going on and read (this is my opinion, this is not a fact or a standard, you can do as you like).

Inside the for loop we need to assign each element in the 'mortarColor' array a value other than black, preferably grey like we did last time. There is a way around this.

Above the 'mortarColor' array variable create another pubic colour and call it 'mortarColour' but don't make it an array. Keep it as a simple variable, turning it into an array is not required. Then in the for loop we will represent the current element in the array by using the temporary variable 'c' in the for loop inside the array indexer ([]). The currently indexed element will be set to the same value as our 'mortarColour' colour variable. This will happen for each element in the array.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

public Color mortarColour;

public Color [] mortarColor;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.Apply ();

   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}


If we go back to Unity after letting it compile we will see the 'mortarColour' variable appear above the 'mortarColor' array. Click on the 'mortarColour' box and choose grey from the colour picker, then save and click play.



Note: The box highlighted in green is the one you we should be concentrating on.
I chose to spell 'mortarColour', 'our' (like the UK) to differentiate the variables but make the connection easy.

Great, we now have the correct colour displaying and all of the elements in the array are grey.

Step 5:


This step is very similar to 'Step 4'. I would have added it to 'Step 4', but it was already quite long and I wanted to do this tutorial in sizeable chunks.

To add the brick colour to the 'l_halfBrickTex' we have to do several things. We will still be using the SetPixels command, but we'll be using it a little differently. Because we are creating the left side of the brick, the mortar does not need to go around all of the sides of it, just the left, top and bottom of it, not the right hand side.


This is a diagram of what the 'l_halfBrickTex' should look like.

Using the SetPixels statement we tell the 'l_halfBrickTex' to start setting the pixels at the integer value 'mortarThickness' because we want to leave the edges grey for the mortar. In case your thinking we don't we hard code this? Because the 'mortarThickness' value is adjustable it will sort out the starting position for us automatically and make the mortar in the texture as thick as we like. Also the pixels on a texture start at 0, 0, not 1, 1. It's like plotting coordinates. We do this for the X and Y coordinates.

For the width and height of the pixel block. In the brackets it's performing another calculation. We have set the width of the pixels to be 'halfBrickWidth' minus 'mortarThickness'. We have done this because if we just set 'halfBrickWidth' and left it to run, we won't get a texture but the console will throw an error saying it's outside of the texture bounds. The engine will not draw a texture if any of it's pixels are out of the texture bounds. That's why we use a variable we already have and take away 'mortarThickness' from it to make it cover just enough of the pixels.

For the height of the pixels to be set we use a similar calculation 'brickMortarHeight' minus, 'mortarThickness' times two. Again we do this because we already have a variable close the to value we want, but if we just take away one 'mortarThickness' it will still cover the top part of the texture where we want a grey line.

After this we create and use a variable called 'brickColor' from a colour array. We create it below the 'mortarColor' array variable.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;
public Color mortarColour;
public Color [] mortarColor;
public Color [] brickColor;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();

   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}


This is all good, but like last time we need to re-size the 'brickColor' array for the same reason we re-sized the 'mortarColor' array. It needs enough elements to colour each pixel.

We will do the same calculation that we did with the 'mortarColor' array, we will multiply the 'halfBrickWidth' variable by the 'brickMortarHeight' variable. Now you're asking 'but it will use fewer elements due to the size, why use the same amount?'. Because I want to save on typing, if you want to refine the code, go ahead. As an added thing, it creates a few buffer elements in case they are needed (but this is not a must).

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;
public Color mortarColour;
public Color [] mortarColor;
public Color [] brickColor;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();

   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}

The next part as you will remember from Step 4, is to create a for loop to to assign those new array elements a colour value for the brick colour. The condition in the for loop for the 'brickColor' array is pretty much the same as the 'mortarColour' array. We want to the same thing, the same number of times, but we wan to to use different variables and assign a different colour.

In the for loop below for the counter I have used the integer 'bC' which reminds me it is for the brick (lower case 'b') colour (upper case 'C'). You may have noticed I'm using camel case here (a typing convention). It's to I can differentiate between the two for loops and see what they are for.

Again because we want it to go through the whole array we will run the for loop the same number of times using 'halfBrickWidth * brickMortarHeight'.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

public Color mortarColour;
public Color [] mortarColor;
public Color [] brickColor;

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
      
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();

   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}

To assign each element a colour again we need to add the following like last time with the 'mortarColor'. We make every 'brickColor' element equal the colour value in the new colour variable 'brickColour'. Then we add the 'brickColour' variable at the top just above 'mortarColour'. (It's the one in bold).

Code:

public int resolution = 256;
public Texture2D wallTexture;

public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

public Color brickColour;
public Color mortarColour;
public Color [] mortarColor;
public Color [] brickColor;


void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
      brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();

   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}


If we save this, go back to Unity, we need to go into the 'Inspector' panel and find the 'brickColour' variable. Click on the variable value and choose a shade of red for the brick colour from the colour picker. Save the scene and run the code.


The brick colour appears and we have the left side of our brick done. It should look something like the image below.



Note: The texture is blurry and the reed from the right is wrapping around. We will fix this is a later tutorial but since out end texture will be larger, it won't be that noticeable. If you want to learn how to fix it sooner, look up 'texture' and 'wrapMode' for Unity.

We now have the left brick done, in the next step we will create the right brick texture.

(Also it's easier to view this way because even the brick is at a low resolution, the image is blown up and slightly stretched to fit the surface. This makes it easier to see any imperfections in the pattern).


Step 6:


This step will be pretty similar to the last step but with a few alterations. This will involve some copying and pasting of code we have already done.

For this bit we will be creating the right hand side of the brick. To do this we use the texture we created earlier 'r_halfBrickTex'. I have made it bold in the code below not because I have modified or added it again but so it's easier for you to notice it.

Code:

public int resolution = 256;

public Texture2D wallTexture;
public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

public Color brickColour;
public Color mortarColour;
public Color [] mortarColor;
public Color [] brickColor;


The 'r_halfBrickTex' will have the same pixel dimensions as the 'l_halfBrickTex' and the same colours but the coloured pixels will be positioned a little differently.

Like the 'l_halfBrickTex' texture variable we need to set the resolution of the texture. We will put this code under the left brick code to keep things organised.

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
      brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}

Again we need to set the pixels for the mortar and make sure it covers the entire texture.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c &lt; halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
      brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
 r_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMOrtarHeight, mortarColor);
   r_halfBrickTex.Apply ();
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = l_halfBrickTex;
}

The next bit, setting the brick colour is a little more complicated for the right hand side. We want the right hand edge to have mortar on it, the top and bottom as well. The left side however we don't want to be covered by grey pixels because if we put it to the right of the 'l_halfBrickTex' the bricks will appear unconnected. See image below for an example.


This shows how the two textures will work in unison side by side.


To do this we will set the pixels in a block like last time using the same width and height properties, but we will adjust it's X position a little. When setting the pixels we will keep the starting X coordinate at '0' and zero in this case is the most left pixel on the texture. We hard code this value because we know it's NOT going to change at all and there is no need to create a special variable for it. For the Y starting coordinate we use the 'mortarThickness' variable again because this could change.

Then for the height and width of the pixels to be set we use the same equation as with the left brick. If you need a reminder of how the equation works here it is again. For the width we know we want the brick colour to cover all of it apart from the number of pixels on the right hand side that is the 'mortarThickness'. For this we get the width and take away the number of pixel the 'mortarThickness' takes up. For the height, we get the height of the actual texture. Then we need to take away the 'mortarThickness' twice because we want to show the 'mortarColor' on the top and the bottom rows of pixels.

After this we change the 'mainTexture' or the material render to 'r_halfBrickTex' to set it to our newly created texture to see if it has come out all right.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
      brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
 r_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMOrtarHeight, mortarColor);
   r_halfBrickTex.Apply ();
   
   r_halfBrickTex.SetPixels (0, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   r_halfBrickTex.Apply ();

   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = r_halfBrickTex;
}

This is what we get from our new code.





Great we have the boring bits done. In the next and final step we will make a brick wall texture by putting there two mini textures together.

Step 7:

In this step we will be putting both of the textures we created for the left and right parts of the brick into one large texture. You are probably asking 'why split the brick texture in two?'. With a brick wall the brick alternate. So one layer is shifted by half a brick to the above or lower layer of bricks. If we had the brick as one whole texture, it would be a pain to code the alternating rows.

The way we will implement this is similar to creating a checker board pattern. We will create a grid of squares on the X and Y axis. Using a 'for' loop we will go through the squares on both axis. If the square's number on the X and Y axis equals the sum of total squares on the grid the 'for' loop will output one result, and if the X and Y axis does NOT equal the total sum, it will output a different result. The output that will be executed will set the pixel of the current block of the texture.

This approach is good for a simple checkerboard pattern or for when you need something to alternate two different outputs in a large system like a grid.

First we need to get the number of blocks on the X and Y axis for the large texture. We'll create two new integer variables in our code. We'll use 'blocksX' for square blocks on the X axis and 'blocksY' for blocks along the Y axis.

Code:

public int resolution = 256;
public int blocksX = 4;
public int blocksY = 4;
public Texture2D wallTexture;

public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

public Color brickColour;
public Color mortarColour;
public Color [] mortarColor;
public Color [] brickColor;

As you may have guessed the blocks are NOT pixels, they are groups of pixels that will be pigmented. We will create a 'for' loop to cycle through each block on the X axis in the start function.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
      brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
 r_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   r_halfBrickTex.Apply ();
   
   r_halfBrickTex.SetPixels (0, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   r_halfBrickTex.Apply ();
   
   for ( int x = 0; x < blocksX; x++)
   {
      
   }
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = r_halfBrickTex;
}

This will cycle through all of the blocks in the X axis, if we place our decider code in here it will only do a single row of blocks. We need to put another 'for' loop inside of it, also known as 'nesting'. For each block along the X axis we need it to cycle through all the blocks on the Y axis of the particular row. This will form our square grid.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC &lt; halfBrickWidth * brickMortarHeight; bC++)
   {
      brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
 r_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   r_halfBrickTex.Apply ();
   
   r_halfBrickTex.SetPixels (0, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   r_halfBrickTex.Apply ();
   
   for ( int x = 0; x < blocksX; x++)
   {
      for ( int y = 0; y < blocksY; y++ )
      {
         
      }
   }
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = r_halfBrickTex;
}

Inside the nested 'for' loop where we have 'blocksY' is where we write our interesting code. In here we write an 'if' statement that checks weather the current X and Y block is equal to the sum of all the blocks in the texture grid.

As a quick explanation of what the condition in the 'if' statement does. A single '&' is a bit wise operator. It works similar to the '&&;' but the double '&' is a Boolean operator. They are very different but works in a similar way. (If you want to know more about this leave a comment below and I may make a tutorial based on it. If you want to find out sooner, use Google). With a Boolean operator a value is either 'true' or 'false'. With a bit wise operator a value is converted (or cast temporally to the compiler) into a bit value of '0' or '1'. '0' is false or off and '1' is true or on. It's used to manipulate values for comparisons and calculations. It's a simple operation and is faster than performing an arrhythmic calculation to compare a value. It get's the the lowest bit of the variable inside the brackets and checks weather it is set. Because we have one on the right of the '&' if the value is odd the code inside the 'if' statement brackets runs. The 'x' and 'y' in the brackets is what creates the alternating effect we want to achieve.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
 r_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   r_halfBrickTex.Apply ();
   
   r_halfBrickTex.SetPixels (0, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   r_halfBrickTex.Apply ();
   
   for ( int x = 0; x < blocksX; x++)
   {
      for ( int y = 0; y < blocksY; y++ )
      {
         if (((x+y)&1) == 1 )
         {
            
         } else {
            
         }
      }
   }
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = r_halfBrickTex;
}

We're nearly there. We need to do a few more things now. The 'if' statement above means if 'blocksX' and 'blocksY' are odd numbers, the code inside the brackets will run. If that condition has NOT been met the 'else' code will run.

We will first place the left brick texture inside the 'if' statement. Actually before we even do that we need to get the pixels of the 'l_halfBrickTex' and store them somewhere locally. For this process we need to create a new colour array to store the colour of each pixel in the miniature texture. Whilst we're at it we'll create one for the 'r_halfBrickTex'.

Code:


public int resolution = 256;
public int blocksX = 4;
public int blocksY = 4;
public Texture2D wallTexture;

public Texture2D l_halfBrickTex;
public Texture2D r_halfBrickTex;

public int brickWidth = 7;
public int brickHeight = 3;
public int mortarThickness = 1;

public Color brickColour;
public Color mortarColour;
public Color [] mortarColor;
public Color [] brickColor;
public Color [] l_BrickTextureColor;
public Color [] r_BrickTextureColor;

Then we use the 'GetPixels' statement to put the pixels into the appropriate arrays. We do the same thing for the 'r_halfBrickTexture' in the 'else' condition.

Code:


void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
      brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
 r_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   r_halfBrickTex.Apply ();
   
   r_halfBrickTex.SetPixels (0, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   r_halfBrickTex.Apply ();
   
   l_BrickTextureColor = l_halfBrickTex.GetPixels (0, 0, halfBrickWidth , brickMortarHeight);
   r_BrickTextureColor = r_halfBrickTex.GetPixels (0, 0, halfBrickWidth , brickMortarHeight);
   
   for ( int x = 0; x < blocksX; x++)
   {
      for ( int y = 0; y < blocksY; y++ )
      {
         if (((x+y)&1) == 1 )
         {
            
         } else {
            
         }
      }
   }
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = r_halfBrickTex;
}

We then set the appropriate block of pixels to the same colour as the 'l_halfBrickTex' texture. We do this as we did last time but some more maths in involved. When telling it which pixel the 'SetPixels' command should start on the variable will change each time we the 'for' loop. In order to this we need to get the current value 'x' is at (in the temporary in the first 'for' loop) and multiply it by the width of the 'l_halfBrickTex' texture.

Then we do the same thing with the 'y' variable and 'brickMortarHeight'. Then we set the width and height of the pixels to be set using just the 'halfBrickWidth' and 'brickMortarHeight'. Then we set the colour of the pixels using the 'l_BrickTextureColor' array. Under the 'SetPixels' statements we need to actually apply the changes again so we can see them.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
 r_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   r_halfBrickTex.Apply ();
   
   r_halfBrickTex.SetPixels (0, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   r_halfBrickTex.Apply ();
   
   l_BrickTextureColor = l_halfBrickTex.GetPixels (0, 0, halfBrickWidth , brickMortarHeight);
   r_BrickTextureColor = r_halfBrickTex.GetPixels (0, 0, halfBrickWidth , brickMortarHeight);
   
   for ( int x = 0; x < blocksX; x++)
   {
      for ( int y = 0; y < blocksY; y++ )
      {
         if (((x+y)&<1) == 1 )
         {
            wallTexture.SetPixels (x*halfBrickWidth , y*brickMortarHeight,  halfBrickWidth brickMortarHeightl_BrickTextureColor);
            wallTexture.Apply ();
         } else {
            wallTexture.SetPixels (x*halfBrickWidth , y*brickMortarHeight,  halfBrickWidth brickMortarHeightr_BrickTextureColor);
            wallTexture.Apply ();
         }
      }
   }
   
   //renderer.material.mainTexture = wallTexture;
   renderer.material.mainTexture = r_halfBrickTex;
}

Oh and last but not least we need to tell it to render the 'wallTexture' again and NOT the 'r_halfBrickTex' texture. We can do this by deleting or commenting out the line below '//renderer.material.mainTexture = wallTexture;'.

Code:

void Start ()
{
   wallTexture = new Texture2D (resolution, resolution);
   int halfBrickWidth = (brickWidth / 2) + (mortarThickness * 2);
   int brickMortarHeight = brickHeight + (mortarThickness * 2);
   mortarColor = new Color [halfBrickWidth * brickMortarHeight);
   for (int c = 0; c < halfBrickWidth * brickMortarHeight; c++)
   {
      mortarColor[c] = mortarColour;
   }
   
   brickColor = new Color [halfBrickWidth * brickMortarHeight];
   for (int bC = 0; bC < halfBrickWidth * brickMortarHeight; bC++)
   {
      brickColor[bC] = brickColour;
   }
   l_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
   l_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   l_halfBrickTex.SetPixels (mortarThickness, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   l_halfBrickTex.Apply ();
   
   
   r_halfBrickTex = new Texture2D (halfBrickWidth, brickMortarHeight);
 r_halfBrickTex.SetPixels (0, 0, halfBrickWidth, brickMortarHeight, mortarColor);
   r_halfBrickTex.Apply ();
   
   r_halfBrickTex.SetPixels (0, mortarThickness, (halfBrickWidth - mortarThickness), (brickMortarHeight - (mortarThickness * 2)), brickColor);
   r_halfBrickTex.Apply ();
   
   l_BrickTextureColor = l_halfBrickTex.GetPixels (0, 0, halfBrickWidth , brickMortarHeight);
   r_BrickTextureColor = r_halfBrickTex.GetPixels (0, 0, halfBrickWidth , brickMortarHeight);
   
   for ( int x = 0; x < blocksX; x++)
   {
      for ( int y = 0; y < blocksY; y++ )
      {
         if (((x+y)&1) == 1 )
         {
            wallTexture.SetPixels (x*halfBrickWidth , y*brickMortarHeight,  halfBrickWidth brickMortarHeightl_BrickTextureColor);
            wallTexture.Apply ();
         } else {
            wallTexture.SetPixels (x*halfBrickWidth , y*brickMortarHeight,  halfBrickWidth brickMortarHeightr_BrickTextureColor);
            wallTexture.Apply ();
         }
      }
   }
   
   renderer.material.mainTexture = wallTexture;
}

Now if we save this, go back to Unity and run the code we will get this.




However there is one problem, there is a line along the top and the right hand side. Also what if we want more bricks on the wall and the brick are a certain size, some bricks may not show up due to texture constraints. This will throw an error. This texture code is good and does what it's supposed to do but if we want something more automatic and flexible we need to improve and polish this.


Great we have the ground work of the texture done. In part 2 we will be modifying this using our new knowledge and will refine this texture so the brick size adjusts according to how any brick we want according to our texture size.

If you have any suggestions for future blogs, please leave a comment below, weather it be on a certain topic or go into a topic further. If you did not like this blog, did not find it helpful or would prefer the format to be changed (e.g. font style, colour, etc), please leave a comment below saying why you didn't like it and leave a suggestions for improvements for later blogs (or the current one).

Thanks for reading! :)