<?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: Kirill Dmitrievich</title>
    <description>The latest articles on DEV Community by Kirill Dmitrievich (@untodesu).</description>
    <link>https://dev.to/untodesu</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%2F523053%2F7feb6118-8af1-4d14-9681-7e99bd345eff.png</url>
      <title>DEV Community: Kirill Dmitrievich</title>
      <link>https://dev.to/untodesu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/untodesu"/>
    <language>en</language>
    <item>
      <title>Source Engine materials</title>
      <dc:creator>Kirill Dmitrievich</dc:creator>
      <pubDate>Thu, 03 Dec 2020 09:41:48 +0000</pubDate>
      <link>https://dev.to/untodesu/source-engine-materials-2h34</link>
      <guid>https://dev.to/untodesu/source-engine-materials-2h34</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy1jf3oiqxnn4o8axzbtj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy1jf3oiqxnn4o8axzbtj.png" alt="Sorse" width="800" height="451"&gt;&lt;/a&gt;&lt;br&gt;
I can see a lack of Source Engine articles nowadays and some people asked me to write an article explaining how materials work, so...&lt;br&gt;
This article assumes you know C++ and shaders at certain level.&lt;/p&gt;
&lt;h2&gt;
  
  
  Materials
&lt;/h2&gt;

&lt;p&gt;What is a material in Source Engine?&lt;br&gt;
The simplest answer would be a bunch of abstraction layers on &lt;a href="https://developer.valvesoftware.com/wiki/KeyValues" rel="noopener noreferrer"&gt;KeyValues&lt;/a&gt; that is used as a base for all rendering activity.&lt;br&gt;
Materials are stored on disk and being loaded into the memory on demand (e.g. loading a map, pre-caching a model) or pre-cached as a client screen space effects.&lt;/p&gt;
&lt;h4&gt;
  
  
  Surface properties
&lt;/h4&gt;

&lt;p&gt;Materials may have a special &lt;a href="https://developer.valvesoftware.com/wiki/$surfaceprop" rel="noopener noreferrer"&gt;variable&lt;/a&gt; that is being used by the physics and the sound to determine how does this material behave in relation with other objects in the world.&lt;/p&gt;
&lt;h4&gt;
  
  
  Relativity to the shaders
&lt;/h4&gt;

&lt;p&gt;Each and every material basically is a recursive key-value pair where the key contains a shader's name and the value contains &lt;em&gt;material variables&lt;/em&gt; to use in the C++ part of the shader.&lt;br&gt;
To get a better understanding how it works, let's look at a simple material example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This is a shader's name.&lt;/span&gt;
&lt;span class="c1"&gt;// This means that we will use a shader named LightmappedGeneric&lt;/span&gt;
&lt;span class="c1"&gt;// in order to get a model to be shaded by a pre-baked lightmap&lt;/span&gt;
&lt;span class="n"&gt;LightmappedGeneric&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This is called a material variable, a key-value pair&lt;/span&gt;
    &lt;span class="c1"&gt;// that is declared inside C++ code and being used by it in&lt;/span&gt;
    &lt;span class="c1"&gt;// order to modify shader's behaviour.&lt;/span&gt;
    &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;basetexture&lt;/span&gt; &lt;span class="s"&gt;"props/citymap001"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Shaders
&lt;/h2&gt;

&lt;h4&gt;
  
  
  HLSL
&lt;/h4&gt;

