From f025656b9758f19b0bb7cb12f03d9e6620cd9e83 Mon Sep 17 00:00:00 2001 From: Josef Date: Tue, 27 May 2025 22:07:15 +0200 Subject: [PATCH] Tween Lights --- Runtime/Actions/Visual/TweenLight.cs | 70 ++++++++ Runtime/Actions/Visual/TweenLight.cs.uid | 1 + Runtime/Actions/Visual/TweenLightData.cs | 86 ++++++++++ Runtime/Actions/Visual/TweenLightData.cs.uid | 1 + Runtime/Actions/Visual/TweenMaterial.cs | 152 ++++++++++++------ Runtime/Animation/Flash/Flash.cs | 60 +++++-- Runtime/Animation/Tweens/TweenTimeCurve.cs | 30 ++++ .../Animation/Tweens/TweenTimeCurve.cs.uid | 1 + Runtime/Animation/Tweens/TweenType.cs | 22 +++ Runtime/Animation/Tweens/TweenType.cs.uid | 1 + Runtime/Godot/Nodes.cs | 14 ++ .../Mesh/MaterialSurfaceContainer.cs | 14 +- Runtime/Shading/Materials/MaterialDelta.cs | 74 +++++++++ .../Shading/Materials/MaterialDelta.cs.uid | 1 + Runtime/Shading/Materials/Materials.cs | 5 + .../Properties/Properties/ColorProperty.cs | 8 + .../Properties/Properties/FloatProperty.cs | 8 + Runtime/Shading/Shaders/Shaders.cs | 35 ++++ Runtime/Shading/Shaders/UniformMember.cs | 31 ++++ Runtime/Tools/Boxed/ColorValue.cs | 49 ++++++ Runtime/Tools/Boxed/ColorValue.cs.uid | 1 + Runtime/Tools/Boxed/FloatValue.cs | 50 ++++++ Runtime/Tools/Boxed/FloatValue.cs.uid | 1 + 23 files changed, 651 insertions(+), 64 deletions(-) create mode 100644 Runtime/Actions/Visual/TweenLight.cs create mode 100644 Runtime/Actions/Visual/TweenLight.cs.uid create mode 100644 Runtime/Actions/Visual/TweenLightData.cs create mode 100644 Runtime/Actions/Visual/TweenLightData.cs.uid create mode 100644 Runtime/Animation/Tweens/TweenTimeCurve.cs create mode 100644 Runtime/Animation/Tweens/TweenTimeCurve.cs.uid create mode 100644 Runtime/Animation/Tweens/TweenType.cs create mode 100644 Runtime/Animation/Tweens/TweenType.cs.uid create mode 100644 Runtime/Shading/Materials/MaterialDelta.cs create mode 100644 Runtime/Shading/Materials/MaterialDelta.cs.uid create mode 100644 Runtime/Tools/Boxed/ColorValue.cs create mode 100644 Runtime/Tools/Boxed/ColorValue.cs.uid create mode 100644 Runtime/Tools/Boxed/FloatValue.cs create mode 100644 Runtime/Tools/Boxed/FloatValue.cs.uid diff --git a/Runtime/Actions/Visual/TweenLight.cs b/Runtime/Actions/Visual/TweenLight.cs new file mode 100644 index 0000000..709314d --- /dev/null +++ b/Runtime/Actions/Visual/TweenLight.cs @@ -0,0 +1,70 @@ + +using System; +using Godot; + + +namespace Rokojori +{ + [Tool] + [GlobalClass ] + public partial class TweenLight:SequenceAction + { + [Export] + public Light3D light3D; + + [Export] + public TweenLightData tweenLightData; + + [Export] + public TweenType tweenType = new TweenTimeCurve(); + + [Export] + public TimeLine timeLine; + + + protected override void _OnTrigger() + { + if ( light3D == null || tweenLightData == null ) + { + return; + } + + var tl = TimeLineManager.Ensure( timeLine ); + + var start = tl.position; + + var fromData = new TweenLightData(); + fromData.CopyFrom( light3D ); + var lerpData = tweenLightData.Clone( true ); + + var sequenceID = DispatchStart(); + + var tweenType = this.tweenType; + + if ( tweenType == null ) + { + tweenType = TweenTimeCurve.defaultCurve; + } + + TimeLineManager.ScheduleSpanIn( tl, 0, tweenType.GetTweenDuration(), + ( span, type )=> + { + var timeNow = tl.position; + var elapsed = timeNow - start; + + var state = tweenType.GetTweenPhaseForPhase( span.phase ); + + TweenLightData.LerpTo( fromData, tweenLightData, state, lerpData ); + + lerpData.CopyTo( light3D ); + + if ( type == TimeLineSpanUpdateType.End ) + { + DispatchEnd( sequenceID ); + } + } + ); + } + + } +} \ No newline at end of file diff --git a/Runtime/Actions/Visual/TweenLight.cs.uid b/Runtime/Actions/Visual/TweenLight.cs.uid new file mode 100644 index 0000000..1fdbe0a --- /dev/null +++ b/Runtime/Actions/Visual/TweenLight.cs.uid @@ -0,0 +1 @@ +uid://bhn2p16isptba diff --git a/Runtime/Actions/Visual/TweenLightData.cs b/Runtime/Actions/Visual/TweenLightData.cs new file mode 100644 index 0000000..b244e88 --- /dev/null +++ b/Runtime/Actions/Visual/TweenLightData.cs @@ -0,0 +1,86 @@ + +using System; +using Godot; + + +namespace Rokojori +{ + [Tool] + [GlobalClass ] + public partial class TweenLightData:Resource + { + [ExportGroup("Light")] + [Export] + public ColorValue lightColor; + + [Export] + public FloatValue lightEnergy; + + [Export] + public FloatValue lightSpecular; + + [ExportGroup("Shadow")] + [Export] + public FloatValue shadowOpacity; + + + public virtual TweenLightData Clone( bool deepClone ) + { + var clone = new TweenLightData(); + + clone.lightColor = ColorValue.Clone( lightColor, deepClone ); + clone.lightEnergy = FloatValue.Clone( lightEnergy, deepClone ); + clone.lightSpecular = FloatValue.Clone( lightSpecular, deepClone ); + + clone.shadowOpacity = FloatValue.Clone( shadowOpacity, deepClone ); + + return clone; + + } + + public virtual void CopyFrom( Light3D light3D ) + { + lightColor = ColorValue.Create( light3D.LightColor ); + lightEnergy = FloatValue.Create( light3D.LightEnergy ); + lightSpecular = FloatValue.Create( light3D.LightSpecular ); + + shadowOpacity = FloatValue.Create( light3D.ShadowOpacity ); + } + + + public virtual void CopyFrom( TweenLightData tweenLightData ) + { + lightColor = tweenLightData.lightColor; + lightEnergy = tweenLightData.lightEnergy; + lightSpecular = tweenLightData.lightSpecular; + + shadowOpacity = tweenLightData.shadowOpacity; + } + + public virtual void CopyTo( Light3D light3D ) + { + if ( lightColor != null ) + { light3D.LightColor = lightColor.value; } + + if ( lightEnergy != null ) + { light3D.LightEnergy = lightEnergy.value; } + + if ( lightSpecular != null ) + { light3D.LightSpecular = lightSpecular.value; } + + if ( shadowOpacity != null ) + { light3D.ShadowOpacity = shadowOpacity.value; } + + } + + public static void LerpTo( TweenLightData a, TweenLightData b, float lerpAmount, TweenLightData output ) + { + ColorValue.Lerp( a.lightColor, b.lightColor, lerpAmount, output.lightColor ); + FloatValue.Lerp( a.lightEnergy, b.lightEnergy, lerpAmount, output.lightEnergy ); + FloatValue.Lerp( a.lightSpecular, b.lightSpecular, lerpAmount, output.lightSpecular ); + + FloatValue.Lerp( a.shadowOpacity, b.shadowOpacity, lerpAmount, output.shadowOpacity ); + } + + } +} \ No newline at end of file diff --git a/Runtime/Actions/Visual/TweenLightData.cs.uid b/Runtime/Actions/Visual/TweenLightData.cs.uid new file mode 100644 index 0000000..fc8ab4f --- /dev/null +++ b/Runtime/Actions/Visual/TweenLightData.cs.uid @@ -0,0 +1 @@ +uid://b6bnmseo2eq0q diff --git a/Runtime/Actions/Visual/TweenMaterial.cs b/Runtime/Actions/Visual/TweenMaterial.cs index 669d112..e14b8e1 100644 --- a/Runtime/Actions/Visual/TweenMaterial.cs +++ b/Runtime/Actions/Visual/TweenMaterial.cs @@ -1,4 +1,5 @@ +using System; using Godot; @@ -12,38 +13,36 @@ namespace Rokojori public void OnAnimatorEnd(){} public void OnAnimatorCancel(){} - [Export] - public Material material; + // [Export] + // public Material fromMaterial; [Export] - public float duration; - + public Material toMaterial; [Export] - public Curve tweenCurve = MathX.Curve( 0, 1 ); + public TweenType tweenType = new TweenTimeCurve(); [Export] public TimeLine timeLine; + ColorProperty[] colors = []; - - [Export] - public ColorProperty[] colors = []; - - [Export] - public FloatProperty[] floats = []; + FloatProperty[] floats = []; public enum MaterialAssignmentMode { No_Assignment, - Assignment, - Unique_Assignment + Assignment_Once, + Unique_Once, + Temporary_Duplicate_For_Each_Tween } - [ExportGroup( "Target Assignment")] - [Export] - public MaterialAssignmentMode assignmentMode; + + // [Export] + // public + MaterialAssignmentMode assignmentMode = MaterialAssignmentMode.Temporary_Duplicate_For_Each_Tween; + [ExportGroup( "Target")] [Export] public Node3D target; @@ -53,95 +52,140 @@ namespace Rokojori [Export] public int index = 0; + // [ExportToolButton( "Assign From-Material")] + // public Callable AssignFromMaterialButton => Callable.From( + // () => + // { + // MaterialSurfaceContainer.SetMaterialInSlot( target, index, slot, fromMaterial ); + // } + // ); + + [ExportToolButton( "Assign To-Material")] + public Callable AssignToMaterialButton => Callable.From( + () => + { + MaterialSurfaceContainer.SetMaterialInSlot( target, index, slot, toMaterial ); + } + ); + + [ExportToolButton( "Get Material Delta")] + public Callable GetMaterialDeltaButton => Callable.From( + () => + { + var from = MaterialSurfaceContainer.GetMaterialInSlot( target, index, slot ); + this.LogInfo( "Delta", MaterialDelta.Create( from, toMaterial ) ); + } + ); + Material _assignedMaterial = null; protected override void _OnTrigger() { - if ( material == null && _assignedMaterial == null ) + if ( toMaterial == null && this._assignedMaterial == null ) { return; } - SetAssignedMaterial(); + var fromMaterial = MaterialSurfaceContainer.From( target, this.index ).GetMaterialInSlot( slot ); + + SetAssignedMaterial( fromMaterial ); var tl = TimeLineManager.Ensure( timeLine ); var start = tl.position; + + + var delta = MaterialDelta.Create( fromMaterial, toMaterial ); + + this.LogInfo( "Delta:", delta ); + + + colors = delta.colorProperties.ToArray(); + floats = delta.floatProperties.ToArray(); + + var startColors = new Color[ colors.Length ]; var startFloats = new float[ floats.Length ]; - var index = 0; - - var assignedMaterial = _assignedMaterial; + var elementIndex = 0; foreach ( var c in colors ) { - AnimationManager.StartAnimation( this, assignedMaterial, c.propertyName ); - startColors[ index ] = c.propertyName.Get( assignedMaterial ); + AnimationManager.StartAnimation( this, _assignedMaterial, c.propertyName ); + startColors[ elementIndex ] = c.propertyName.Get( fromMaterial ); - index ++; + elementIndex ++; } - index = 0; + elementIndex = 0; foreach ( var f in floats ) { - AnimationManager.StartAnimation( this, assignedMaterial, f.propertyName ); - startFloats[ index ] = f.propertyName.Get( assignedMaterial ); - index ++; + AnimationManager.StartAnimation( this, _assignedMaterial, f.propertyName ); + startFloats[ elementIndex ] = f.propertyName.Get( fromMaterial ); + elementIndex ++; } var sequenceID = DispatchStart(); - TimeLineManager.ScheduleSpanIn( tl, 0, duration, + var tweenType = this.tweenType; + + if ( tweenType == null ) + { + tweenType = TweenTimeCurve.defaultCurve; + } + + TimeLineManager.ScheduleSpanIn( tl, 0, tweenType.GetTweenDuration(), ( span, type )=> { var timeNow = tl.position; var elapsed = timeNow - start; - var index = 0; - var state = span.phase; - - if ( tweenCurve != null ) - { - state = tweenCurve.Sample( state ); - } + var elementIndex = 0; + var state = tweenType.GetTweenPhaseForPhase( span.phase ); foreach ( var c in colors ) { - if ( AnimationManager.IsAnimating( this, assignedMaterial, c.propertyName ) ) + if ( AnimationManager.IsAnimating( this, _assignedMaterial, c.propertyName ) ) { - c.ApplyLerped( assignedMaterial, startColors[ index ], state ); + c.ApplyLerped( _assignedMaterial, startColors[ elementIndex ], state ); } - index ++; + elementIndex ++; } - index = 0; + elementIndex = 0; foreach ( var f in floats ) { - if ( AnimationManager.IsAnimating( this, assignedMaterial, f.propertyName ) ) + if ( AnimationManager.IsAnimating( this, _assignedMaterial, f.propertyName ) ) { - f.ApplyLerped( assignedMaterial, startFloats[ index ], state ); + f.ApplyLerped( _assignedMaterial, startFloats[ elementIndex ], state ); } - index ++; + elementIndex ++; } if ( type == TimeLineSpanUpdateType.End ) { foreach ( var c in colors ) { - AnimationManager.EndAnimation( this, assignedMaterial, c.propertyName ); + AnimationManager.EndAnimation( this, _assignedMaterial, c.propertyName ); } foreach ( var f in floats ) { - AnimationManager.EndAnimation( this, assignedMaterial, f.propertyName ); + AnimationManager.EndAnimation( this, _assignedMaterial, f.propertyName ); } + if ( MaterialAssignmentMode.Temporary_Duplicate_For_Each_Tween == assignmentMode ) + { + _assignedMaterial = null; + var msc = MaterialSurfaceContainer.From( target, index ); + msc.SetMaterialInSlot( slot, toMaterial ); + } + DispatchEnd( sequenceID ); } } @@ -150,8 +194,16 @@ namespace Rokojori } - void SetAssignedMaterial() + void SetAssignedMaterial( Material material ) { + if ( MaterialAssignmentMode.Temporary_Duplicate_For_Each_Tween == assignmentMode ) + { + _assignedMaterial = (Material)material.Duplicate(); + var tmsc = MaterialSurfaceContainer.From( target, index ); + tmsc.SetMaterialInSlot( slot, _assignedMaterial ); + return; + } + if ( _assignedMaterial != null ) { return; @@ -159,15 +211,15 @@ namespace Rokojori if ( MaterialAssignmentMode.No_Assignment == assignmentMode ) { - _assignedMaterial = material; + _assignedMaterial = toMaterial; return; } - _assignedMaterial = material; + _assignedMaterial = toMaterial; - if ( MaterialAssignmentMode.Unique_Assignment == assignmentMode ) + if ( MaterialAssignmentMode.Unique_Once == assignmentMode ) { - _assignedMaterial = (Material)material.Duplicate(); + _assignedMaterial = (Material)toMaterial.Duplicate(); } var msc = MaterialSurfaceContainer.From( target, index ); diff --git a/Runtime/Animation/Flash/Flash.cs b/Runtime/Animation/Flash/Flash.cs index ca0a1f8..b1b1baa 100644 --- a/Runtime/Animation/Flash/Flash.cs +++ b/Runtime/Animation/Flash/Flash.cs @@ -13,9 +13,49 @@ namespace Rokojori [Export] public FlashEffect flashEffect; - [Export] - public Node3D[] targets = new Node3D[ 0 ]; + Node3D[] _targets = []; + [Export] + public Node3D[] targets + { + get => _targets; + set + { + _targets = value; + _allTargets = null; + } + } + + [Export] + public bool includeChildren = false; + + bool refresh = false; + + Node3D[] _allTargets; + public Node3D[] allTargets + { + get + { + if ( _allTargets != null ) + { + return _allTargets; + } + + if ( includeChildren ) + { + _allTargets = Nodes.GetAnyChildren( _targets ).ToArray(); + } + else + { + _allTargets = _targets; + } + + _allTargets = Lists.Filter( Lists.From( allTargets ), t => t as GeometryInstance3D != null ).ToArray(); + + return _allTargets; + + } + } int animationID = -1; int actionID = -1; @@ -73,7 +113,7 @@ namespace Rokojori if ( FlashEffect.FlashLightMode.No_Light != flashEffect.lightMode ) { - light = targets[ 0 ].CreateChild(); + light = allTargets[ 0 ].CreateChild(); light.LightColor = ComputeLightColor( color, 0 ); light.LightEnergy = 0; light.OmniRange = flashEffect.lightRange; @@ -126,7 +166,7 @@ namespace Rokojori _materials = new List(); - Arrays.ForEach( targets, + Arrays.ForEach( allTargets, t => { var m = (Material) material.Duplicate( true ); @@ -219,12 +259,6 @@ namespace Rokojori public override void CancelAction( int id ) { - if ( false && actionID != id ) - { - // RJLog.Log( "actionID != id", "id", id, "actionID", actionID ); - return; - } - if ( light != null ) { // RJLog.Log( "Removing Light", light.Name ); @@ -243,14 +277,14 @@ namespace Rokojori void RemoveMaterials() { - if ( _materials.Count != targets.Length ) + if ( _materials.Count != allTargets.Length ) { return; } - for ( int i = 0; i < targets.Length; i++ ) + for ( int i = 0; i < allTargets.Length; i++ ) { - Materials.RemoveOverlay( targets[ i ], _materials[ i ] ); + Materials.RemoveOverlay( allTargets[ i ], _materials[ i ] ); } _materials.Clear(); diff --git a/Runtime/Animation/Tweens/TweenTimeCurve.cs b/Runtime/Animation/Tweens/TweenTimeCurve.cs new file mode 100644 index 0000000..e177daf --- /dev/null +++ b/Runtime/Animation/Tweens/TweenTimeCurve.cs @@ -0,0 +1,30 @@ + +using Godot; + + +namespace Rokojori +{ + [Tool] + [GlobalClass ] + public partial class TweenTimeCurve : TweenType + { + public static readonly TweenTimeCurve defaultCurve = new TweenTimeCurve(); + + [Export] + public float duration = 0.5f; + + [Export] + public Curve curve = MathX.Curve( 0, 1 ); + + public override float GetTweenDuration() + { + return duration; + } + + public override float GetTweenPhaseForPhase( float phase ) + { + return curve == null ? phase : curve.Sample( phase ); + } + + } +} diff --git a/Runtime/Animation/Tweens/TweenTimeCurve.cs.uid b/Runtime/Animation/Tweens/TweenTimeCurve.cs.uid new file mode 100644 index 0000000..353331f --- /dev/null +++ b/Runtime/Animation/Tweens/TweenTimeCurve.cs.uid @@ -0,0 +1 @@ +uid://lm37r3ycp1ls diff --git a/Runtime/Animation/Tweens/TweenType.cs b/Runtime/Animation/Tweens/TweenType.cs new file mode 100644 index 0000000..eac6f28 --- /dev/null +++ b/Runtime/Animation/Tweens/TweenType.cs @@ -0,0 +1,22 @@ + +using Godot; + + +namespace Rokojori +{ + [Tool] + [GlobalClass ] + public partial class TweenType : Resource + { + public virtual float GetTweenDuration() + { + return 0.5f; + } + + public virtual float GetTweenPhaseForPhase( float phase ) + { + return phase; + } + + } +} diff --git a/Runtime/Animation/Tweens/TweenType.cs.uid b/Runtime/Animation/Tweens/TweenType.cs.uid new file mode 100644 index 0000000..61cba3b --- /dev/null +++ b/Runtime/Animation/Tweens/TweenType.cs.uid @@ -0,0 +1 @@ +uid://b7x1qbh5cosdl diff --git a/Runtime/Godot/Nodes.cs b/Runtime/Godot/Nodes.cs index cacb6bc..a0900d1 100644 --- a/Runtime/Godot/Nodes.cs +++ b/Runtime/Godot/Nodes.cs @@ -135,6 +135,20 @@ namespace Rokojori return list; } + public static List GetAnyChildren( T[] nodes ) where T:Node + { + var list = new List(); + + for ( int i = 0; i < nodes.Length; i++ ) + { + list.Add( nodes[ i ] ); + + ForEach( nodes[ i ], list.Add ); + } + + return list; + } + public static List AllIn( Node root, Func filter = null, bool includeRoot = true) where T:class { var list = new List(); diff --git a/Runtime/Procedural/Mesh/MaterialSurfaceContainer.cs b/Runtime/Procedural/Mesh/MaterialSurfaceContainer.cs index 460a172..3b3af51 100644 --- a/Runtime/Procedural/Mesh/MaterialSurfaceContainer.cs +++ b/Runtime/Procedural/Mesh/MaterialSurfaceContainer.cs @@ -34,6 +34,18 @@ namespace Rokojori public abstract T GetMaterialInSlot( MaterialSlot slot ) where T:Material; public abstract void SetMaterialInSlot( MaterialSlot slot, Material material ); + public static void SetMaterialInSlot( Node3D owner, int surfaceIndex, MaterialSlot slot, Material material ) + { + var c = MaterialSurfaceContainer.From( owner, surfaceIndex ); + c.SetMaterialInSlot( slot, material ); + } + + public static T GetMaterialInSlot( Node3D owner, int surfaceIndex, MaterialSlot slot ) where T:Material + { + var c = MaterialSurfaceContainer.From( owner, surfaceIndex ); + return c.GetMaterialInSlot( slot ); + } + public void SetActiveMaterial( Material material ) { SetMaterialInSlot( GetActiveMaterialSlot(), material ); @@ -169,7 +181,7 @@ namespace Rokojori public override void SetMaterialInSlot( MaterialSlot slot, Material material ) { - if ( surfaceIndex == -1 || MaterialSlot.None == slot ) + if ( surfaceIndex == -1 || MaterialSlot.None == slot || material == null || node == null ) { return; } diff --git a/Runtime/Shading/Materials/MaterialDelta.cs b/Runtime/Shading/Materials/MaterialDelta.cs new file mode 100644 index 0000000..664c4f6 --- /dev/null +++ b/Runtime/Shading/Materials/MaterialDelta.cs @@ -0,0 +1,74 @@ +using Godot; +using System.Reflection; +using System.Collections.Generic; +using System.Text; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class MaterialDelta:Resource + { + public List colorProperties = new List(); + public List floatProperties = new List(); + + public override string ToString() + { + var sb = new StringBuilder(); + colorProperties.ForEach( c => sb.Append( c.propertyName.propertyName + ", " ) ); + floatProperties.ForEach( f => sb.Append( f.propertyName.propertyName + ", " ) ); + return sb.ToString(); + } + + public static MaterialDelta Create( Material a, Material b ) + { + if ( ! Materials.HaveSameShaderType( a, b ) ) + { + return null; + } + + var delta = new MaterialDelta(); + + var uniforms = Shaders.GetUniformMembers( a ); + + uniforms.ForEach( + ( u )=> + { + + if ( Variant.Type.Color == u.type ) + { + var colorA = u.Get( a ); + var colorB = u.Get( b ); + + if ( colorA == colorB ) + { + return; + } + + RJLog.Log( "Is Different", u.name, ":", u.type, ">>", colorA, colorB ); + + delta.colorProperties.Add( ColorProperty.Create( u.name, colorB ) ); + } + + if ( Variant.Type.Float == u.type ) + { + var floatA = u.Get( a ); + var floatB = u.Get( b ); + + if ( floatA == floatB ) + { + return; + } + + + RJLog.Log( "Is Different", u.name, ":", u.type, ">>", floatA, floatB ); + + delta.floatProperties.Add( FloatProperty.Create( u.name, floatB ) ); + } + } + ); + + return delta; + } + } +} \ No newline at end of file diff --git a/Runtime/Shading/Materials/MaterialDelta.cs.uid b/Runtime/Shading/Materials/MaterialDelta.cs.uid new file mode 100644 index 0000000..d9103c6 --- /dev/null +++ b/Runtime/Shading/Materials/MaterialDelta.cs.uid @@ -0,0 +1 @@ +uid://bnbt4xcvfdb1b diff --git a/Runtime/Shading/Materials/Materials.cs b/Runtime/Shading/Materials/Materials.cs index 27ee5aa..4175652 100644 --- a/Runtime/Shading/Materials/Materials.cs +++ b/Runtime/Shading/Materials/Materials.cs @@ -7,6 +7,11 @@ namespace Rokojori public class Materials { + public static bool HaveSameShaderType( Material a, Material b ) + { + return a.GetType() == b.GetType(); + } + public static int CountOf( Node node ) { var s = new StandardMaterial3D(); diff --git a/Runtime/Shading/Properties/Properties/ColorProperty.cs b/Runtime/Shading/Properties/Properties/ColorProperty.cs index 81be888..1fa0a97 100644 --- a/Runtime/Shading/Properties/Properties/ColorProperty.cs +++ b/Runtime/Shading/Properties/Properties/ColorProperty.cs @@ -24,5 +24,13 @@ namespace Rokojori var lerpedColor = from.Lerp( color, lerpState ); propertyName.Set( material, lerpedColor ); } + + public static ColorProperty Create( string name, Color color ) + { + var cp = new ColorProperty(); + cp.propertyName = ColorPropertyName.Create( name ); + cp.color = color; + return cp; + } } } \ No newline at end of file diff --git a/Runtime/Shading/Properties/Properties/FloatProperty.cs b/Runtime/Shading/Properties/Properties/FloatProperty.cs index 410b528..7072822 100644 --- a/Runtime/Shading/Properties/Properties/FloatProperty.cs +++ b/Runtime/Shading/Properties/Properties/FloatProperty.cs @@ -24,5 +24,13 @@ namespace Rokojori var lerpedValue = Mathf.Lerp( from, value, lerpState ); propertyName.Set( material, lerpedValue ); } + + public static FloatProperty Create( string name, float value ) + { + var fp = new FloatProperty(); + fp.propertyName = FloatPropertyName.Create( name ); + fp.value = value; + return fp; + } } } \ No newline at end of file diff --git a/Runtime/Shading/Shaders/Shaders.cs b/Runtime/Shading/Shaders/Shaders.cs index d6de596..1f09aa9 100644 --- a/Runtime/Shading/Shaders/Shaders.cs +++ b/Runtime/Shading/Shaders/Shaders.cs @@ -7,6 +7,41 @@ namespace Rokojori public class Shaders { + public static List GetUniformMembersOfStandardMaterial() + { + var list = new List(); + + var m = new StandardMaterial3D(); + + list.AddRange( + Lists.Map( + ReflectionHelper.GetDataMemberInfos( m ), + c => UniformMember.Create( c.Name, Variant.Type.Color ) + ) + ); + + list.AddRange( + Lists.Map( + ReflectionHelper.GetDataMemberInfos( m ), + c => UniformMember.Create( c.Name, Variant.Type.Float ) + ) + ); + + return list; + } + + public static List GetUniformMembers( Material material ) + { + if ( material is StandardMaterial3D ) + { + return GetUniformMembersOfStandardMaterial(); + } + + var shaderMaterial = material as ShaderMaterial; + return GetUniformMembers( shaderMaterial.Shader ); + } + + public static List GetUniformMembers( Shader shader ) { var list = new List(); diff --git a/Runtime/Shading/Shaders/UniformMember.cs b/Runtime/Shading/Shaders/UniformMember.cs index 6f7b6b1..fd58ae1 100644 --- a/Runtime/Shading/Shaders/UniformMember.cs +++ b/Runtime/Shading/Shaders/UniformMember.cs @@ -1,6 +1,7 @@ using Godot; using System.Reflection; using System.Collections.Generic; +using Microsoft.VisualBasic; namespace Rokojori { @@ -18,6 +19,14 @@ namespace Rokojori return type + " " + name + "( '" + hint + "', '" + hintString + "', '" + usage + "')"; } + public static UniformMember Create( string name, Variant.Type type ) + { + var um = new UniformMember (); + um.name = name; + um.type = type; + return um; + } + public string GetPropertyNameType() { if ( type == Variant.Type.Object ) @@ -30,5 +39,27 @@ namespace Rokojori } } + public T Get<[MustBeVariant] T>( Material material ) + { + return material is ShaderMaterial sm ? Get( sm ) : Get( (StandardMaterial3D) material ); + } + + public T Get<[MustBeVariant] T>( ShaderMaterial shaderMaterial ) + { + return shaderMaterial.GetShaderParameter( name ).As(); + } + + public T Get<[MustBeVariant] T>( StandardMaterial3D standardMaterial ) + { + var property = new ShaderPropertyName(); + property.propertyName = name; + return property._Get( standardMaterial, default( T ) ); + } + + public void Set( ShaderMaterial shaderMaterial, Variant value ) + { + shaderMaterial.SetShaderParameter( name, value ); + } + } } \ No newline at end of file diff --git a/Runtime/Tools/Boxed/ColorValue.cs b/Runtime/Tools/Boxed/ColorValue.cs new file mode 100644 index 0000000..bd29cd3 --- /dev/null +++ b/Runtime/Tools/Boxed/ColorValue.cs @@ -0,0 +1,49 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System; +using Godot; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class ColorValue:Resource + { + [Export] + public Color value; + + public override string ToString() + { + return "ColorValue( " + value + " )"; + } + + public static ColorValue Create( Color value ) + { + var cv = new ColorValue(); + cv.value = value; + + return cv; + } + + public static ColorValue Clone( ColorValue value, bool deepClone ) + { + if ( deepClone ) + { + return value == null ? null : Create( value.value ); + } + + return value; + } + + public static void Lerp( ColorValue a, ColorValue b, float amount, ColorValue output ) + { + if ( a == null || b == null || output == null ) + { + return; + } + + output.value = ColorX.Lerp( a.value, b.value, amount ); + } + } +} \ No newline at end of file diff --git a/Runtime/Tools/Boxed/ColorValue.cs.uid b/Runtime/Tools/Boxed/ColorValue.cs.uid new file mode 100644 index 0000000..69879ec --- /dev/null +++ b/Runtime/Tools/Boxed/ColorValue.cs.uid @@ -0,0 +1 @@ +uid://evtt3x1yxlbw diff --git a/Runtime/Tools/Boxed/FloatValue.cs b/Runtime/Tools/Boxed/FloatValue.cs new file mode 100644 index 0000000..d92aac4 --- /dev/null +++ b/Runtime/Tools/Boxed/FloatValue.cs @@ -0,0 +1,50 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System; +using Godot; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class FloatValue:Resource + { + [Export] + public float value; + + public override string ToString() + { + return "FloatValue( " + RegexUtility.NumberToString( value ) + " )"; + } + + public static FloatValue Create( float value ) + { + var fv = new FloatValue(); + fv.value = value; + + return fv; + } + + public static FloatValue Clone( FloatValue value, bool deepClone ) + { + if ( deepClone ) + { + return value == null ? null : Create( value.value ); + } + + return value; + } + + + public static void Lerp( FloatValue a, FloatValue b, float amount, FloatValue output ) + { + if ( a == null || b == null || output == null ) + { + return; + } + + output.value = Mathf.Lerp( a.value, b.value, amount ); + } + } +} \ No newline at end of file diff --git a/Runtime/Tools/Boxed/FloatValue.cs.uid b/Runtime/Tools/Boxed/FloatValue.cs.uid new file mode 100644 index 0000000..0096fd2 --- /dev/null +++ b/Runtime/Tools/Boxed/FloatValue.cs.uid @@ -0,0 +1 @@ +uid://cfvigaosponfn