Revision Difference
CustomPostProcessing#547620
<cat>Code.Shader</cat>
<title>Custom Post-Processing</title>
# Setting up your material and rendering it
From the C# side you'll need to do two things. I'll be using a simple color invert shader for this example that you can turn on and off with a ClientCmd.
1. Setup a class for your PostProcessing based on MaterialPostProcess, where you set up all your shader stuff, including the material.
```cs
public class InvertPostProcess : MaterialPostProcess
{
public InvertPostProcess() : base( "materials/post_invert.vmat" ) { }
public bool Enabled
{
set => Attributes.SetCombo( "D_ENABLED", value );
}
}
```
<note>
The DynamicCombo "D_ENABLED" is defined in the example shader below. You can use `Set` to set any attributes. Eg: `float flMyAttribute< Attribute("MyCoolAttribute"); >;` and you'd set it with `Set( "MyCoolAttribute", 1337.0f);`
</note>
2. Initialize that PostProcessing class in your Game class.
```cs
public CustomGame()
{
if(IsClient)
{
InitPostProcess();
}
}
public void InitPostProcess()
{
PostProcess.Add(new InvertPostProcess());
var postInvert = PostProcess.Get<InvertPostProcess>();
postInvert.Enabled = true; // set it to invert colors by default
}
```
<note>You can also directly load a post-processing material if you don't have any attributes you want to set from C#</note>
```
PostProcess.Add( new MaterialPostProcess( "materials/post_invert.vmat" ) );
```
This is a basic example using the post-processing material `post_invert.vmat`.
That's all we need to do from the C# side to get our post-processing material to draw, now we just need to actually make the shader.
# Basic Post Processing Shader
```
HEADER
{
Description = "Example post processing shader";
}
MODES
{
Default();
VrForward();
}
FEATURES
{
}
COMMON
{
#include "postprocess/shared.hlsl"
}
struct VertexInput
{
float3 vPositionOs : POSITION < Semantic( PosXyz ); >;
float2 vTexCoord : TEXCOORD0 < Semantic( LowPrecisionUv ); >;
};
struct PixelInput
{
float2 vTexCoord : TEXCOORD0;
// VS only
#if ( PROGRAM == VFX_PROGRAM_VS )
float4 vPositionPs : SV_Position;
#endif
// PS only
#if ( ( PROGRAM == VFX_PROGRAM_PS ) )
float4 vPositionSs : SV_ScreenPosition;
#endif
};
VS
{
PixelInput MainVs( VertexInput i )
{
PixelInput o;
o.vPositionPs = float4(i.vPositionOs.xyz, 1.0f);
o.vTexCoord = i.vTexCoord;
return o;
}
}
PS
{
#include "postprocess/common.hlsl"
RenderState( DepthWriteEnable, false );
RenderState( DepthEnable, false );
CreateTexture2D( g_tColorBuffer ) < Attribute( "ColorBuffer" ); SrgbRead( true ); Filter( MIN_MAG_LINEAR_MIP_POINT ); AddressU( MIRROR ); AddressV( MIRROR ); >;
CreateTexture2D( g_tDepthBuffer ) < Attribute( "DepthBuffer" ); SrgbRead( false ); Filter( MIN_MAG_MIP_POINT ); AddressU( CLAMP ); AddressV( CLAMP ); >;
DynamicCombo( D_ENABLED, 0..1, Sys( PC ) );
struct PixelOutput⤶
float4 MainPs( PixelInput i ) : SV_Target0⤶
{
float4 vColor : SV_Target0;⤶
};⤶
⤶
PixelOutput MainPs( PixelInput i )⤶
{⤶
PixelOutput o;⤶
// Get the current screen texture coordinates
float2 vScreenUv = i.vTexCoord.xy - g_vViewportOffset.xy / g_vRenderTargetSize;
// Get the current color at a given pixel
float3 vFrameBufferColor = Tex2D( g_tColorBuffer, vScreenUv.xy ).rgb;
#if D_ENABLED
// Invert the color and write it to our output
o.vColor.rgb = 1.0f - vFrameBufferColor;
float4 vColor = float4( 1.0f - vFrameBufferColor, 1.0f );
#else
o.vColor.rgb = vFrameBufferColor;
float4 vColor = float4( vFrameBufferColor, 1.0f );
#endif
o.vColor.a = 1.0f;
return o;⤶
return vColor;
}
}
```
This is a basic post processing shader that inverts the screen color.
<upload src="3c1ff/8d9a61ea993d2f1.png" size="5219945" name="sbox-dev_oXb7vCc1Z3.png" />