{"id":85568,"date":"2019-11-04T23:36:52","date_gmt":"2019-11-04T23:36:52","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=85568"},"modified":"2021-07-29T19:44:06","modified_gmt":"2021-07-29T19:44:06","slug":"creating-a-shader-in-unity","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/creating-a-shader-in-unity\/","title":{"rendered":"Creating a Shader in Unity"},"content":{"rendered":"<p>Have you ever looked at a game and wondered how it achieved its appearance? Perhaps it looked like it was ripped straight from a comic book or the world was drawn perfectly to convey an eerie atmosphere. There are three components that create the look of the game, them being textures, materials, and shaders. Textures are simple images, which is what the material can use to define a surface. Shaders are small scripts that hold the mathematical calculations of every pixel rendered in game and are largely based on the lighting input and configuration of materials. Shaders can play a pivotal role in creating unique and interesting visuals for a project.<\/p>\n<p>To create a shader, one must be prepared to do a little graphics programming. Here, the aim will be to get your feet wet with a Unity shader of your own creation. The code in this shader will specify what to do with the very vertices that make up the triangles which in turn make up the geometry the material is applied to. By the end you should be able to create a material from this shader that draws an object in a wireframe. You can also change its color, the wire thickness and its transparency to get exactly the look you want in the object.<\/p>\n<h2>Creating the Shader<\/h2>\n<p>As of this writing, Unity has unveiled a new program called Unity Hub, which is where project creation will occur. Start by selecting the <em>New <\/em>button in the top right.<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"245\" class=\"wp-image-85569\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image.jpeg\" \/> Figure 1: Creating a new project in Unity Hub.<\/p>\n<p>Project creation proceeds as usual from here. Give it a name, select the type of project, and designate a location for the project. Once you have finished, click the create project button to begin.<\/p>\n<p><strong><img loading=\"lazy\" decoding=\"async\" width=\"846\" height=\"484\" class=\"wp-image-85570\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-1.png\" \/><\/strong><\/p>\n<p class=\"caption\">Figure 2: Project creation<\/p>\n<p>Of course, in order to test out any shader you create, you&#8217;ll first need an object or two. Here two objects will be made, a cube and a sphere, using the <em>Create <\/em>menu in the <em>Hierarchy.<\/em><\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"416\" height=\"237\" class=\"wp-image-85571\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-1.jpeg\" \/> <br \/>\nFigure 3: Creating objects<\/p>\n<p>To better view the objects, increase their scale to five, then place them anywhere you&#8217;d like. The example below places the <em>Cube <\/em>object at <em>-3<\/em>, <em>1.5<\/em>, <em>2 <\/em>position and rotates its x axis by <em>45<\/em> and its y axis by <em>25<\/em>. Your <em>Sphere <\/em>object can be placed at <em>5<\/em>, <em>1.5<\/em>, <em>0 <\/em>position with no rotation.<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"606\" height=\"149\" class=\"wp-image-85572\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-2.jpeg\" \/> <br \/>\nFigure 4: <em>Cube <\/em>object&#8217;s placement, rotation, and scale.<\/p>\n<p>The environment is now set, which means it&#8217;s time to begin creating the shader. Create your new shader by right clicking in the <em>Assets <\/em>window and selecting <em>Create-&gt;Shader-&gt;Standard Surface Shader.<\/em><\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"763\" height=\"710\" class=\"wp-image-85573\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-3.jpeg\" \/> Figure 5: Creating a new shader.<\/p>\n<p>You may name the shader whatever you wish, but the remainder of this writing will refer to this shader as <em>MyShader<\/em>. Now that this has been created, double click the newly created shader file to open Visual Studio and begin the coding process.<\/p>\n<h2>The Code<\/h2>\n<p>To recap, the shader in question will draw objects in a wireframe. For the uninitiated, a wireframe is a 3D model that is drawn with only the vertices and lines. There will be no textures or lighting on these wireframe objects. That removes some problems you would ordinarily have to figure out, but it presents some new ones as well. Drawing a series of triangles in code can yield its own set of challenges. Not only that, but the wireframe shader will have a slight glow to it as well as some user defined thickness and transparency.<\/p>\n<p>Back to Visual Studio, you can see that the code here is not like what you usually program in Unity. There are some parts that use Unity&#8217;s Shaderlab, a language for writing shaders, while others incorporate more traditional C for Graphics (Cg) and C# code with a heavy leaning towards Cg. There are some familiar elements such as structs and void functions while on other lines you&#8217;ll see syntax like <code>SubShader<\/code> and <code>LOD<\/code>. Those will be explained as they come, but this writing will largely be focused on the Cg and C# elements. Now that the environment has been established, it&#8217;s time to get to work on the wireframe shader.<\/p>\n<p>For starters, you can go ahead and delete all code currently within the shader. The shader you&#8217;re about to make will be created from scratch to more easily understand how all its parts come together. Once that&#8217;s done, enter the following:<\/p>\n<pre class=\"lang:c# theme:vs2012\">Shader \"Simple Talk\/Wireframe Tutorial\"\r\n{\r\n}<\/pre>\n<p>All this first line does is set the menu location for the shader. When editing any material there is a <em>Shader<\/em> menu you can navigate to select which shader this material will use. In this case, <em>MyShader<\/em> is found at <em>SimpleTalk-&gt;Wireframe Tutorial<\/em>. This will be demonstrated after you finish coding the shader. Speaking of which, it&#8217;s time to begin the shader creation proper, starting with property declarations. This will go within the Shader pair of curly braces.<\/p>\n<pre class=\"lang:c# theme:vs2012\">Properties\r\n{\r\n\t_Color(\"Color\", Color) = (1, 1, 1, 1)\r\n\t_Wireframe(\"Wireframe thickness\", Range(0.0, 0.005)) = 0.0025\r\n\t_Transparency(\"Transparency\", Range(0.0, 1)) = 0.5\r\n}<\/pre>\n<p>The general structure of a property is the variable name, the property&#8217;s designation in the editor, what kind of property it is, and then a default value. For example, the first variable is given the name <code>_Color<\/code> while in the editor it will display as whatever is in the quotations. Then you specify that it will be of the <code>Color<\/code> value type and give it a default color of white. <code>_Wireframe<\/code> and <code>_Transparency<\/code> are a little different in that their value types are given as a range of floats. This means in the Unity editor those variables can be edited by moving a slider.<\/p>\n<p>Next comes the <code>SubShader<\/code>, which defines rendering passes and optionally can set up any state common to all passes. In other words, it&#8217;s the part that makes the shader what it is. The <code>SubShader<\/code> goes inside the Shader under the Properties section.<\/p>\n<pre class=\"theme:vs2012 lang:c# decode:true\">SubShader{\r\n     Tags { \"Queue\" = \"Transparent\" \"RenderType\" = \"Transparent\" }\r\n     LOD 200\r\n}<\/pre>\n<p>At this point, the script should look like the below figure:<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"555\" height=\"255\" class=\"wp-image-85574\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-4.jpeg\" \/><\/p>\n<p class=\"caption\">Figure 6: The shader so far.<\/p>\n<p>Since you want the material born from this shader to be transparent, you give it both the render type of transparent as well as the queue in its tags. If you wanted a shader that still had a full object with wires around it, you would remove the queue tag to do so. As the ability to change the material&#8217;s transparency will be available, you need to let Unity know that the object is able to fade. You might wonder why you wouldn&#8217;t just set the color to have an alpha of zero to achieve the same effect. The reason is simple \u2013 it doesn&#8217;t affect anything. Materials appear to ignore the alpha value in the color selection on primarily focus on the RGB values. At that point, the biggest reason to keep the alpha value is tradition.<\/p>\n<p>Tags can also be queried later in other C# scripts for whatever purpose you may need. This is similar to the typical tagging system seen when creating an object in Unity. Finally, there&#8217;s the <code>LOD<\/code> line with a number beside it. <code>LOD<\/code> stands for Level Of Detail and controls, you guessed it, the level of detail in the material. For example, if an object has a material that makes it look like a concrete tile, the LOD controls how nice looking that concrete tile can be. You would typically have multiple LOD options for various computer builds but since this is a wireframe shader it&#8217;s reasonable to assume that the material derived from this shader could run on a toaster.<\/p>\n<p>Within <code>SubShader<\/code> you now must create a <code>Pass<\/code>. All the prep work is out of the way, meaning <code>Pass<\/code> will contain the code that defines the material&#8217;s appearance.<\/p>\n<pre class=\"lang:c# theme:vs2012\">Pass\r\n{\r\n\tBlend SrcAlpha OneMinusSrcAlpha\r\n\tCull Back\r\n}<\/pre>\n<p>And here&#8217;s how the script looks now:<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"555\" height=\"382\" class=\"wp-image-85575\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-5.jpeg\" \/><\/p>\n<p class=\"caption\">Figure 7: The shader with Pass included.<\/p>\n<p>The <code>Blend<\/code> line exists to create transparent objects and nothing more. <code>Cull<\/code> <code>Back<\/code> is you telling Unity to not render polygons facing away from the viewer. There is also <code>Cull<\/code> <code>Front<\/code>, which does the opposite of <code>Back<\/code> and stops the rendering of polygons facing the viewer, and <code>Cull<\/code> <code>Off<\/code> which draws all polygons regardless if they are currently being viewed. This example chose <code>Cull<\/code> <code>Back<\/code> with the belief that it looks better but you may adjust this as you wish.<\/p>\n<p>It&#8217;s now time to put those properties to use in some functions and structs. Before beginning, you&#8217;ll need to let Unity know that Cg is in use until otherwise noted by adding the following in <code>Pass<\/code><em>:<\/em><\/p>\n<pre class=\"lang:c# theme:vs2012\">CGPROGRAM<\/pre>\n<p>Then, under that create the following:<\/p>\n<pre class=\"lang:c# theme:vs2012\">#pragma vertex vertexFunction\r\n#pragma fragment fragmentFunction\r\n#pragma geometry geometryFunction\r\n#include \"UnityCG.cginc\"<\/pre>\n<p>The rest of the code all goes inside the <code>Pass<\/code> section. The pragma statements are very much like method declarations that you may normally find in a C# script. They will be defined later on in the coding process. At the end there&#8217;s an include statement, which lets the editor know you&#8217;ll be using some commonly used helper functions from that library. Now to create a couple structs:<\/p>\n<pre class=\"lang:c# theme:vs2012\">struct v2g\r\n{\r\n\tfloat4 pos : SV_POSITION;\r\n};\r\nstruct g2f\r\n{\r\n\tfloat4 pos : SV_POSITION;\r\n\tfloat3 bary : TEXCOORD0;\r\n};<\/pre>\n<p><code>v2g<\/code> stands for <code>vector 2 geometry<\/code> and contains a single variable \u2013 a float4 named <code>pos<\/code>, with <code>SV_POSITION<\/code> being what&#8217;s known as a semantic. Semantics is how you explain to the editor what the variable&#8217;s \u201cintent\u201d is. In this case, the intent is to output the clip space position of a vertex, this way the GPU knows where on screen to place pixels. The next struct, <code>g2f<\/code> (standing for <em>geometry 2 fragment<\/em>) has all the same info as <code>v2g<\/code> but with an additional float3 named <code>bary<\/code> which uses the <code>TEXCOORD0<\/code> semantic. <code>TEXCOORD0<\/code> is simply the first <code>UV<\/code> coordinate in the shader, given as a float3 in this example but can also be done with float2 or float4.<\/p>\n<pre class=\"lang:c# theme:vs2012\">v2g vertexFunction(appdata_base v)\r\n{\r\n\tv2g o;\r\n\to.pos = UnityObjectToClipPos(v.vertex);\r\n\treturn o;\r\n}<\/pre>\n<p>Earlier you wrote some pragma statements, which acted effectively as function declarations. It&#8217;s time to give those functions a little code to execute. First up is <code>vertexFunction<\/code> which, as the name suggests, gets the various vertexes ready for the next two functions. Then comes <code>geometryFunction<\/code>:<\/p>\n<pre class=\"lang:c# theme:vs2012 \">[maxvertexcount(3)]\r\nvoid geometryFunction(triangle v2g IN[3], \r\n     inout TriangleStream&lt;g2f&gt; triStream)\r\n{\r\n\tg2f o;\r\n\to.pos = IN[0].pos;\r\n\to.bary = float3(1, 0, 0);\r\n\ttriStream.Append(o);\r\n\to.pos = IN[1].pos;\r\n\to.bary = float3(0, 0, 1);\r\n\ttriStream.Append(o);\r\n\to.pos = IN[2].pos;\r\n\to.bary = float3(0, 1, 0);\r\n\ttriStream.Append(o);\r\n}<\/pre>\n<p>Here the different triangles that make up an object are being drawn. This is possibly the busiest function in the whole script, though you&#8217;ll notice a pattern \u2013 a few lines of code are being repeated, just with different elements in the <code>IN<\/code> array and the <code>bary<\/code> value from the <code>g2f<\/code> struct being given different float3 values each time. There&#8217;s also an attribute at the top of the function specifying that the maximum vertex count per shape is three, which makes sense as it is triangles being drawn and thus only need three vertexes per triangle. The last step remaining is to change the object based on the color, thickness and transparency values the user enters.<\/p>\n<pre class=\"lang:c# theme:vs2012\">float _Wireframe;\r\nfixed4 _Color;\r\nfloat _Transparency;\r\nfixed4 fragmentFunction(g2f i) : SV_Target\r\n{\r\n\tfloat value = min(i.bary.x, (min(i.bary.y, i.bary.z)));\r\n\tvalue = exp2(-1 \/ _Wireframe * value * value);\r\n\tfixed4 col = _Color;\r\n\tcol.a = _Transparency;\r\n\treturn col * value;\r\n}\r\nENDCG<\/pre>\n<p>You&#8217;ll notice the three variables kicking things off look awfully familiar. They share the name of the properties declared early in the script. Why the repeat? Remember that you&#8217;re currently working in the <code>CGPROGRAM<\/code> section and it needs to take in the properties defined early on to make any use of them. You can see their use implemented in <code>fragmentFunction<\/code>, where the object is given its assigned color, wireframe thickness, and transparency. Finally, the script ends with <code>ENDCG<\/code>, which tells Unity that Cg is not being used any longer.<\/p>\n<p>All the code needed to give objects a wireframe appearance is complete. Save your work and go back to the Unity editor. If there are errors, they will appear in the <em>Inspector <\/em>window upon selecting the shader file in the <em>Assets <\/em>window.<\/p>\n<h2>Putting the Shader to Use<\/h2>\n<p>First, you&#8217;ll need to create a material that uses this shader. The easiest way to do this is to right click the shader file in the <em>Assets <\/em>window and navigate to <em>Create-&gt;Material<\/em>.<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"651\" height=\"532\" class=\"wp-image-85576\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-6.jpeg\" \/><\/p>\n<p class=\"caption\">Figure 8: Creating a new material with <em>MyShader<\/em><\/p>\n<p>Name the material whatever you wish, then navigate to the <em>Inspector <\/em>window. If you look at the top of the <em>Inspector <\/em>window you can see the path <em>Simple Talk\/Wireframe Tutorial <\/em>in the <em>Shader <\/em>menu. Selecting that drop down menu brings up the following:<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"549\" height=\"291\" class=\"wp-image-85577\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-7.jpeg\" \/><\/p>\n<p class=\"caption\">Figure 9: The <em>Shader <\/em>menu. You can see <em>Simple Talk <\/em>as an option.<\/p>\n<p>In this menu you can select from any number of shaders, for this material, including the one just created. If you navigate to <em>Simple Talk-&gt;WireFrame Tutorial <\/em>you will select <em>MyShader <\/em>as the shader to base this material off of. Since you right clicked the shader and created the material from the context menu, this is not needed. However, you could still use this menu if you accidentally chose the wrong shader.<\/p>\n<p>In a preview window at the bottom of the <em>Inspector <\/em>window you can see how the material will look on an object. Go ahead and assign a color to it. You can also specify how thick you want the lines to be and how transparent the object is.<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"604\" height=\"166\" class=\"wp-image-85578\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-8.jpeg\" \/><\/p>\n<p class=\"caption\">Figure 10: Changing material properties.<\/p>\n<p>Your cube and sphere will need the material applied to them in order to better see the material, and by extension the shader, in action. Select an object and find its <em>Mesh Renderer <\/em>component in the <em>Inspector<\/em>. Under <em>Materials<\/em> there is a space to click and drag your new material in.<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"856\" height=\"473\" class=\"wp-image-85579\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-9.jpeg\" \/> Figure 11: Setting object material.<\/p>\n<p>Once you&#8217;ve done that, the project is finished, and you should see your objects take on its wireframe appearance. You can try playing with the values in the material to get different appearances.<\/p>\n<p class=\"caption\"><img loading=\"lazy\" decoding=\"async\" width=\"881\" height=\"386\" class=\"wp-image-85580\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2019\/11\/word-image-10.jpeg\" \/> Figure 12: <em>Cube <\/em>and <em>Sphere <\/em>with new material.<\/p>\n<h2>Conclusion<\/h2>\n<p>As shaders go this is perhaps one of the more basic ones you can create. Still, pat yourself on the back for dipping your toe into graphics programming. One way you can expand on this knowledge is to study and recreate the default shaders in Unity. All you need to do is create a new shader file, open the code in Visual Studio and have a look around. Or, you can get experimental and try coming up with your own unique shaders.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The visual elements of games are very important, and there is a lot to learn before you create the next best seller. In this article, Lance Talbert shows you how to create a shader, one tool in the game programmer\u2019s toolbox.&hellip;<\/p>\n","protected":false},"author":317499,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538,53],"tags":[95509],"coauthors":[52549],"class_list":["post-85568","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","category-featured","tag-standardize"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/85568","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/317499"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=85568"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/85568\/revisions"}],"predecessor-version":[{"id":85582,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/85568\/revisions\/85582"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=85568"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=85568"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=85568"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=85568"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}