<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Patrik Mandić</title>
    <description>The latest articles on DEV Community by Patrik Mandić (@afatduck).</description>
    <link>https://dev.to/afatduck</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F908568%2Fbd26ff8a-e292-4b5d-bff5-2252d98fd137.png</url>
      <title>DEV Community: Patrik Mandić</title>
      <link>https://dev.to/afatduck</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/afatduck"/>
    <language>en</language>
    <item>
      <title>Procedural Tiles with Shader Graph</title>
      <dc:creator>Patrik Mandić</dc:creator>
      <pubDate>Sun, 14 Aug 2022 18:13:54 +0000</pubDate>
      <link>https://dev.to/afatduck/procedural-tiles-with-shader-graph-48gi</link>
      <guid>https://dev.to/afatduck/procedural-tiles-with-shader-graph-48gi</guid>
      <description>&lt;h3&gt;
  
  
  Disclaimer
&lt;/h3&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;If you notice any mistakes or have better solutions, please point them out in the comments.&lt;/p&gt;

&lt;h3&gt;
  
  
  The goal
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Creating a texture
&lt;/h3&gt;

&lt;p&gt;For this example, I decided to create a simple texture with a black border and a small circle in the center using the &lt;em&gt;Rectangle&lt;/em&gt; and &lt;em&gt;Eclipse&lt;/em&gt; node.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qAMWzRb_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbfyreiswxbhrwpiylf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qAMWzRb_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbfyreiswxbhrwpiylf7.png" alt="Tile texture created in shader graph" width="880" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am also going to assume that this part doesn't require any explaining.&lt;/p&gt;

&lt;p&gt;Here is the texture on a resized cube.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2slK2d00--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fyeguqjoza1f9picqvlk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2slK2d00--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fyeguqjoza1f9picqvlk.png" alt="Tile texture on a cube" width="880" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tiling effect
&lt;/h3&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hLX-HFhP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hibo5w5p05d16gipa9fg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hLX-HFhP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hibo5w5p05d16gipa9fg.png" alt="Applying tilling to our texture" width="880" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that the effect works, but this is still not what we want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qXr2FU-B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvmigr7ku68hrqg1jx6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qXr2FU-B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvmigr7ku68hrqg1jx6o.png" alt="Cube with tiling applied" width="880" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Making tile size constant
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Getting an object's scale in shader graph is pretty easy. It's one of two properties we get from the &lt;em&gt;Object&lt;/em&gt; node.&lt;/p&gt;

&lt;p&gt;So, to get the number of tiles on a face, we can divide the scale by the tile size.&lt;/p&gt;

&lt;p&gt;To define the tile size I created a Vector2 property. In this example, I set it to .8.&lt;/p&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;p&gt;To solve this issue we need the normal vector, which we can access with the &lt;em&gt;Normal Vector&lt;/em&gt; 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.&lt;/p&gt;

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

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;em&gt;String&lt;/em&gt; and put this code in &lt;em&gt;Body&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Here is my implementation of that last part.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GcwSsbfn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nozku5bxw2h5ql6019ji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GcwSsbfn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nozku5bxw2h5ql6019ji.png" alt="Getting number or tiles" width="880" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is our cube. :D&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L1X_f9F1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/71vb28kdcaiqh4m4jh9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L1X_f9F1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/71vb28kdcaiqh4m4jh9w.png" alt="Final cube" width="880" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h4&gt;
  
  
  Thank you for reading!
&lt;/h4&gt;

</description>
      <category>unity3d</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>gamedev</category>
    </item>
  </channel>
</rss>
