212 lines
4.8 KiB
C#
212 lines
4.8 KiB
C#
|
|
using Godot;
|
|
using Rokojori;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Rokojori
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
[Tool]
|
|
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Spline.svg") ]
|
|
public partial class Deformer : Node3D
|
|
#if TOOLS
|
|
, GizmoDrawer
|
|
#endif
|
|
|
|
{
|
|
public class MappingData
|
|
{
|
|
public Vector3 localPosition;
|
|
public float parameter;
|
|
public float weight;
|
|
}
|
|
|
|
public enum WeightsMappingMethod
|
|
{
|
|
Max_Distance
|
|
}
|
|
|
|
[Export]
|
|
public Spline[] sourceSplines;
|
|
|
|
[Export]
|
|
public MeshInstance3D sourceMesh;
|
|
|
|
[Export]
|
|
public bool updateSourceMesh;
|
|
|
|
[Export]
|
|
public Spline[] deformerSplines;
|
|
|
|
[Export]
|
|
public MeshInstance3D outputMesh;
|
|
|
|
[Export( PropertyHint.Range, "0,1")]
|
|
public float targetSmoothing = 0f;
|
|
|
|
[Export]
|
|
public float splineMaxDistance = 1000f;
|
|
|
|
[Export]
|
|
public float splineMinDistance = 0f;
|
|
|
|
[Export]
|
|
public int splineMappingResolution = 40;
|
|
|
|
[Export]
|
|
public int splineMappingDepth = 3;
|
|
|
|
[Export]
|
|
public bool update = false;
|
|
|
|
[Export]
|
|
public bool updateAlways = false;
|
|
|
|
|
|
MappingData[] deformerMappings;
|
|
MeshGeometry meshGeometry;
|
|
|
|
MappingData CreateSourceMapping( Spline s, Vector3 worldPosition )
|
|
{
|
|
var curve = s.GetCurve();
|
|
var closestParameter = curve.GetClosestParameterTo( worldPosition, splineMappingResolution, splineMappingDepth );
|
|
var pose = curve.GetPoseByPointIndex( closestParameter );
|
|
|
|
var localPosition = pose.ApplyInverse( worldPosition );
|
|
|
|
var mappingData = new MappingData();
|
|
|
|
mappingData.localPosition = localPosition;
|
|
mappingData.parameter = closestParameter;
|
|
mappingData.weight = 0;
|
|
|
|
return mappingData;
|
|
}
|
|
|
|
void CreateSourceMappings()
|
|
{
|
|
meshGeometry = MeshGeometry.From( sourceMesh );
|
|
|
|
var mappingSize = meshGeometry.vertices.Count * sourceSplines.Length;
|
|
|
|
if ( deformerMappings == null || deformerMappings.Length != mappingSize )
|
|
{
|
|
deformerMappings = new MappingData[ mappingSize];
|
|
}
|
|
|
|
RJLog.Log( "Mappings:", deformerMappings.Length, meshGeometry );
|
|
|
|
for ( int i = 0; i < meshGeometry.vertices.Count; i++ )
|
|
{
|
|
var weights = 0f;
|
|
|
|
for ( int j = 0; j < sourceSplines.Length; j++ )
|
|
{
|
|
var vertex = meshGeometry.vertices[ i ];
|
|
var mapping = CreateSourceMapping( sourceSplines[ j ], vertex );
|
|
var curve = sourceSplines[ j ].GetCurve();
|
|
var distance = curve.PositionAt( mapping.parameter ) - vertex;
|
|
var inverseWeight = MathX.NormalizeClamped( distance.Length(), splineMinDistance, splineMaxDistance );
|
|
mapping.weight = 1f - inverseWeight;
|
|
weights += mapping.weight;
|
|
deformerMappings[ i * sourceSplines.Length + j ] = mapping;
|
|
}
|
|
|
|
if ( weights > 0 && weights != 1f )
|
|
{
|
|
for ( int j = 0; j < sourceSplines.Length; j++ )
|
|
{
|
|
var mapping = deformerMappings[ i * sourceSplines.Length + j ];
|
|
mapping.weight /= weights;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CreateDeformed()
|
|
{
|
|
// RJLog.Log( "CreateDeformed" );
|
|
|
|
var cloned = meshGeometry.Clone();
|
|
|
|
for ( int i = 0; i < cloned.vertices.Count; i++ )
|
|
{
|
|
var vertexPosition = Vector3.Zero;
|
|
|
|
for ( int j = 0; j < deformerSplines.Length; j++ )
|
|
{
|
|
var mapping = deformerMappings[ i * deformerSplines.Length + j ];
|
|
var curve = deformerSplines[ j ].GetCurve();
|
|
|
|
if ( targetSmoothing > 0 )
|
|
{
|
|
var pose = curve.SmoothedPoseAt( mapping.parameter, targetSmoothing * 0.5f, 2, targetSmoothing );
|
|
vertexPosition += pose.Apply( mapping.localPosition ) * mapping.weight;
|
|
|
|
}
|
|
else
|
|
{
|
|
var pose = curve.PoseAt( mapping.parameter );
|
|
pose.ApplyTwist( curve.TwistAt( mapping.parameter ) );
|
|
vertexPosition += pose.Apply( mapping.localPosition ) * mapping.weight;
|
|
}
|
|
|
|
}
|
|
|
|
cloned.vertices[ i ] = vertexPosition;
|
|
}
|
|
|
|
// RJLog.Log( cloned.vertices.Count );
|
|
outputMesh.Mesh = cloned.GenerateMesh();
|
|
}
|
|
|
|
#if TOOLS
|
|
|
|
public void DrawGizmo( EditorNode3DGizmoPlugin gizmoPlugin, EditorNode3DGizmo gizmo )
|
|
{
|
|
|
|
gizmo.Clear();
|
|
|
|
|
|
}
|
|
|
|
public override void _Process( double delta )
|
|
{
|
|
if ( updateSourceMesh )
|
|
{
|
|
updateSourceMesh = false;
|
|
|
|
CreateSourceMappings();
|
|
}
|
|
|
|
if ( update || updateAlways )
|
|
{
|
|
update = false;
|
|
UpdateMesh();
|
|
}
|
|
|
|
UpdateGizmos();
|
|
}
|
|
|
|
void UpdateMesh()
|
|
{
|
|
if ( meshGeometry == null )
|
|
{
|
|
CreateSourceMappings();
|
|
}
|
|
|
|
if ( meshGeometry == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
CreateDeformed();
|
|
}
|
|
|
|
#endif
|
|
}
|
|
} |