&lt;p&gt;A shader program is a program in the first place, therefore it has to be compiled. Source uses FXC (DXC's older brother) to pre-compile shaders.&lt;br&gt;
There's only two shaders you would use in Source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A vertex shader. This shader contains some code that does all that matrix math allowing you to see a 3D picture on a 2D screen. The shader's entry point is called for each vertex.&lt;/li&gt;
&lt;li&gt;A pixel shader. This shader contains some code that affects the actual appearance of a vertex: its color, transparency, etc. The shader's entry point is called for each pixel of a render target.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  C++
&lt;/h4&gt;

&lt;p&gt;Any program should be glued to the material system so both the game and &lt;a href="https://developer.valvesoftware.com/wiki/Valve_Hammer_Editor" rel="noopener noreferrer"&gt;Hammer Editor&lt;/a&gt; draw materials correctly. Each shader is defined in a separate source code file due to some insanity going on with macros. Default shaders such as &lt;code&gt;LightmappedGeneric&lt;/code&gt; "live" in the &lt;code&gt;stdshader_dx9.dll&lt;/code&gt; module while the game-defined shaders "live" in the &lt;code&gt;game_shader_dx9.dll&lt;/code&gt; module.&lt;br&gt;
I will keep the shader's C++ code away from this article because this article attempts to explain how the material system works in general and not how to make your own shader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Textures
&lt;/h2&gt;

&lt;p&gt;Like the shaders, textures are also defined by a string identifier and can be re-loaded like materials.&lt;br&gt;
Textures are stored on disk in a format called VTF (stands for Valve Texture Format) and being loaded whenever the material system decides to.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4fhsk5xwdyyilgci36z0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4fhsk5xwdyyilgci36z0.png" alt="Texture list utility" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Render targets
&lt;/h4&gt;

&lt;p&gt;Render targets (or framebuffers) in Source are stored in the same way as regular textures are. The main difference is the naming convention (the &lt;code&gt;_rt_&lt;/code&gt; prefix for all RTs) and a flag indicating that the texture is actually a render target.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawing a mesh
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5gojne6l6gjeparj8okg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5gojne6l6gjeparj8okg.jpg" alt="Oh yeah it's all coming together!" width="680" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  CViewSetup
&lt;/h4&gt;

&lt;p&gt;The renderer uses a special thing to set up the view and projection matrices; this thing is called a ViewSetup and contains basically all the information required to generate a matrix procedurally: frame size, FOV, camera position, view angles, etc.&lt;br&gt;
The views are stored in the stack, allowing programmer to define their own views without affecting previously set views.&lt;/p&gt;

&lt;h4&gt;
  
  
  Game developer's view
&lt;/h4&gt;

&lt;p&gt;To draw something, game developer just calls a bunch of rendering context methods to prepare, draw, and then return the renderer to its previous state. The Source SDK code (basically the Half-Life 2 and Episodic source code) contains some functions that are made to simplify screen-space effect drawing process: those functions do almost everything leaving you only to find a material and pass it to the function.&lt;/p&gt;

&lt;h4&gt;
  
  
  Engine developer's view
&lt;/h4&gt;

&lt;p&gt;When the drawing call is being invoked, the renderer firstly searches for the shader by the name retrieved from the material.&lt;br&gt;
If the shader exists, the shader draw part is being invoked. In this part shader pre-caches HLSL binaries if required, parses some material variables and fills the shader constants and samplers with the parsed data, then binds the HLSL binaries.&lt;br&gt;
Finally, the renderer draw a mesh using the bound shader.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvf54e3quh0aicvo1tl0z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvf54e3quh0aicvo1tl0z.jpg" alt="A diagram" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you have learned something new about how does Source Engine renders stuff. In the future, I would like to write an article about actually making a post-processing shader for a game.&lt;/p&gt;

&lt;h4&gt;
  
  
  Useful links
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Valve Developer Community (VDC), (&lt;a href="https://developer.valvesoftware.com/wiki/Main_Page" rel="noopener noreferrer"&gt;click&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Source SDK 2013 code on GitHub (&lt;a href="https://github.com/ValveSoftware/source-sdk-2013" rel="noopener noreferrer"&gt;click&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;My Source 2013 SP mod source code (&lt;a href="https://github.com/undbsd/refraction" rel="noopener noreferrer"&gt;click&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Corrections
&lt;/h2&gt;

&lt;p&gt;After writing this article and working on shaders for a while I just suddenly realized that C++ part of shaders is not actually bound with "shader" definition: that's all just a pipeline of a data-driven renderer!&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>cpp</category>
      <category>sourceengine</category>
      <category>hlsl</category>
    </item>
  </channel>
</rss>
