DEV Community

Cover image for Procedural Tiles with Shader Graph
Patrik Mandić
Patrik Mandić

Posted on

Procedural Tiles with Shader Graph

Disclaimer

I am a beginner myself when it comes to game dev. This may not be the best way to do this, but I failed to find another method online, so this might help a fellow newbie.

If you notice any mistakes or have better solutions, please point them out in the comments.

The goal

So, what I wanted to create is a shader, I mean, a material with a repeating texture I could just assign to a cube and then resize it however I want. It had to look the same on every side, and the tile size had to be constant.

Just to be clear from the beginning, as far as I know, this will work correctly only if you are using a cube.

Creating a texture

For this example, I decided to create a simple texture with a black border and a small circle in the center using the Rectangle and Eclipse node.

I am going to assume you already know how to create a shader graph shader, assign it to a material, and assign that material to an object.

Tile texture created in shader graph

I am also going to assume that this part doesn't require any explaining.

Here is the texture on a resized cube.

Tile texture on a cube

Tiling effect

Creating a tiling effect is pretty straightforward; all we need is a Tiling And Offset node, connected to the Fraction node, which we then connect to our texture nodes, in this case, Rectangle and Eclipse.

We can then mess with tiling Vector2 to choose the number of tiles. There is also an offset Vector2, but I won't be using that one here.

Applying tilling to our texture

We can see that the effect works, but this is still not what we want.

Cube with tiling applied

Making tile size constant

This is, of course, the most difficult part. However, since we are using a resized cube as our object, we can make use of the object's scale to determine the number of tiles.

Getting an object's scale in shader graph is pretty easy. It's one of two properties we get from the Object node.

So, to get the number of tiles on a face, we can divide the scale by the tile size.

To define the tile size I created a Vector2 property. In this example, I set it to .8.

You might have noticed that there is one small problem, scale is a Vector3 property, and tiling is a Vector2 property, so how will we pick which two axis we need?

To solve this issue we need the normal vector, which we can access with the Normal Vector node. The normal vector is perpendicular to the texture face. That means that if we invert and then multiply the normal vector with the scale, we will get a Vector3 with the irrelevant axis as zero.

Make sure you use the Absolute node somewhere in this process to avoid negative values. Also, set the normal vector space to Object. Otherwise, rotating the cube will ruin your tiles.

The last thing to do is just removing the 0 from our Vector3, thus turning it into a Vector2 we can connect to tiling.

I wasn't sure how to approach this problem so I just reused a custom node I created for something else which takes three inputs and returns the two largest ones.

If you want to use the same method I did, create a custom node, give it three float inputs (A, B, C) and two float outputs (X, Y). Set the type to String and put this code in Body.

bool a = A < B;

if (a) {
bool c=C<A;
Y=B;
X=c?A:C;
}

else {
bool b=C>B;
X=A;
Y=b?C:B;
}
Enter fullscreen mode Exit fullscreen mode

And that's it! Our cube is now covered with equally large tiles. And we can use this shader to create walls, floors, and whatnot.

Here is my implementation of that last part.

Getting number or tiles

And this is our cube. :D

Final cube

If you want the tiles to perfectly fit the surface, so, no cut tiles (like in the picture), make sure the cube size is divisible by the tile size.

Thank you for reading!

Top comments (0)