OMREdgeCuePostProcess.cs
using Sandbox;
using Sandbox.Rendering;
using System;
/// <summary>
/// Runtime-only native S&box post-process bridge for OMR world geometry edge cues.
///
/// OMRVisualFoundation creates/configures this component on the authored gameplay
/// camera while the scene is playing. Because the later OMR viewmodel composite
/// camera has post-processing disabled and does not own this component, the pass
/// remains world-only.
/// </summary>
[Title( "OMR Edge Cue Post Process" )]
[Category( "One More Round/Internal" )]
public sealed class OMREdgeCuePostProcess : BasePostProcess<OMREdgeCuePostProcess>
{
private const string ShaderPath = "shaders/omr_edge_cues.shader";
private const int RenderOrder = 900;
public float Strength { get; set; } = 0.16f;
public float DepthStrength { get; set; } = 1f;
public float NormalStrength { get; set; } = 0.7f;
public float DepthThreshold { get; set; } = 0.018f;
public float NormalThreshold { get; set; } = 0.08f;
public float SampleRadius { get; set; } = 1f;
public float FadeStart { get; set; } = 450f;
public float FadeEnd { get; set; } = 1450f;
public int DebugMode { get; set; } = 0;
private Material _material;
private bool _materialFailureLogged;
public override void Render()
{
bool debugActive = DebugMode != 0;
if ( Strength <= 0.0001f && !debugActive )
return;
if ( _material is null || !_material.IsValid )
{
_material = Material.FromShader( ShaderPath );
if ( _material is null || !_material.IsValid )
{
if ( !_materialFailureLogged )
{
_materialFailureLogged = true;
Log.Warning( $"[OMR VISUAL] Could not create edge-cue post-process material from '{ShaderPath}'." );
}
return;
}
_materialFailureLogged = false;
}
Attributes.Set( "OMREdgeStrength", MathX.Clamp( Strength, 0f, 1f ) );
Attributes.Set( "OMREdgeDepthStrength", MathX.Clamp( DepthStrength, 0f, 2f ) );
Attributes.Set( "OMREdgeNormalStrength", MathX.Clamp( NormalStrength, 0f, 2f ) );
Attributes.Set( "OMREdgeDepthThreshold", MathX.Clamp( DepthThreshold, 0.001f, 0.25f ) );
Attributes.Set( "OMREdgeNormalThreshold", MathX.Clamp( NormalThreshold, 0.001f, 1f ) );
Attributes.Set( "OMREdgeSampleRadius", MathX.Clamp( SampleRadius, 1f, 3f ) );
Attributes.Set( "OMREdgeFadeStart", MathF.Max( 0f, FadeStart ) );
Attributes.Set( "OMREdgeFadeEnd", MathF.Max( FadeStart + 1f, FadeEnd ) );
Attributes.Set( "OMREdgeDebugMode", (float)DebugMode );
// Use S&box's supported post-process path. BeforePostProcess keeps the
// world depth pyramid / G-buffer available and WithBackbuffer provides
// the current world color as the shader's ColorBuffer input.
var blit = BlitMode.WithBackbuffer(
_material,
Stage.BeforePostProcess,
RenderOrder,
false
);
Blit( blit, "OMR World Edge Cues" );
}
}