342 lines
9.3 KiB
C#
342 lines
9.3 KiB
C#
using Godot;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Rokojori
|
|
{
|
|
[Tool]
|
|
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Flash.svg") ]
|
|
public partial class FlashVFX:SequenceAction, Animator
|
|
{
|
|
[Export]
|
|
public FlashPreset preset;
|
|
|
|
// [Export, ReadOnly]
|
|
// public string test = "3";
|
|
|
|
// [Export, NamedArray ]
|
|
// public FlareLayer[] layers = [];
|
|
|
|
[Export]
|
|
public Node[] targets;
|
|
|
|
[Export]
|
|
public bool includeChildren = false;
|
|
|
|
public enum MaterialAssignementMode
|
|
{
|
|
Replace_Per_Target,
|
|
Add_For_Each_Material
|
|
}
|
|
|
|
[ExportGroup("Material Assignment")]
|
|
[Export]
|
|
public MaterialAssignementMode assignementMode = MaterialAssignementMode.Add_For_Each_Material;
|
|
|
|
[Export]
|
|
public Node3D positionOffset;
|
|
|
|
public void OnAnimatorStart(){}
|
|
public void OnAnimatorEnd(){}
|
|
public void OnAnimatorCancel(){}
|
|
|
|
Dictionary<int,FlashVFXRunner> _running = new Dictionary<int, FlashVFXRunner>();
|
|
|
|
protected override void _OnTrigger()
|
|
{
|
|
|
|
if ( assignementMode == MaterialAssignementMode.Replace_Per_Target )
|
|
{
|
|
_OnTrigger_ReplacePerTarget();
|
|
}
|
|
|
|
if ( assignementMode == MaterialAssignementMode.Add_For_Each_Material )
|
|
{
|
|
_OnTrigger_AddForEachMaterial();
|
|
}
|
|
}
|
|
|
|
|
|
protected void _OnTrigger_ReplacePerTarget()
|
|
{
|
|
var id = DispatchStart();
|
|
|
|
var duration = preset.duration == null ? new SecondsDuration() : preset.duration;
|
|
var tl = TimeLineManager.Ensure( duration.timeLine );
|
|
|
|
var OVERLAY = GeometryInstance3D.PropertyName.MaterialOverlay;
|
|
|
|
var runner = new FlashVFXRunner();
|
|
runner.flashVFX = this;
|
|
runner.targets = VFXTools.GetGeometryInstance3Ds( targets, includeChildren );
|
|
|
|
var gradient = preset.colorGradient.GetGradient();
|
|
var gradientRepeat = preset.colorGradient.GetRepeat();
|
|
var gradientRepeatMode = preset.colorGradient.GetRepeatMode();
|
|
|
|
var opacityCurve = preset.opacityCurve;
|
|
|
|
|
|
if ( runner.targets.Count == 0 )
|
|
{
|
|
DispatchEnd( id );
|
|
return;
|
|
}
|
|
|
|
runner.materials = runner.targets.Map( gi =>
|
|
{
|
|
return preset.flashType.CreateAndInitializeMaterial( runner, gi, gradient.Sample( 0 ) );
|
|
}
|
|
);
|
|
|
|
_running[ id ] = runner;
|
|
|
|
runner.AddLight();
|
|
|
|
for ( int i = 0; i < runner.targets.Count; i++ )
|
|
{
|
|
var t = runner.targets[ i ];
|
|
|
|
AnimationManager.StartAnimation( this, t, OVERLAY );
|
|
|
|
t.MaterialOverlay = runner.materials[ i ];
|
|
runner.assignedMaterials[ t ] = runner.materials[ i ];
|
|
|
|
}
|
|
|
|
|
|
TimeLineManager.ScheduleSpanIn( tl, 0, duration.GetDurationInSeconds(),
|
|
( span, type )=>
|
|
{
|
|
var timeNow = tl.position;
|
|
var phase = span.phase;
|
|
var color = gradient.SampleRepeated( phase * gradientRepeat, gradientRepeatMode );
|
|
var opacity = opacityCurve.Sample( phase );
|
|
|
|
runner.UpdateLight( phase, color, opacity );
|
|
|
|
for ( int i = 0; i < runner.targets.Count; i++ )
|
|
{
|
|
var gi = runner.targets[ i ];
|
|
|
|
if ( ! AnimationManager.IsAnimating( this, gi, OVERLAY ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var material = runner.materials[ i ];
|
|
preset.flashType.ApplyFlashType( runner, span.phase, color, opacity, gi, material );
|
|
}
|
|
|
|
|
|
if ( type == TimeLineSpanUpdateType.End )
|
|
{
|
|
for ( int i = 0; i < runner.targets.Count; i++ )
|
|
{
|
|
var gi = runner.targets[ i ];
|
|
|
|
if ( gi.MaterialOverlay == runner.assignedMaterials[ gi ] )
|
|
{
|
|
gi.MaterialOverlay = null;
|
|
}
|
|
|
|
AnimationManager.EndAnimation( this, gi, OVERLAY, runner.materials[ i ] );
|
|
}
|
|
|
|
runner.RemoveLight();
|
|
DispatchEnd( id );
|
|
}
|
|
},
|
|
this
|
|
);
|
|
}
|
|
|
|
protected void _OnTrigger_AddForEachMaterial()
|
|
{
|
|
var id = DispatchStart();
|
|
|
|
var duration = preset.duration == null ? new SecondsDuration() : preset.duration;
|
|
var tl = TimeLineManager.Ensure( duration.timeLine );
|
|
|
|
var OVERLAY = GeometryInstance3D.PropertyName.MaterialOverlay;
|
|
|
|
var runner = new FlashVFXRunner();
|
|
runner.flashVFX = this;
|
|
runner.targets = VFXTools.GetGeometryInstance3Ds( targets, includeChildren );
|
|
|
|
if ( runner.targets.Count == 0 )
|
|
{
|
|
DispatchEnd( id );
|
|
return;
|
|
}
|
|
|
|
runner.AddLight();
|
|
|
|
var gradient = preset.colorGradient.GetGradient();
|
|
var gradientRepeat = preset.colorGradient.GetRepeat();
|
|
var gradientRepeatMode = preset.colorGradient.GetRepeatMode();
|
|
var opacityCurve = preset.opacityCurve;
|
|
|
|
Material nullMaterial = null;
|
|
|
|
for ( int i = 0; i < runner.targets.Count; i++ )
|
|
{
|
|
var t = runner.targets[ i ];
|
|
|
|
if ( t.MaterialOverlay == null )
|
|
{
|
|
if ( nullMaterial == null )
|
|
{
|
|
nullMaterial = preset.flashType.CreateAndInitializeMaterial( runner, null, gradient.Sample( 0 ) );
|
|
runner.materials.Add( nullMaterial );
|
|
runner.assignedMaterials[ t ] = nullMaterial;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
var original = t.MaterialOverlay;
|
|
Material extended = null;
|
|
|
|
if ( ! runner.mappedMaterials.ContainsKey( original ) )
|
|
{
|
|
var mapped = preset.flashType.CreateAndInitializeMaterial( runner, null, gradient.Sample( 0 ) );
|
|
extended = t.MaterialOverlay.Duplicate() as Material;
|
|
|
|
Materials.AddToNextPass( extended, mapped );
|
|
runner.materials.Add( extended );
|
|
runner.mappedMaterials[ original ] = extended;
|
|
}
|
|
else
|
|
{
|
|
extended = runner.mappedMaterials[ original ];
|
|
}
|
|
|
|
runner.originalMaterials[ t ] = original;
|
|
runner.assignedMaterials[ t ] = extended;
|
|
t.MaterialOverlay = extended;
|
|
}
|
|
}
|
|
|
|
|
|
_running[ id ] = runner;
|
|
|
|
|
|
TimeLineManager.ScheduleSpanIn( tl, 0, duration.GetDurationInSeconds(),
|
|
( span, type )=>
|
|
{
|
|
var timeNow = tl.position;
|
|
var phase = span.phase;
|
|
var color = gradient.SampleRepeated( phase * gradientRepeat, gradientRepeatMode );
|
|
var opacity = opacityCurve.Sample( phase );
|
|
|
|
runner.UpdateLight( phase, color, opacity );
|
|
|
|
for ( int i = 0; i < runner.materials.Count; i++ )
|
|
{
|
|
var material = runner.materials[ i ];
|
|
preset.flashType.ApplyFlashType( runner, span.phase, color, opacity, null, material );
|
|
}
|
|
|
|
if ( type == TimeLineSpanUpdateType.End )
|
|
{
|
|
for ( int i = 0; i < runner.targets.Count; i++ )
|
|
{
|
|
var gi = runner.targets[ i ];
|
|
var material = runner.assignedMaterials[ gi ];
|
|
|
|
if ( gi.MaterialOverlay == material )
|
|
{
|
|
gi.MaterialOverlay = runner.originalMaterials.ContainsKey( gi ) ? runner.originalMaterials[ gi ] : null;
|
|
}
|
|
|
|
}
|
|
|
|
DispatchEnd( id );
|
|
|
|
runner.RemoveLight();
|
|
|
|
}
|
|
},
|
|
this
|
|
);
|
|
}
|
|
}
|
|
|
|
public class FlashVFXRunner
|
|
{
|
|
public FlashVFX flashVFX;
|
|
public FlashPreset preset => flashVFX.preset;
|
|
|
|
public List<GeometryInstance3D> targets = [];
|
|
public List<Material> materials = [];
|
|
|
|
public OmniLight3D light;
|
|
|
|
public Dictionary<GeometryInstance3D,Material> originalMaterials = new Dictionary<GeometryInstance3D, Material>();
|
|
public Dictionary<GeometryInstance3D,Material> assignedMaterials = new Dictionary<GeometryInstance3D, Material>();
|
|
public Dictionary<Material,Material> mappedMaterials = new Dictionary<Material, Material>();
|
|
|
|
|
|
public Vector3 GetFlashPosition( FlashPreset.PositionMode mode, Vector3 offset )
|
|
{
|
|
if ( FlashPreset.PositionMode.Position_Offset == mode )
|
|
{
|
|
return flashVFX.positionOffset.GlobalPosition + offset;
|
|
}
|
|
else if ( FlashPreset.PositionMode.Origin_Of_First == mode )
|
|
{
|
|
return targets[ 0 ].GlobalPosition + offset;
|
|
}
|
|
else if ( FlashPreset.PositionMode.Center_Of_All == mode )
|
|
{
|
|
return Node3DExtensions.GetCenter( targets ) + offset;
|
|
}
|
|
else
|
|
{
|
|
return offset;
|
|
}
|
|
}
|
|
|
|
public void AddLight()
|
|
{
|
|
if ( ! preset.lightEnabled )
|
|
{
|
|
return;
|
|
}
|
|
|
|
light = flashVFX.CreateChild<OmniLight3D>();
|
|
|
|
light.LightColor = new Color( 0, 0, 0 );
|
|
|
|
light.GlobalPosition = GetFlashPosition( preset.lightPosition, preset.lightPositionOffset );
|
|
|
|
light.OmniRange = preset.lightRange;
|
|
light.OmniAttenuation = preset.lightAttenutation;
|
|
light.LightEnergy = preset.lightEnergy;
|
|
light.ShadowEnabled = preset.lightShadowCasting;
|
|
|
|
|
|
}
|
|
|
|
public void UpdateLight( float phase, Color color, float opacity )
|
|
{
|
|
if ( light == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
light.LightColor = color * opacity;
|
|
}
|
|
|
|
public void RemoveLight()
|
|
{
|
|
if ( light == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
light.DeleteSelf();
|
|
}
|
|
}
|
|
} |