{"id":355,"date":"2015-10-23T06:21:49","date_gmt":"2015-10-23T06:21:49","guid":{"rendered":"http:\/\/magiteker.com\/?p=355"},"modified":"2016-10-24T23:10:43","modified_gmt":"2016-10-24T23:10:43","slug":"unity-shader-experiments","status":"publish","type":"post","link":"https:\/\/magiteker.com\/index.php\/2015\/10\/23\/unity-shader-experiments\/","title":{"rendered":"Unity Shader Primer"},"content":{"rendered":"<p style=\"text-align: justify;\">Shaders are one of the more obscure technologies within the Unity game engine, and while the <a href=\"http:\/\/docs.unity3d.com\/Manual\/ShadersOverview.html\">documentation<\/a> covers most of the shader language and functions it fails to provide comprehensive techniques that would result in compelling graphics. They&#8217;re core focus appears to be that of treating shaders as a black box with which materials are constructed and applied to meshes and while this allows for quick iteration and prototyping of mechanics it fails to provide an intuitive means by which a\u00a0game designer can move past hobbyist levels of production value.Unity&#8217;s shader language, <b>ShaderLab<\/b> , is based on the <a href=\"http:\/\/http.developer.nvidia.com\/CgTutorial\/cg_tutorial_chapter01.html\" target=\"_blank\">Nvidia CG Language<\/a> which is similar in structure to C making it somewhat obscure when it comes to translating graphical concepts to a visible program. As such in this blog post I&#8217;ll be detailing and dissecting several shaders I&#8217;ve developed after doing my own research into the subject.<\/p>\n<h1 class=\"post-title\">Setup:<\/h1>\n<p>&nbsp;<\/p>\n<p style=\"text-align: left;\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"374\" data-permalink=\"https:\/\/magiteker.com\/index.php\/2015\/10\/23\/unity-shader-experiments\/test_scene\/\" data-orig-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?fit=557%2C557&amp;ssl=1\" data-orig-size=\"557,557\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"test_scene\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?fit=512%2C512&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?fit=557%2C557&amp;ssl=1\" class=\" wp-image-374 alignleft\" src=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?resize=324%2C324&#038;ssl=1\" alt=\"test_scene\" width=\"324\" height=\"324\" srcset=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?resize=512%2C512&amp;ssl=1 512w, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?resize=128%2C128&amp;ssl=1 128w, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?resize=160%2C160&amp;ssl=1 160w, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?resize=50%2C50&amp;ssl=1 50w, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/test_scene.png?w=557&amp;ssl=1 557w\" sizes=\"auto, (max-width: 324px) 100vw, 324px\" data-recalc-dims=\"1\" \/><\/p>\n<p style=\"text-align: justify;\">To test Unity 5.x shaders I&#8217;ve opted to first construct a scene complete with the new physically based rendering bounce lighting effect. To set this up I&#8217;ve first constructed some level geometry consisting of four walls, each a separate color, and a floor. The bounce lighting is visible on the floor geometry due to\u00a0 baked light maps Unity 5.x generates based on meshes flagged as being static in the scene. I am also utilizing the default blue skybox for global illumination.<\/p>\n<p>&nbsp;<\/p>\n<h2 class=\"post-title\">Global Illumination<\/h2>\n<div>\n<p style=\"text-align: justify;\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"375\" data-permalink=\"https:\/\/magiteker.com\/index.php\/2015\/10\/23\/unity-shader-experiments\/lightsettings\/\" data-orig-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/lightsettings.png?fit=565%2C623&amp;ssl=1\" data-orig-size=\"565,623\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"lightsettings\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/lightsettings.png?fit=464%2C512&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/lightsettings.png?fit=565%2C623&amp;ssl=1\" class=\"wp-image-375 alignright\" src=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/lightsettings.png?resize=429%2C473&#038;ssl=1\" alt=\"lightsettings\" width=\"429\" height=\"473\" srcset=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/lightsettings.png?resize=464%2C512&amp;ssl=1 464w, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/lightsettings.png?w=565&amp;ssl=1 565w\" sizes=\"auto, (max-width: 429px) 100vw, 429px\" data-recalc-dims=\"1\" \/><\/p>\n<p style=\"text-align: justify;\">To achieve these lightmap results the following setup is used. The most important portion of these settings is the Precomputed Realtime GI which controls the amount of processing the CPU will use to construct the lightmaps.<\/p>\n<p style=\"text-align: justify;\">The General GI settings contains the values that affect the lighting being simulated in your scene as they influence the lightmap. The Intensity and Boost values scales the effect of each bounced light ray on a surface, when varied can create some interesting results.<\/p>\n<p style=\"text-align: justify;\">The atlas size is used to control the size of the baked image, the larger the image the more GPU memory your game will require.<\/p>\n<p style=\"text-align: justify;\">That should cover the bulk of the scene setup, it should be noted that I have my player settings setup for forward rendering since none of these examples will require using the stencil shader or altering shadows.<\/p>\n<p style=\"text-align: justify;\">\n<\/div>\n<p><!--nextpage--><\/p>\n<h1 class=\"post-title\">Basic Shader Syntax<\/h1>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">In the most basic sense the job of any shader is simply to provide detail to some mesh geometry. Shaders accomplish this through a set of inputs or properties exposed by the shader program to the engine. These inputs can hold various types of data such as textures, vectors, or values. Finally using these inputs the shader computes their affect combined with a lighting model to achieve a rendered scene.<\/p>\n<p style=\"text-align: justify;\">The first line of a shader program contains the <strong>Shader<\/strong> keyword followed by the menu structure for unity to use within the editor, and last the name of your shader.<\/p>\n<p style=\"text-align: center;\"><strong>Shader <\/strong><strong>&#8220;SubMenu\/ShaderName&#8221;<\/strong><\/p>\n<p style=\"text-align: justify;\">Properties in any shader are exposed in the first section of the shader program, preceded by the keyword <strong>Properties. <\/strong>Within this code block variables are exposed using the syntax<strong>:<\/strong><\/p>\n<p style=\"text-align: center;\"><strong>VariableName <\/strong>(&#8220;<strong>Variable Description<\/strong>&#8220;, <strong>Type<\/strong>) = <strong>Default Value<\/strong><\/p>\n<p style=\"text-align: justify;\">Once properties are defined the next code block is the <strong>SubShader<\/strong>. The subshader section contains the <strong>Tags <\/strong>section which defines the lighting model to be used with the shader, typically all that is required is <strong>&#8220;RenderType&#8221; <\/strong>= <strong>&#8220;Opaque&#8221;<\/strong> but there are many more models to experiment with.<\/p>\n<p style=\"text-align: justify;\">Next within the subshader block is the <strong>#pragma <\/strong> section which tells the GPU which order to execute your shader functions in, as well as any other shader functions you want to include. Tags should be followed by the <strong>CGPROGRAM <\/strong>directive to alert the compiler where your shader starts.<\/p>\n<p style=\"text-align: justify;\">The rest of the shader is similar to a C program wherein you would define a memory structure to access your game data along with declaring any other variables to access your property data. Within the shader function, in this case the <strong>surf<\/strong>\u00a0function, you must pass in parameters to utilize the data you need such as UV coordinates, mesh position, time, ect. Also you must define an output for your function to send back to the GPU, in this example <strong>inout SurfaceOutput o<\/strong> receives the color data of the texture <strong>_MainTex<\/strong> at the UV location stored in <strong>IN.uv_MainTex<\/strong>, these variables are passed to a standard function <strong>tex2D<\/strong> which returns the color data to <strong>o.Albedo<\/strong> to be rendered by Unity.<\/p>\n<p style=\"text-align: justify;\">Last you have the option of declaring a <strong>Fallback<\/strong> shader program just in case there is a problem with your custom shader.<\/p>\n<p style=\"text-align: center;\">\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nShader &quot;Custom\/ShaderExperiment1&quot; {    \r\n\tProperties {\r\n\t  _MainTex (&quot;Texture&quot;, 2D) = &quot;white&quot; {}\r\n\t}\r\n\tSubShader {\r\n\t  Tags { &quot;RenderType&quot; = &quot;Opaque&quot; }\r\n\t  CGPROGRAM\r\n\t  #pragma surface surf Lambert\r\n\t  struct Input {\r\n\t\t  float2 uv_MainTex;\r\n\t  };\r\n\t  sampler2D _MainTex;\r\n\t  void surf (Input IN, inout SurfaceOutput o) {\r\n\t\t  o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;\r\n\t  }\r\n\t  ENDCG\r\n\t} \r\n\tFallBack &quot;Diffuse&quot;\r\n}\r\n<\/pre>\n<\/p>\n<p><!--nextpage--><\/p>\n<h1 class=\"post-title\">Shaders and Game Data<\/h1>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">This next section will explain how to alter a mesh&#8217;s texture based on internal game data, such as the gameobject&#8217;s world position.<\/p>\n<p style=\"text-align: justify;\">In order to implement the desired effect first the properties code block must be expanded to include a few new items. The <strong>Center<\/strong> property will define the world position vector that the shader will alter itself, and the <strong>Radius<\/strong> property which will determine how large the effect will be.<\/p>\n<p style=\"text-align: justify;\">The next alteration will be in the <strong>input <\/strong>struct, an extra field <strong>worldPos <\/strong>is added to access the mesh world position at runtime. Then we declare the new properties into the shader above the shader <strong>surf<\/strong> function.<\/p>\n<p style=\"text-align: justify;\">The <strong>surf<\/strong> function&#8217;s parameters remain unchanged since the <strong>Input<\/strong> struct was all that needed to be altered. Inside the function some math is used to determine when to change the mesh. First the distance between the <strong>Center<\/strong> and <strong>worldPos<\/strong> vectors is stored followed by a delta calculation between 1.0 and 0.0 involving that <strong>saturate<\/strong> function, which is a fancy min max function.<\/p>\n<p style=\"text-align: justify;\">Next the delta variable is altered using a series of <strong>step<\/strong> functions, which checks to see if the first parameter is larger than the second, essentially this is a fancy test to check if delta is larger than 0.3 and 0.25 is smaller than delta. This trick is used because shaders are more efficient at math than at doing branches, so while you can write simple if else statements you can achieve higher frame rates relying on pure math.<\/p>\n<p style=\"text-align: justify;\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"391\" data-permalink=\"https:\/\/magiteker.com\/index.php\/2015\/10\/23\/unity-shader-experiments\/shadertwo_pic-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shadertwo_pic1.png?fit=322%2C161&amp;ssl=1\" data-orig-size=\"322,161\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"shadertwo_pic\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shadertwo_pic1.png?fit=322%2C161&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shadertwo_pic1.png?fit=322%2C161&amp;ssl=1\" class=\"wp-image-391 size-full alignleft\" src=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shadertwo_pic1.png?resize=322%2C161&#038;ssl=1\" alt=\"\" width=\"322\" height=\"161\" data-recalc-dims=\"1\" \/>Finally the mesh&#8217;s <strong>o.Albedo<\/strong> is assigned again using <strong>tex2D<\/strong> with its result scaled by the delta variable which sets the color to white. The end result of this shader is that a white circle, with a radius defined by the <strong>Radius<\/strong> property, will be projected onto a mesh when that mesh is moved to the position defined by the <strong>Center<\/strong> property.<\/p>\n<p style=\"text-align: center;\">\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nShader &quot;Custom\/ShaderExperiment2&quot; {    \r\n\tProperties {\r\n\t  _MainTex (&quot;Texture&quot;, 2D) = &quot;white&quot; {}\r\n\t  _Center (&quot;Center&quot;, Vector) = (0,0,0,0)\r\n\t  _Radius (&quot;Radius&quot;, Float) = 0.5\r\n\t}\r\n\tSubShader {\r\n\t  Tags { &quot;RenderType&quot; = &quot;Opaque&quot; }\r\n\t  CGPROGRAM\r\n\t  #pragma surface surf Lambert\r\n\t  struct Input {\r\n\t\t  float2 uv_MainTex;\r\n\t\t  float3 worldPos;\r\n\t  };\r\n\t  sampler2D _MainTex;\r\n\t  float3 _Center;\r\n\t  float _Radius;\r\n\r\n\t  void surf (Input IN, inout SurfaceOutput o) {\r\n\t\t\tfloat d = distance(_Center, IN.worldPos);\r\n\t\t\tfloat dN = 1 - saturate(d \/ _Radius);\r\n\t\t\tdN = step(0.25, dN) * step(dN, 0.3);\r\n\t\t\to.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * (1-dN) + half3(1,1,1) * dN;\r\n\t  }\r\n\t  ENDCG\r\n\t} \r\n\tFallBack &quot;Diffuse&quot;\r\n}\r\n\r\n<\/pre>\n<\/p>\n<p><!--nextpage--><\/p>\n<h1 class=\"post-title\">Vertex Shaders<\/h1>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"400\" data-permalink=\"https:\/\/magiteker.com\/index.php\/2015\/10\/23\/unity-shader-experiments\/shaderthree_pic-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shaderthree_pic1.png?fit=580%2C290&amp;ssl=1\" data-orig-size=\"580,290\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"shaderthree_pic\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shaderthree_pic1.png?fit=512%2C256&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shaderthree_pic1.png?fit=580%2C290&amp;ssl=1\" class=\"wp-image-400 alignleft\" src=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shaderthree_pic1.png?resize=324%2C162&#038;ssl=1\" alt=\"\" width=\"324\" height=\"162\" srcset=\"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shaderthree_pic1.png?resize=512%2C256&amp;ssl=1 512w, https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shaderthree_pic1.png?w=580&amp;ssl=1 580w\" sizes=\"auto, (max-width: 324px) 100vw, 324px\" data-recalc-dims=\"1\" \/>Since the topic of GPU&#8217;s being optimized for math has been touched upon this next section will demonstrate a method of quickly altering mesh geometry for visual effect. More specifically this shader will cause the faces of a mesh to move along the direction of the surface normals.<\/p>\n<p style=\"text-align: justify;\">The <strong>Properties<\/strong> code block for this shader only contains two values, a texture and a ranged float. The ranged float value will be what causes the displacement of the mesh geometry.<\/p>\n<p style=\"text-align: justify;\">Within the <strong>SubShader <\/strong>block the <strong>#pragma <\/strong> must be extended to contain our new vertex function by appending <strong>vertex:vert<\/strong> to the end of this line. The\u00a0<strong>vertex<\/strong> identifier tells the shader compiler that this function will operate on the mesh&#8217;s vertexes, and <strong>vert<\/strong> simply refers to the new function name. Appending this function the end of\u00a0<strong>#pragma<\/strong> means it will be the last function to be called in this shader, so after the mesh has been prepared to be rendered.<\/p>\n<p style=\"text-align: justify;\">The <strong>vert <\/strong>function contains a single <strong>inout <\/strong>parameter appdata_full which contains the mesh geometry we want to alter in this case. Within this function each mesh vertex is accessed sequentially then the position of that vertex is added to the scaled vector of the vertex normal by the <strong>Amount<\/strong> property. The end result being that the vertex is displaced like we wanted.<\/p>\n<p>&nbsp;<\/p>\n<p style=\"text-align: center;\">\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nShader &quot;Custom\/ShaderExperiment3&quot; {    \r\n\tProperties {\r\n\t  _MainTex (&quot;Texture&quot;, 2D) = &quot;white&quot; {}\r\n\t  _Amount (&quot;Extrusion Amount&quot;, Range(-2, 2)) = 0\r\n\t}\r\n\tSubShader {\r\n\t  Tags { &quot;RenderType&quot; = &quot;Opaque&quot; }\r\n\t  CGPROGRAM\r\n\t  #pragma surface surf Lambert vertex:vert\r\n\t  struct Input {\r\n\t\t  float2 uv_MainTex;\r\n\t  };\r\n\t  float _Amount;\r\n\t  void vert(inout appdata_full v)\r\n\t  {\r\n\t\tv.vertex.xyz += v.normal * _Amount;\r\n\t  }\r\n\r\n\t  sampler2D _MainTex;\r\n\t  void surf (Input IN, inout SurfaceOutput o) {\r\n\t\t\t o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;\r\n\t  }\r\n\t  ENDCG\r\n\t} \r\n\tFallBack &quot;Diffuse&quot;\r\n}\r\n\r\n<\/pre>\n<\/p>\n<p><!--nextpage--><\/p>\n<h1 class=\"post-title\">Accessing Properties At Run-time<\/h1>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">Both of the example shaders utilize various properties to define their effects and up until now these properties were set in either the editor or the shader itself, however it is possible to access these properties at run-time via the Unity API.<\/p>\n<p style=\"text-align: justify;\">The API has several <a href=\"http:\/\/docs.unity3d.com\/Manual\/MaterialsAccessingViaScript.html\" target=\"_blank\">setters and getters<\/a> built in for assigning values to a material using a script and they all utilize a <strong>string<\/strong> to access a specific shader property. This <strong>string <\/strong>is the name assigned to the property in the shader program, i.e. to change the main texture of a material you would use the following function.<\/p>\n<p style=\"text-align: center;\"><strong>SetTexture(&#8220;_MainTex&#8221;, NewTexture);<\/strong><\/p>\n<p style=\"text-align: justify;\">This syntax is similar for all material properties including Colors, Vectors, Matrices, Ints, and Floats, and is shared for the getters where instead of a new value you supply a default value, the important take away is that your script must contain a string with the name of the property you wish to access.<\/p>\n<p style=\"text-align: justify;\">It&#8217;s important to understand the difference between unity materials and instanced materials, in short when you affect a material you change every mesh that uses that material where as if you only change an instanced material your changes will only propagate to the mesh that has that material instance. To illustrate the difference both methods will be described below.<\/p>\n<h2 class=\"post-title\" style=\"text-align: center;\">Non-instanced Material Change<\/h2>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">There are two ways to change material property values without instancing the material, store a reference to a material in a script, or access the shared material of a game object through the <strong>Renderer <\/strong>component.<\/p>\n<p style=\"text-align: justify;\">Using the first method, storing a material reference, simply create a material field in your script then assign the material you wish to control using the editor. After the material is assigned you can access its properties and changes will propagate to all game objects in the scene.<\/p>\n<p style=\"text-align: justify;\">The second method requires the script to be attached to a game object using the material you wish to control. Then the script can utilize the <strong>GetComponent <\/strong>function to get the object&#8217;s <strong>Renderer <\/strong>component, from this component the <strong>sharedMaterial<\/strong> property can be accessed which stores a reference to your material.<\/p>\n<p style=\"text-align: justify;\">As an example say you want to change the color of all game enemies, using the enemy material, to a new color. Using the first method would be better in this case since the material we want to control is known and can be stored ahead of time. In which case the following function call would control the material color.<\/p>\n<p style=\"text-align: center;\"><strong>enemyMaterial.SetColor(&#8220;_DiffuseColor&#8221;, newColor);<\/strong><\/p>\n<p style=\"text-align: justify;\">In the second method in order to change the enemy color the material must first be accessed. Its good practice to store a reference to the <strong>Renderer<\/strong> component in the script, to assign this reference use the following syntax<\/p>\n<p style=\"text-align: center;\"><strong>renderer = GetComponent&lt;Renderer&gt;();<\/strong><\/p>\n<p style=\"text-align: justify;\">After storing the reference to the renderer the next step is to get the shared material which can be accessed and stored like so.<\/p>\n<p style=\"text-align: center;\"><strong>enemyMaterial = renderer.sharedMaterial;<\/strong><\/p>\n<p>Then finally we can use the <strong>SetColor<\/strong> function just like in the first method.<\/p>\n<h2 class=\"post-title\" style=\"text-align: center;\">Instanced Material Change<\/h2>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">An important aside to changing materials in this way is that it will increase the draw calls your game must perform, meaning for every material you instance your game will have to draw separately which will take longer for each frame to process. Also material instancing only takes place the first time a script changes a material property per game object.<\/p>\n<p style=\"text-align: justify;\">For example say a script changes the color of a game object, Unity then makes an instance of that object&#8217;s material then alters the <strong>_DiffuseColor <\/strong>property value and assigns that material instance its own draw call separate from all other objects that use that material. Now whenever that game object changes color it can alter its own material without affecting other game objects.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Shaders are one of the more obscure technologies within the Unity game engine, and while the documentation covers most of the shader language and functions it fails to provide comprehensive techniques that would result in compelling graphics. They&#8217;re core focus appears to be that of treating shaders as a black box with which materials are [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":357,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[21,5],"tags":[],"class_list":["post-355","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code","category-tutorials"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/magiteker.com\/wp-content\/uploads\/2015\/10\/shader_experiment.png?fit=822%2C463&ssl=1","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6MIgq-5J","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/posts\/355","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/comments?post=355"}],"version-history":[{"count":46,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/posts\/355\/revisions"}],"predecessor-version":[{"id":588,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/posts\/355\/revisions\/588"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/media\/357"}],"wp:attachment":[{"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/media?parent=355"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/categories?post=355"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/magiteker.com\/index.php\/wp-json\/wp\/v2\/tags?post=355"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}