Revision Difference
CustomPostProcessing#546109
<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 BasePostProcess, where you setup all your shader stuff, including the material.
```⤶
public class PostInvert : BasePostProcess⤶
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⤶
{
private Material PostProcessMaterial;
private static PostInvert Current;⤶
⤶
public bool Invert⤶
public InvertPostProcess() : base( "materials/post_invert.vmat" ) { }
⤶
public bool Enabled⤶
{
set => Set("invert", value);
}⤶
⤶
public PostInvert()⤶
{⤶
PostProcessMaterial = Material.Load("materials/post_invert.vmat");⤶
Current = this;⤶
}⤶
⤶
public override void Render()⤶
{⤶
if(PostProcessMaterial is null) return;⤶
Sandbox.Render.Material = PostProcessMaterial;⤶
RenderScreenQuad();⤶
}⤶
⤶
[ClientCmd("post_invert")]⤶
public static void SetValue(bool state)⤶
{⤶
Host.AssertClient();⤶
Current.Invert = state;⤶
set => SetCombo( "D_ENABLED", value );
}
}
```⤶
⤶
```⤶
<note>
The attribute "invert" in this case is a Dynamic expression I set in the material editor. ⤶
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 PostInvert());
var postInvert = PostProcess.Get<PostInvert>();
PostProcess.Add(new InvertPostProcess());
var postInvert = PostProcess.Get<InvertPostProcess>();
postInvert.Invert = 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>
<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.
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
{
CompileTargets = ( IS_SM_50 && ( PC || VULKAN ) );
Description = "Base Post Processing Shader";
CompileTargets = ( IS_SM_50 && ( PC || VULKAN ) );
Description = "Example post processing shader";
}
⤶
//=========================================================================================================================⤶
⤶
FEATURES⤶
⤶
MODES⤶
{
#include "common/features.hlsl"⤶
Default();⤶
VrForward();⤶
}
⤶
//=========================================================================================================================⤶
⤶
MODES⤶
⤶
FEATURES⤶
{
VrForward();⤶
Default();⤶
}
⤶
//=========================================================================================================================⤶
COMMON
{
#include "system.fxc"⤶
#include "common.fxc"⤶
#include "postprocess/shared.hlsl"⤶
}
⤶
//=========================================================================================================================⤶
struct VertexInput
{
float3 vPositionOs : POSITION < Semantic( PosXyz ); >;
float2 vTexCoord : TEXCOORD0 < Semantic( LowPrecisionUv ); >;
float2 vTexCoord : TEXCOORD0 < Semantic( LowPrecisionUv ); >;
};
⤶
//=========================================================================================================================⤶
struct PixelInput
{
float4 vPositionPs : SV_Position;⤶
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
{
struct PixelOutput⤶
#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 vColor : SV_Target0;
};
⤶
// grab the frame buffer texture⤶
CreateTexture2D( g_FrameBuffer ) < Attribute( "ColorBuffer" ); SrgbRead( true ); Filter( MIN_MAG_LINEAR_MIP_POINT ); AddressU( MIRROR ); AddressV( MIRROR ); >;⤶
⤶
bool g_vInvert < UiGroup("Invert"); UiType(CheckBox); Default(0); >;⤶
PixelOutput MainPs( PixelInput i )
{
PixelOutput o;
float2 uv = i.vTexCoord.xy - g_vViewportOffset.xy / g_vRenderTargetSize; // uv from 0,0 in the top left to 1,1 in the bottom right⤶
⤶
float4 color = Tex2D(g_FrameBuffer, uv.xy).rgba; // grab color from frame texture⤶
if(g_vInvert)⤶
color = 1 - color; // invert color⤶
⤶
o.vColor = color;
// 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;⤶
#else⤶
o.vColor.rgb = vFrameBufferColor;⤶
#endif⤶
o.vColor.a = 1.0f;⤶
return o;
}
}
```
This is a basic post processing shader that inverts the screen color.
<upload src="3c1ff/8d9a61ea993d2f1.png" size="5219945" name="sbox-dev_oXb7vCc1Z3.png" />