Shaders are an overwhelming area of programming that many people wish they could do, but very few dare to venture into due to their complexity. Unfortunately there is a lack of tutorials around the Half Life 2 community in regards to shader editing. This tutorial is designed to give you an introduction to the basic concept of Shaders and how to configure your development environment to compile them. There are also several other tutorials avaliable which will start you on development of a simple post-process shader, and an object shader for Source.
[page=What is a shader?]
You may have heard a few buzzwords flying around if you’ve ever tried to do some research or development with shaders. Things like programmable pipeline, fragment shader and fixed-function. So what does it all mean, and how does it relate to shaders?
Modern video cards are much different to ones that were around several years ago. Video cards have what we refer nowadays to as ‘programmable pipelines’ – that is, the output that the video card produces can be modified by a program, known as a ‘shader’. Older video cards had a ‘fixed-function pipeline’, which means that output could not be customized by shaders and developers were limited with how they could work and manipulate the images that were rendered.
Shaders are essentially made up of two parts: Pixel Shaders (sometimes referred to as fragment shaders), and Vertex Shaders. The word ‘Shaders’ and ‘Programs’ are interchangeable – some resources may refer to them as Pixel Programs and Vertex Programs.
As you can probably tell from the names, a Pixel Shader has the ability to modify each pixel that is rendered onto the screen, and a Vertex Shader has the ability to modify each vertex that is rendered onto the screen. In DirectX 9, each of these shaders do different things, and in most cases (not all), both of them are required in order to have a fully functional shader.
There are several different languages that are used for shader development, such as HLSL, GLSL and CG. Source uses HLSL (High Level Shader Language), which is DirectX’s shader language
Shaders come in several different ‘versions’ if you will – think of it the same as Visual C++. First there was VC++ 6, then VC++ .NET 2002, VC++ .NET 2003 and now, VC++ .NET 2005. Shaders are the same sort of thing, except they are called Shader Models (generally abbreviated to SM). There are several different shader models, including 1.1, 1.4, 2.0, 2.0a, 2.0b and the most recent 3.0. Each shader model has different features in their code – for example, SM3.0 supports floating point values where no other shader model does.
These tutorials will only deal with SM2.0, with fallbacks to SM1.4.
[page=Source and Shaders]
The Source engine is really the first game engine that has given modders the ability to create their own shaders for use in their mods. While several other engines do support it (such as CryEngine and Doom 3), the features and methodology in these engines regarding shaders are lackluster at best.
Source has two types of shaders, which are generally referred to as Post-Process and Per-Object shaders.
Post-Process, as the name implies, processes each frame before its finally rendered onto the screen. Common Post-Process effects include Bloom, Motion Blur, Depth of Field blur and many other simple manipulation techniques (sepia, desaturation and emboss to name a select few).
Per-Object shaders are shaders that are applied to individual objects. If you’re experienced with creating materials with Source, you’ve no doubt come across the LightmappedGeneric or UnlitGeneric types when creating a VMT file. These are Per-Object shaders.
In general, post-process shaders are much easier to create than per-object shaders. This guide will cover the creation of both types.
Shaders for Source are made up of four separate components:
The Pixel Shader, as was mentioned earlier;
The Vertex Shader, as was mentioned earlier;
A Shader DLL, which holds information about the shader and how a VMT file references it;
The client DLL, which is occasionally needed for rendering techniques that can’t be controlled in any other way.
Before you start getting into the programming, there are several things that you need to do to set up your environment for shader development.
The SDK’s shaders are located in src/materialsystem/stdshaders. This is where you will spend most of your time working.
Firstly, you will need to download a copy of Perl and the DirectX SDK. Both of these are required for successful shader compiling.
When Perl and the DirectX SDK are installed, several small things are required in order to make the shaders compile properly.
You will need to modify your ‘path’ to include the directories where Perl and the DirectX SDK. To do this, right click on My Computer, select the Advanced tab, and click the Environment Variable button down the bottom. In the bottom box (System Variables), find the ‘Path’ entry and edit it.
Each entry in this is separated by a semicolon (;). Simple add the paths to both the DirectX utilities/bin/x86 directory, and the directory that contains perl.exe
You may also need to copy nmake.exe to your materialsystem\stdshaders directory. nmake is located in the location you installed Visual Studio .NET 2003 (for me, C:\program files\Microsoft Visual Studio .NET 2003) in the Vc7\bin subdirectory. Alternately, you could also set an entry in your path for this.
The alternative is to set up a common directory for you to place all your utilities in. I’m set up so all my tools (fxc.exe, vsa.exe, psa.exe, nmake.exe, perl.exe and perl58.dll) are all in E:\basecode\src\devtools. I recommend this method, its far easier ?
As such, end of my entry looks like this:
If you don’t wish to download the entirety of the SDK, you can download the tools that are needed at my website (http://www.wraiyth.com). You will still need to set a path (put them in your src directory) to them in order for the SDK to work correctly.
Finally, it seems that in the latest update, Valve still have not provided a fix for spaces in pathnames. Unfortunately there does not seem to be a fix for this as of yet. There was a fix available at Developer.valvesoftware.com however I believe that is outdated.
The temporary method to use it to relocate your source directory (and mod directory) to a location that doesn’t contain any spaces.
As we know, shaders are made up of several different things: pixel shaders, vertex shaders, shader DLL and occasionally a component in the client DLL.
With Source, pixel shaders and vertex shaders are stored in separate files with the extension .FXC. Each file before the extentsion also has a little tag on it, such as _ps20. This little tag tells the shader compiler the type of shader it is, and therefore what compiler settings to use. The _ps part tells the compiler that this file is a pixel shader, and the 20 part tells it that we’re compiling for SM2.0.
Valid tags include vs14, vs20, ps14, ps20 and ps20b. You can also use 11 (indicating SM1.1) but we won’t go into that in this guide.
There is also a .psh and .vsh extension that can be used for shaders, but they are only used for assembly shaders (we don’t really need to go into them when we have HLSL at our disposal).
So thats it for this tutorial. This tutorial was a tad boring - it covered the basic theory and configuration you need to do in order to delve right into the development. You can take alook at Simple Post-Process Shader, which is where the good stuff starts.
Tutorial originally posted on Wraiyths Website