rokojori_action_library/Runtime/VFX/FlareVFX/FlareLayer.cs

367 lines
9.5 KiB
C#

using Godot;
using System.Collections.Generic;
namespace Rokojori
{
[Tool]
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/FlareVFX.svg") ]
public partial class FlareLayer:Resource
{
[Export]
public string layerName = "";
[Export]
public bool solo = false;
[Export]
public bool hide = false;
[Export( PropertyHint.Range, "0,1" )]
public float opacity = 1f;
[Export]
public int numLayers = 1;
[Export]
public FlareType flareType;
[ExportGroup("Color/Overwrite")]
[Export]
public Color overwriteColor = Colors.White;
[Export( PropertyHint.Range, "0,1" )]
public float overwriteAmount = 0f;
[ExportGroup("Color")]
[Export( PropertyHint.Range, "-180,180" )]
public float minHueRandom = 0;
[Export( PropertyHint.Range, "-180,180" )]
public float maxHueRandom = 0;
[Export]
public CurveTexture opacityCurvePerLayer = null;
[Export]
public Color tint = Colors.White;
[Export( PropertyHint.Range, "-180,180" )]
public float hueShift = 0;
[Export( PropertyHint.Range, "-180,180" )]
public float temparatureShift = 0;
[Export( PropertyHint.Range, "-100,100" )]
public float saturationShift = 0;
[Export( PropertyHint.Range, "-100,100" )]
public float lighntessShift = 0;
[ExportGroup("Size")]
[Export]
public float size = 1;
[Export( PropertyHint.Range, "0,1" )]
public float sizeScale = 1;
[Export( PropertyHint.Range, "0,1" )]
public float sizeXScale = 1f;
[Export( PropertyHint.Range, "0,1" )]
public float sizeYScale = 1f;
[Export( PropertyHint.Range, "0,2" )]
public float worldSizeScale = 1f;
[Export( PropertyHint.Range, "0,2" )]
public float screenSizeScale = 1f;
[Export( PropertyHint.Range, "0,1" )]
public float worldSize_vs_screenSize = 1f;
[Export( PropertyHint.Range, "0,2" )]
public float randomScaleMin = 1f;
[Export( PropertyHint.Range, "0,2" )]
public float randomScaleMax = 1f;
[Export]
public bool overwriteExtension = false;
[Export( PropertyHint.Range, "1,10" )]
public float extension = 1f;
[ExportGroup("ScreenOffset")]
[Export]
public Vector2 screenOffset = Vector2.Zero;
[Export( PropertyHint.Range, "0,1" )]
public float screenOffsetStaticScale = 1f;
[Export]
public Vector2 screenOffsetStaticDirection = Vector2.Zero;
[Export( PropertyHint.Range, "0,1" )]
public float screenOffsetLayerScale = 1f;
[Export]
public Vector2 screenOffsetLayerDirection = Vector2.Zero;
[ExportGroup("Rotation")]
[Export( PropertyHint.Range, "-180,180" )]
public float rotation = 0;
[Export( PropertyHint.Range, "-180,180" )]
public float rotationOverX = 0;
[Export( PropertyHint.Range, "-180,180" )]
public float rotationOverY = 0f;
[Export( PropertyHint.Range, "-180,180" )]
public float rotationPerLayer = 0f;
[ExportGroup("Overwrites")]
[Export]
public FlareFading fading = null;
[Export]
public FlareChromaticAberation chromaticAberation = null;
[Export]
public FlareOcclusion occlusion = null;
[Export]
public FlareBlendMode blendMode = null;
[Export]
public FlareStencilMode stencilMode = null;
[Export]
public int renderPriority = 0;
public Data Create( FlareVFX vfx )
{
return new Data( vfx, this );
}
public class Data
{
public FlareLayer layer;
public FlareVFX vfx;
public MeshInstance3D meshInstance;
public ShaderMaterial material;
public FlareBlendMode.BlendModeType GetBlendMode()
{
return layer.blendMode != null ? layer.blendMode.blendMode : vfx.preset.blendMode;
}
public Data( FlareVFX vfx, FlareLayer layer )
{
this.vfx = vfx;
this.layer = layer;
}
public void Update()
{
if ( meshInstance == null || layer.flareType == null )
{
return;
}
EnsureMesh();
EnsureMaterial();
if ( material == null )
{
return;
}
layer.flareType.ApplyShape( this );
ApplyColor();
ApplySize();
ApplyScreenOffset();
ApplyRotation();
ApplyFading();
ApplyChromaticAberation();
ApplyOcclusion();
material.RenderPriority = layer.renderPriority;
}
void EnsureMesh()
{
var arrayMesh = meshInstance.Mesh as ArrayMesh;
if ( arrayMesh != null && arrayMesh.SurfaceGetArrayLen( 0 ) == layer.numLayers * 4 )
{
return;
}
var gen = new UnitBillboardQuadsGenerator();
gen.num = layer.numLayers;
meshInstance.Mesh = gen.Generate();
}
void EnsureMaterial()
{
var miMaterial = meshInstance.GetSurfaceOverrideMaterial( 0 ) as ShaderMaterial;
if ( material != null && miMaterial != null && miMaterial.Shader == layer.flareType.GetShader( this ) )
{
return;
}
material = layer.flareType.CreateMaterial( this );
meshInstance.SetSurfaceOverrideMaterial( 0, material );
}
void ApplyColor()
{
var preset = vfx.preset;
var color = preset.mainColor;
if ( layer.overwriteAmount > 0 )
{
color = color.Lerp( layer.overwriteColor, layer.overwriteAmount );
}
color *= layer.tint;
var scale = color.GetColorScale();
var hsl = color.ToHSL( scale );
hsl.h += layer.hueShift + preset.hueShift;
hsl.h = MathX.Repeat( hsl.h, 360f );
hsl.h = HSLColor.ShiftTemparatureOfHue( hsl.h, preset.temparatureShift + layer.temparatureShift );
hsl.s += ( layer.saturationShift + preset.saturationShift ) / 100f;
hsl.l += ( layer.lighntessShift + preset.lightnessShift ) / 100f;
hsl.ClampToLimits();
color = hsl.ToRGBA( scale );
// color = preset.mainColor;
BaseFlareShader.color.Set( material, color );
BaseFlareShader.opacity.Set( material, preset.opacity * layer.opacity );
BaseFlareShader.opacityCurve.Set( material, layer.opacityCurvePerLayer );
BaseFlareShader.minHueRandom.Set( material, layer.minHueRandom / 360f );
BaseFlareShader.maxHueRandom.Set( material, layer.maxHueRandom / 360f );
}
void ApplySize()
{
var preset = vfx.preset;
var size = Vector2.One * preset.scale;
size *= layer.size * layer.sizeScale * new Vector2( layer.sizeXScale, layer.sizeYScale );
BaseFlareShader.sizeX.Set( material, size.X );
BaseFlareShader.sizeY.Set( material, size.Y );
BaseFlareShader.worldSizeScale.Set( material, layer.worldSizeScale );
BaseFlareShader.screenSizeScale.Set( material, layer.screenSizeScale );
BaseFlareShader.worldSizeVsScreenSize.Set( material, layer.worldSize_vs_screenSize );
BaseFlareShader.randomScaleMin.Set( material, layer.randomScaleMin );
BaseFlareShader.randomScaleMax.Set( material, layer.randomScaleMax );
BaseFlareShader.extension.Set( material, layer.overwriteExtension ? layer.extension : preset.extension );
}
void ApplyScreenOffset()
{
BaseFlareShader.screenOffset.Set( material, layer.screenOffset );
BaseFlareShader.screenOffsetScale.Set( material, layer.screenOffsetStaticDirection * layer.screenOffsetStaticScale );
BaseFlareShader.screenOffsetLayerSpread.Set( material, layer.screenOffsetLayerDirection * layer.screenOffsetLayerScale );
}
void ApplyRotation()
{
BaseFlareShader.rotation.Set( material, layer.rotation );
BaseFlareShader.rotationOverX.Set( material, layer.rotationOverX );
BaseFlareShader.rotationOverY.Set( material, layer.rotationOverY );
BaseFlareShader.rotationPerLayer.Set( material, layer.rotationPerLayer );
// BaseFlareShader.vertexRotation.Set( material, layer.vertexRotation );
// BaseFlareShader.vertexRotationOverX.Set( material, layer.vertexRotationOverX );
// BaseFlareShader.vertexRotationOverY.Set( material, layer.vertexRotationOverY );
// BaseFlareShader.vertexRotationPerLayer.Set( material, layer.vertexRotationPerLayer );
}
void ApplyFading()
{
var preset = vfx.preset;
var fading = preset.fading;
if ( layer.fading != null )
{
fading = layer.fading;
}
if ( fading == null )
{
BaseFlareShader.fadingMode.Set( material, 0 );
return;
}
fading.ApplyFading( this );
}
void ApplyChromaticAberation()
{
var preset = vfx.preset;
var chromaticAberation = preset.chromaticAberation;
if ( layer.chromaticAberation != null )
{
chromaticAberation = layer.chromaticAberation;
}
if ( chromaticAberation == null )
{
BaseFlareShader.chromaticAberationMode.Set( material, 0 );
return;
}
chromaticAberation.ApplyChromaticAberation( this );
}
void ApplyOcclusion()
{
var preset = vfx.preset;
var occlusion = preset.occlusion;
if ( layer.occlusion != null )
{
occlusion = layer.occlusion;
}
if ( occlusion == null )
{
BaseFlareShader.occlusionMode.Set( material, 0 );
return;
}
occlusion.ApplyOcclusion( this );
}
}
}
}