Shader authoring/Anatomy of a Shader

From Valve Developer Community
Jump to: navigation, search
Icon-broom.png
This article or section needs to be cleaned up to conform to a higher standard of quality.
For help, see the VDC Editing Help and Wikipedia cleanup process. Also, remember to check for any notes left by the tagger at this article's talk page.

Anatomy Of Shader DLL Code

A shader DLL should contain one .CPP file for each shader. Inside the .CPP file, a set of macros is used to define the structure of the shader. These macros are listed below. For reference, here is a sample shader's code that you can refer to while reading the macros:

#include "BaseVSShader.h"

// Note: you have to run buildshaders.bat to generate these files from the FXC code.
#include "sdk_lightmap_ps20.inc"
#include "sdk_lightmap_vs20.inc"

BEGIN_VS_SHADER( SDK_Lightmap, "Help for SDK_Lightmap" )

	BEGIN_SHADER_PARAMS
		SHADER_PARAM( BUMPMAP, SHADER_PARAM_TYPE_TEXTURE, "shadertest/BaseTexture", "base texture" )
		SHADER_PARAM( BUMPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "frame number for $bumpmap" )
	END_SHADER_PARAMS

	// Set up anything that is necessary to make decisions in SHADER_FALLBACK.
	SHADER_INIT_PARAMS()
	{
		if( !params[BUMPFRAME]->IsDefined() )
		{
			params[BUMPFRAME]->SetIntValue( 0 );
		}
	}

	SHADER_FALLBACK
	{
		return 0;
	}

	// Note: You can create member functions inside the class definition.
	int SomeMemberFunction()
	{
		return 0;
	}

	SHADER_INIT
	{
		LoadTexture( BASETEXTURE );
	}

	SHADER_DRAW
	{
		SHADOW_STATE
		{
			// Enable the texture for base texture and lightmap.
			pShaderShadow->EnableTexture( SHADER_TEXTURE_STAGE0, true );
			pShaderShadow->EnableTexture( SHADER_TEXTURE_STAGE1, true );

			sdk_lightmap_vs20_Static_Index vshIndex;
			pShaderShadow->SetVertexShader( "sdk_lightmap_vs20", vshIndex.GetIndex() );

			sdk_lightmap_ps20_Static_Index pshIndex;
			pShaderShadow->SetPixelShader( "sdk_lightmap_ps20", pshIndex.GetIndex() );

			DefaultFog();
		}
		DYNAMIC_STATE
		{
			BindTexture( SHADER_TEXTURE_STAGE0, BASETEXTURE, FRAME );
			pShaderAPI->BindLightmap( SHADER_TEXTURE_STAGE1 );
		}
		Draw();
	}
END_SHADER
BEGIN_VS_SHADER( [shader name], [help string] ) / END_SHADER

This macro defines the name of the shader, as referenced in .VMT files. It expands to a class definition, so you can create member functions inside.

BEGIN_SHADER_PARAMS / END_SHADER_PARAMS

These macros define the section in which your material parameters are defined. Briefly, the material parameters are the variables that your shader can read out of a .vmt file.

SHADER_PARAM( [param name], [param type], [default value], [help string] )

Each of these defines a parameter in your shader, and the parameter values are specified inside .VMT files. Any code you write in your shader can refer to the values of these parameters (as specified in the .VMT file) by referring to params[param name] (which will be of type IMaterialVar).

There are a number of default shader parameters that are automatically present in any shader. See Default Shader Parameters for a list of these.

For example, you could have a SHADER_PARAM like this:

SHADER_PARAM( LIGHT_COLOR, SHADER_PARAM_TYPE_VEC3, "1 0 0", "This is the directional light color." )

and a .VMT material file like this:

"(your shader name here - whatever was in BEGIN_VS_SHADER)"
{
	"$light_color" "0 0 1"
}

and then you could write params[LIGHT_COLOR]->GetVecValue() anywhere in your shader code to use the color.

See src\public\materialsystem\IMaterialVar.h for the IMaterialVar interface, and see src\public\materialsystem\IMaterialSystem.h - ShaderParamType_t - for a list of the parameter types that are supported.

SHADER_INIT_PARAMS

The code inside this block is called right after the values for the parameters are loaded from the .vmt file. It gives the shader a chance to validate and clamp the incoming parameters, and to set default values for them if needed.

SHADER_FALLBACK

The code inside this block detects what DirectX version the user is running (using g_pHardwareConfig, and based on the DirectX version and what material parameters are specified, the shader can decide to use another shader to render the current material.

This is useful if you have a high-end shader that makes use of the very latest HLSL version. If a user with an older DirectX 7 compatible machine were to try to run your shader, it wouldn't work because their machine couldn't support it. In that case, you would return the name of a "lesser" shader that will run on the person's machine.

Note: Sometimes, a material may go through a chain of SHADER_FALLBACKuntil it finds one that will support it. If all the versions of LightmappedGeneric were compiled into one shader DLL, and a user with a DirectX 6 video card were to use a LightmappedGeneric shader, it would call them in this sequence:

LightmappedGeneric -> LightmappedGeneric_DX8 -> LightmappedGeneric_DX6

SHADER_INIT

The code in this block loads the shader's textures, bumpmaps, and cubemaps, and initializes its shader flags. Briefly, textures can be loaded with LoadTexture, bumpmaps with LoadBumpMap, and cubemaps with LoadCubeMap.

SHADER_DRAW

The code inside the SHADER_DRAW block contains all the state settings.

SHADOW_STATE and DYNAMIC_STATE

These macros always are specified one after the other, and they both are responsible for configuring all the rendering parameters for your shader. See Shader States for more information.

Default Shader Parameters

In addition to the SHADER_PARAM definitions in your shader's C++ file, there are a bunch of parameters that are automatically defined because they are so common. For example, most shaders have a 'main texture' that they use, so there is a shader parameter called BASETEXTURE. The list of default shader parameters is:

Name Parameter Type Default value
COLOR SHADER_PARAM_TYPE_COLOR [1 1 1]
ALPHA SHADER_PARAM_TYPE_FLOAT 1.0
BASETEXTURE SHADER_PARAM_TYPE_TEXTURE shadertest/BaseTexture
FRAME SHADER_PARAM_TYPE_INTEGER 0
BASETEXTURETRANSFORM SHADER_PARAM_TYPE_MATRIX center .5 .5 scale 1 1 rotate 0 translate 0 0