CCSVhsDistort.cs

Post-process effect component that simulates VHS vertical scrolling and horizontal tracking distortion. It exposes tunable properties (warp size, speed, distortion, chromatic aberration, static, deinterlace skew), computes weighted values for blending, sets shader attributes, loads a shader material and issues a blit to apply the effect.

Native Interop
using Sandbox;
using System;


using Sandbox;
using Sandbox.Rendering;

/// <summary>
/// Simulation of the vertical scrolling - horizontal "tracking" effect on old VHS tapes.
/// </summary>
[Title( "VHS Distortion" )]
[Category( "Post Processing" )]
[Icon( "dehaze" )]
public sealed class CCSVHSD : BasePostProcess<CCSVHSD>
{
    /// <summary>
    /// How big are the distortion lines.
    /// </summary>
    [Property, Title("Warp Size"), Range(0f, 20.0f)]
    public float warp_size { get; set; } = 12.0f;

    /// <summary>
    /// Enhance the distorted areas.
    /// </summary>
    [Property, Title("Warp Distortion Multiplier"), Range(-0.5f, 0.5f)]
    public float warp_distort { get; set; } = 0.05f;

    /// <summary>
    /// How fast the distorted areas scroll.
    /// </summary>
    [Property, Title("Warp Speed"), Range(-30.0f, 30.0f)]
    public float warp_speed { get; set; } = 6.0f;

    /// <summary>
    /// number of smaller lines to chop the main warp lines into.
    /// </summary>
    [Property, Title("Warp Variation"), Range(-30.0f, 30.0f)]
    public float warp_random { get; set; } = 1.5f;

    /// <summary>
    /// How fast the distorted areas scroll.
    /// </summary>
    [Property, Title("Chromatic Abberation"), Range(-0.25f, 0.25f)]
    public float ca { get; set; } = 0.02f;

    /// <summary>
    /// Amount of static that each warp line has
    /// </summary>
    [Property, Title("Static Amount"), Range(0.0f, 1.0f)]
    public float Static { get; set; } = 0.5f;

    /// <summary>
    /// high frequency horizontal ripple distortion effect on the entire image.
    /// </summary>
    [Property, Title("DeInterlace Skew"), Range(0.0f, 20.0f)]
    public float dSkew { get; set; } = 0.5f;

    public override void Render()
    {
        // Числовые значения через GetWeighted — поддерживает блендинг в PostProcess Volume
        float warpSizeW = GetWeighted(x => x.warp_size);
        float warpDistortW = GetWeighted(x => x.warp_distort);
        float warpSpeedW = GetWeighted(x => x.warp_speed);
        float warpRandomW = GetWeighted(x => x.warp_random);
        float caW = GetWeighted(x => x.ca);
        float staticW = GetWeighted(x => x.Static);
        float dSkewW = GetWeighted(x => x.dSkew);

        // Передаем значения в шейдер
        Attributes.Set("warp_size", warpSizeW);
        Attributes.Set("warp_speed", warpSpeedW);
        Attributes.Set("warp_random", warpRandomW);
        Attributes.Set("warp_distort", warpDistortW);
        Attributes.Set("ca", caW);
        Attributes.Set("Static", staticW);
        Attributes.Set("dSkew", dSkewW);

        // Загружаем материал с проверкой на null
        var material = Material.FromShader("postprocess/ccs_vhs_distort.shader");
        if (material == null)
        {
            Log.Warning("CCSVHSD: Material 'materials/postprocess/ccs_vhsd.vmat' not found!");
            return;
        }

        // Применяем эффект через современный Blit API
        // Приоритет 9000 перенесен из оригинального кода
        var blit = BlitMode.WithBackbuffer(material, Stage.AfterPostProcess, 9000, true);
        Blit(blit, "CCSVHSD");
    }
}