292 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C#
		
	
	
	
 | 
						|
using Godot;
 | 
						|
using Rokojori;
 | 
						|
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace Rokojori
 | 
						|
{  
 | 
						|
  public enum TubeSegmentMode
 | 
						|
  {
 | 
						|
    Fixed_Division,
 | 
						|
    Depending_On_Length,
 | 
						|
    Maximum_Of_Both,
 | 
						|
    Minimum_Of_Both
 | 
						|
  }
 | 
						|
 | 
						|
  public enum ShapeOrientationMode
 | 
						|
  {
 | 
						|
    Auto,
 | 
						|
    Original,
 | 
						|
    Reverse
 | 
						|
  }
 | 
						|
 | 
						|
  [Tool]
 | 
						|
  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Spline.svg") ]
 | 
						|
  public partial class Tube : Node3D
 | 
						|
  {
 | 
						|
    [Export]
 | 
						|
    public MeshInstance3D output;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public Spline spline;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public TubeSegmentMode segmentMode = TubeSegmentMode.Fixed_Division;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public bool useFullUVQuads = false;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public int fixedSplineSegmentDivisions = 20;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public float splineSegmentLength = 2;
 | 
						|
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public bool undistortSplineSegments = true;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public Curve twistCurve;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public float radius;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public int radialSegments = 8;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public Curve radiusSizeCurve;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public Curve radiusWidthCurve;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public Curve radiusHeightCurve;
 | 
						|
 | 
						|
    // [Export]
 | 
						|
    // public bool scaleRadiusByPathTransforms = true;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public TubeGeometrySettings settings;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public TubeShape[] shapes = new TubeShape[ 0 ];
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public bool update;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public bool updateAlways;
 | 
						|
 | 
						|
 | 
						|
  #if TOOLS
 | 
						|
    
 | 
						|
    public void DrawGizmo( EditorNode3DGizmoPlugin gizmoPlugin, EditorNode3DGizmo gizmo )
 | 
						|
    {
 | 
						|
      /*
 | 
						|
      ClearCurveCache();
 | 
						|
 | 
						|
      var curve = GetCurve();
 | 
						|
 | 
						|
      gizmo.Clear();
 | 
						|
 | 
						|
      var linePoints = new List<Vector3>();
 | 
						|
 | 
						|
      int resolution = editorResolution <= 0 ? 20 : editorResolution;
 | 
						|
 | 
						|
      renderedResolution = editorResolution;
 | 
						|
 | 
						|
      var lastPoint = ToLocal( curve.SampleAt( 0 ) );
 | 
						|
 | 
						|
      for ( int i = 1; i < resolution; i++ )
 | 
						|
      {
 | 
						|
        var t = i / (float) (resolution - 1 );
 | 
						|
        var point = ToLocal( curve.SampleAt( t ) ); 
 | 
						|
 | 
						|
        linePoints.Add( lastPoint );
 | 
						|
        linePoints.Add( point );
 | 
						|
 | 
						|
        lastPoint = point;
 | 
						|
      }
 | 
						|
 | 
						|
      for ( int i = 0; i < curve.points.Count; i++ )
 | 
						|
      {
 | 
						|
        var p = curve.points[ i ];
 | 
						|
        linePoints.Add( ToLocal( p.position ) );
 | 
						|
        linePoints.Add( ToLocal( p.tangentBefore.position ) );
 | 
						|
 | 
						|
        linePoints.Add( ToLocal( p.position ) );
 | 
						|
        linePoints.Add( ToLocal( p.tangentNext.position ) );
 | 
						|
      }
 | 
						|
 | 
						|
      var material = gizmoPlugin.GetMaterial( "main", gizmo );
 | 
						|
 | 
						|
      gizmo.AddLines( linePoints.ToArray(), material, false );
 | 
						|
 | 
						|
      */
 | 
						|
    }
 | 
						|
 | 
						|
    public override void _Process( double delta )
 | 
						|
    {
 | 
						|
      if ( ! ( updateAlways || update ) )
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      if ( spline == null )
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      update = false;
 | 
						|
 | 
						|
      
 | 
						|
      UpdateMesh();
 | 
						|
      
 | 
						|
      // this.LogInfo( "Updating mesh" );
 | 
						|
 | 
						|
      UpdateGizmos();
 | 
						|
 | 
						|
    }
 | 
						|
    
 | 
						|
  #endif
 | 
						|
 | 
						|
    public void UpdateMesh()
 | 
						|
    {
 | 
						|
      var mg = CreateMesh();
 | 
						|
 | 
						|
      if ( output == null )
 | 
						|
      {
 | 
						|
        output = this.CreateChild<MeshInstance3D>();
 | 
						|
      }
 | 
						|
 | 
						|
      output.Mesh = mg.GenerateMesh();
 | 
						|
    }
 | 
						|
 | 
						|
    MeshGeometry CreateMesh()
 | 
						|
    {
 | 
						|
      var curve = spline.GetCurve();
 | 
						|
 | 
						|
      var tubeGeometry = new TubeGeometry();
 | 
						|
      tubeGeometry.curve = curve;
 | 
						|
      tubeGeometry.settings = settings;
 | 
						|
      tubeGeometry.shapes = shapes;
 | 
						|
 | 
						|
      return tubeGeometry.CreateMesh();
 | 
						|
 | 
						|
 | 
						|
      /*
 | 
						|
      int splineSegments = fixedSplineSegmentDivisions;
 | 
						|
 | 
						|
      if ( TubeSegmentMode.Fixed_Division != segmentMode )
 | 
						|
      {
 | 
						|
        splineSegments = Mathf.CeilToInt( curve.ComputeLength( curve.points.Count * 3 ) / splineSegmentLength );
 | 
						|
 | 
						|
        if ( TubeSegmentMode.Maximum_Of_Both == segmentMode )
 | 
						|
        {
 | 
						|
          splineSegments = Mathf.Max( splineSegments, fixedSplineSegmentDivisions );
 | 
						|
        } 
 | 
						|
        if ( TubeSegmentMode.Minimum_Of_Both == segmentMode )
 | 
						|
        {
 | 
						|
          splineSegments = Mathf.Min( splineSegments, fixedSplineSegmentDivisions );
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      var shapesList = new List<TubeShape>();
 | 
						|
 | 
						|
      if ( shapes != null && shapes.Length > 0 )
 | 
						|
      {
 | 
						|
        shapesList.AddRange( shapes );
 | 
						|
        Lists.Sort( shapesList, s => s.tubePosition );
 | 
						|
 | 
						|
        shapesList.ForEach( s => s.ClearCache() );
 | 
						|
        
 | 
						|
      }
 | 
						|
 | 
						|
      
 | 
						|
      var mg = MeshGeometry.CreateFromUVFunction(
 | 
						|
        ( Vector2 uv ) =>
 | 
						|
        {
 | 
						|
          var t = undistortSplineSegments ? curve.ComputeTforNormalizedCurveLength( uv.Y, splineSegments ) : uv.Y;
 | 
						|
          var index = curve.NormalizedToPointIndex( t );
 | 
						|
          var pose = curve.PoseAt( t );        
 | 
						|
          var radiusSize = radius * ( radiusSizeCurve == null ? 1 : radiusSizeCurve.Sample( t ) );
 | 
						|
          var sizeX = radiusSize;
 | 
						|
          var sizeY = radiusSize;
 | 
						|
          var twistOffset = 0f;
 | 
						|
 | 
						|
          if ( radiusWidthCurve != null )
 | 
						|
          {
 | 
						|
            sizeX *= radiusWidthCurve.Sample( t );
 | 
						|
          }
 | 
						|
 | 
						|
          if ( radiusHeightCurve != null )
 | 
						|
          {
 | 
						|
            sizeY *= radiusHeightCurve.Sample( t );
 | 
						|
          }
 | 
						|
 | 
						|
          if ( scaleRadiusByPathTransforms )
 | 
						|
          {
 | 
						|
            
 | 
						|
            var splineScale = curve.SmoothStepScaleByPointIndex( index );
 | 
						|
 | 
						|
            if ( scaleRadiusByPathTransforms )
 | 
						|
            {
 | 
						|
              sizeX *= splineScale.X;
 | 
						|
              sizeY *= splineScale.Y;
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          if ( twistCurve != null )
 | 
						|
          {
 | 
						|
            twistOffset = Mathf.DegToRad( twistCurve.Sample( t ) );
 | 
						|
          }
 | 
						|
 | 
						|
          twistOffset += Mathf.DegToRad( curve.SmoothStepTwistByPointIndex( index ) * 360 );
 | 
						|
 | 
						|
          var twistRotation = Math3D.RotateZ( twistOffset ).Normalized();
 | 
						|
 | 
						|
          var scale = new Vector3( sizeX, sizeY, 0 );
 | 
						|
 | 
						|
          if ( shapesList.Count > 0 )
 | 
						|
          { 
 | 
						|
            if ( shapesList.Count == 1 )
 | 
						|
            {
 | 
						|
              return shapesList[ 0 ].GetPose( undistortSplineSegments, splineSegments, radialSegments, pose, uv, scale, twistRotation );
 | 
						|
            }
 | 
						|
 | 
						|
            var lerpResult = Lists.LerpIndex( shapesList, uv.Y, s => s.tubePosition );
 | 
						|
 | 
						|
 | 
						|
            var closestShape = shapesList[ lerpResult.closestIndex ];
 | 
						|
            var secondShape  = shapesList[ lerpResult.secondIndex ];
 | 
						|
 | 
						|
            var closestPose = closestShape.GetPose( undistortSplineSegments, splineSegments, radialSegments, pose, uv, scale, twistRotation );
 | 
						|
            var secondPose  = secondShape.GetPose( undistortSplineSegments, splineSegments, radialSegments, pose, uv, scale, twistRotation );
 | 
						|
 | 
						|
            var smoothLerp = Mathf.SmoothStep( 0f, 1f, lerpResult.lerpAmount );
 | 
						|
            return Pose.Lerp( closestPose, secondPose, smoothLerp );
 | 
						|
            
 | 
						|
          }          
 | 
						|
          else 
 | 
						|
          {
 | 
						|
            var angle = uv.X * 2f * Mathf.Pi * ( sizeX / sizeY );
 | 
						|
            var circlePose = Pose.Create( Vector3.Zero, pose.rotation * Math3D.RotateZ( angle ) );
 | 
						|
            var circleStart = Vector3.Up * radiusSize * scale;
 | 
						|
 | 
						|
            var positionOnCircle = circlePose.Apply( circleStart );
 | 
						|
 | 
						|
            return Pose.Create( positionOnCircle + pose.position, circlePose.rotation );
 | 
						|
          }
 | 
						|
 | 
						|
        }, 
 | 
						|
        radialSegments, splineSegments, useFullUVQuads 
 | 
						|
      );
 | 
						|
 | 
						|
      return mg;
 | 
						|
      */
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
} |