menu_bookDocumentation

BasePostProcess: Custom Post-Processing with GetWeighted, BlitMode, and PostProcessVolume Blending

calendar_today May 4, 2026 schedule ~1 min read person patrickjr verified 50

BasePostProcess<T>: Custom Post-Processing Effects with Volume Blending

BasePostProcess<T> is the current (non-obsolete) base class for post-processing effects in s&box. It replaces the older PostProcess class.

Creating a Custom Post-Process Effect

CSHARP
public class MyColorGrade : BasePostProcess<MyColorGrade>, Component.ExecuteInEditor
{
    [Property] public Color Tint { get; set; } = Color.White;
    [Property, Range( 0, 1 )] public float Saturation { get; set; } = 1.0f;

    Material _material;

    public override void Render()
    {
        _material ??= Material.Load( "materials/postprocess/my_grade.vmat" );

        Attributes.Set( "g_flSaturation", GetWeighted( x => x.Saturation, 1.0f ) );
        Attributes.Set( "g_vTint", GetWeighted( x => x.Tint, Color.White ) );

        Blit( BlitMode.Simple( _material, Rendering.Stage.AfterPostProcess, 100 ), "MyColorGrade" );
    }
}

GetWeighted<U>

GetWeighted blends values from all active PostProcessVolume instances that contain this effect type, weighted by their BlendWeight and distance:
CSHARP
// Blend a float across all volumes
float saturation = GetWeighted( x => x.Saturation, defaultVal: 1.0f );

// Blend a Color
Color tint = GetWeighted( x => x.Tint, Color.White );

// Only lerp between volumes (don't lerp from default)
float value = GetWeighted( x => x.Value, 0f, onlyLerpBetweenVolumes: true );

BlitMode Options

CSHARP
// Simple blit at a render stage
Blit( BlitMode.Simple( material, Stage.AfterPostProcess, order: 100 ), "DebugName" );

// Blit with backbuffer copy (for effects that read the current frame)
Blit( BlitMode.WithBackbuffer( material, Stage.AfterPostProcess, order: 100 ), "DebugName" );

// Blit with backbuffer + mipmaps (for blurry reflections etc)
Blit( BlitMode.WithBackbuffer( material, Stage.AfterPostProcess, order: 100, mip: true ), "DebugName" );

Render Stages

CSHARP
Rendering.Stage.AfterPostProcess  // after all built-in post-process
Rendering.Stage.AfterTransparent  // after transparent objects
Rendering.Stage.AfterUI           // after UI rendering

PostProcessVolume Integration

Add a PostProcessVolume component alongside your effect to control blending by volume:

CSHARP
// PostProcessVolume properties
volume.Priority = 0;          // higher priority overrides lower
volume.BlendWeight = 1.0f;    // [0..1] overall weight
volume.BlendDistance = 50f;   // blend distance from volume edge

The PostProcessSystem collects all active volumes, sorts by priority, and passes weighted components to BasePostProcess.Render() via context.Components.

Was this helpful?