WorkInProgress/ParticleLineRenderer.cs
namespace Sandbox;
/// <summary>
/// Renders particles as 2D sprites
/// </summary>
[Title( "Particle Line Renderer" )]
[Category( "Particles" )]
[Icon( "favorite" )]
public sealed class ParticleLineRenderer : ParticleRenderer, Component.ExecuteInEditor
{
SceneLineObject _so;
[Property] public Texture Texture { get; set; } = Texture.White;
[Property, Range( 0, 50 )] public float DepthFeather { get; set; } = 0.0f;
[Property, Range( 0, 1 )] public float FogStrength { get; set; } = 1.0f;
[Property, Range( 0, 2 )] public float Scale { get; set; } = 1.0f;
[Property] public bool Additive { get; set; }
[Property] public bool Shadows { get; set; }
/// <summary>
/// If opaque there's no need to sort particles, because they will write to
/// the depth buffer during the opaque pass.
/// </summary>
[Property] public bool Opaque { get; set; }
[Group( "Spline" )]
[Property, Range( 1, 32 )] public int SplineInterpolation { get; set; }
[Group( "Spline" )]
[Property, Range( -1, 1 )] public float SplineTension { get; set; }
[Group( "Spline" )]
[Property, Range( -1, 1 )] public float SplineContinuity { get; set; }
[Group( "Spline" )]
[Property, Range( -1, 1 )] public float SplineBias { get; set; }
protected override void OnAwake()
{
Tags.Add( "particles" );
base.OnAwake();
}
protected override void OnEnabled()
{
_so = new SceneLineObject( Scene.SceneWorld );
_so.Transform = WorldTransform;
_so.Tags.SetFrom( Tags );
}
protected override void DrawGizmos()
{
if ( _so.IsValid() )
{
// Gizmo.Draw.LineBBox( _so.LocalBounds );
}
}
protected override void OnDisabled()
{
_so?.Delete();
_so = null;
}
protected override void OnTagsChanged()
{
_so?.Tags.SetFrom( Tags );
}
protected override void OnPreRender()
{
if ( !_so.IsValid() ) return;
if ( !Components.TryGet( out ParticleEffect effect ) || effect.Particles.Count == 0 )
{
_so.RenderingEnabled = false;
_so.Clear();
return;
}
var viewerPosition = Scene.Camera?.WorldPosition ?? Vector3.Zero;
_so.RenderingEnabled = true;
_so.Transform = WorldTransform;
//_so.Material = Material.FromShader( "shaders/sprite.shader" );
_so.Flags.CastShadows = Shadows && !Additive;
// _so.Texture = Texture;
// if ( Additive ) _so.Attributes.SetCombo( "D_BLEND", 1 );
// else _so.Attributes.SetCombo( "D_BLEND", 0 );
// _so.Attributes.SetCombo( "D_OPAQUE", Opaque ? 1 : 0 );
// if ( MotionBlur )
// {
// _so.Attributes.Set( "g_MotionBlur", new Vector4( LeadingTrail ? 2 : 1, BlurAmount.Remap( 0, 1, 0, 6, false ), BlurSpacing.Remap( 0, 1, 0, 1, false ), BlurOpacity ) );
// }
// else
// {
// _so.Attributes.Set( "g_MotionBlur", new Vector4( 0, 0, 0, 0 ) );
// }
// _so.Attributes.Set( "g_FaceVelocity", FaceVelocity );
// _so.Attributes.Set( "g_FaceVelocityOffset", RotationOffset );
// _so.Attributes.Set( "g_DepthFeather", DepthFeather );
// _so.Attributes.Set( "g_FogStrength", FogStrength );
// _so.Attributes.Set( "g_ScreenSize", false );
// _so.Flags.IsOpaque = Opaque;
// _so.Flags.IsTranslucent = !Opaque;
_so.StartLine();
{
var list = effect.Particles;
var count = list.Count();
if ( list.Count() == 2 || SplineInterpolation == 1 )
{
foreach ( var p in list )
{
var size = p.Size * Scale;
_so.AddLinePoint( p.Position, p.Color.WithAlphaMultiplied( p.Alpha ), size.Length );
}
}
else
{
int i = 0;
int interpolation = SplineInterpolation.Clamp( 1, 100 );
int totalPoints = (count - 1) * interpolation;
foreach ( var point in list.Select( x => x.Position ).TcbSpline( interpolation, SplineTension, SplineContinuity, SplineBias ) )
{
var p = list[i / interpolation];
var size = p.Size * Scale;
_so.AddLinePoint( point, p.Color.WithAlphaMultiplied( p.Alpha ), size.Length );
i++;
}
}
_so.EndLine();
}
}
}