Files
sbox-public/engine/Sandbox.Engine/Scene/Components/PostProcessing/BasePostProcess.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

165 lines
4.3 KiB
C#

using Sandbox.MovieMaker;
using Sandbox.Rendering;
namespace Sandbox;
/// <summary>
/// The base class for all post process effects.
/// </summary>
public abstract class BasePostProcess : Component, Component.ExecuteInEditor, Component.DontExecuteOnServer
{
PostProcessContext? _currentContext;
internal PostProcessContext context
{
get
{
if ( !_currentContext.HasValue ) throw new System.Exception( "Should only be called during build" );
return _currentContext.Value;
}
}
/// <summary>
/// The camera we're being applied to. This is only valid during the Render call.
/// </summary>
protected CameraComponent Camera => context.Camera;
/// <summary>
/// The default attributes for this post process. This will be used by helper functions like Blit.
/// </summary>
protected readonly RenderAttributes Attributes = new();
internal void Build( PostProcessContext ctx )
{
_currentContext = ctx;
try
{
// always cleared before build
Attributes.Clear();
Render();
}
finally
{
_currentContext = default;
}
}
/// <summary>
/// Override in your implementation to do your rendering
/// </summary>
public abstract void Render();
public ref struct BlitMode
{
/// <summary>
/// The material to use for the blit.
/// </summary>
public Material Material;
/// <summary>
/// We'll use this instead of BasePostProcess.Attributes if set.
/// </summary>
public RenderAttributes Attributes;
/// <summary>
/// Where to place this in the render pipeline
/// </summary>
public Stage RenderStage;
/// <summary>
/// The order within the stage. Lower numbers get rendered first.
/// </summary>
public int Order;
/// <summary>
/// If true, the backbuffer will be copied to a texture called "ColorBuffer" before the blit.
/// </summary>
public bool WantsBackbuffer;
/// <summary>
/// If both WantsBackbufferCopy and this is true the backbuffer will be mipped after being copied.
/// </summary>
public bool WantsBackbufferMips;
/// <summary>
/// Shortcut to build a simple blit mode
/// </summary>
public static BlitMode Simple( Material m, Stage stage, int order = 0 ) => new BlitMode { Material = m, RenderStage = stage, Order = order };
/// <summary>
/// Shortcut to build a blit mode that copies the backbuffer first
/// </summary>
public static BlitMode WithBackbuffer( Material m, Stage stage, int order = 0, bool mip = false ) => new BlitMode { Material = m, RenderStage = stage, Order = order, WantsBackbuffer = true, WantsBackbufferMips = true };
}
/// <summary>
/// Helper to do a blit with the current camera's post process
/// </summary>
protected void Blit( BlitMode blit, string debugName )
{
if ( !blit.Material.IsValid() ) return;
CommandList cl = new CommandList( blit.Material.Name );
if ( blit.WantsBackbuffer )
{
cl.Attributes.GrabFrameTexture( "ColorBuffer", blit.WantsBackbufferMips );
}
cl.Blit( blit.Material, blit.Attributes ?? Attributes );
InsertCommandList( cl, blit.RenderStage, blit.Order, debugName );
}
/// <summary>
/// Helper to do a blit with the current camera's post process
/// </summary>
protected void BlitSimple( Material shader, Stage stage, int order, string debugName )
{
Blit( BlitMode.Simple( shader, stage, order ), debugName );
}
/// <summary>
/// Helper to add a command list to the current camera's post process
/// </summary>
protected void InsertCommandList( CommandList cl, Sandbox.Rendering.Stage stage, int order, string debugName )
{
var layer = context.Camera.PostProcess.CreateLayer( stage );
layer.Order = order;
layer.CommandList = cl;
layer.Name = debugName;
}
}
/// <summary>
/// Like BasePostProcess but enables access to helper methods for accessing from multiple instances using GetWeighted.
/// </summary>
public abstract class BasePostProcess<T> : BasePostProcess where T : BasePostProcess
{
/// <summary>
/// Helper to get a weighted value from all active post process volumes
/// </summary>
protected U GetWeighted<U>( System.Func<T, U> value, U defaultVal = default, bool onlyLerpBetweenVolumes = false )
{
U v = defaultVal;
var lerper = Interpolator.GetDefault<U>();
int i = 0;
foreach ( var e in context.Components )
{
var target = value( (T)e.Effect );
v = lerper.Interpolate( v, target, e.Weight );
if ( onlyLerpBetweenVolumes && i == 0 )
v = target;
i++;
}
return v;
}
}