S&box Wiki

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" />