Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions Assets/SplineMesh/Scripts/Bezier/CubicBezierCurve.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,19 @@ private Vector3 GetLocation(float t) {
float omt = 1f - t;
float omt2 = omt * omt;
float t2 = t * t;


// old version, before free tangents
//return
// n1.Position * (omt2 * omt) +
// n1.Direction * (3f * omt2 * t) +
// GetInverseDirection() * (3f * omt * t2) +
// n2.Position * (t2 * t);

return
n1.Position * (omt2 * omt) +
n1.Direction * (3f * omt2 * t) +
GetInverseDirection() * (3f * omt * t2) +
n1.DirectionOut * (3f * omt2 * t) +
n2.DirectionIn * (3f * omt * t2) +
n2.Position * (t2 * t);
}

Expand All @@ -100,11 +109,21 @@ private Vector3 GetTangent(float t) {
float omt = 1f - t;
float omt2 = omt * omt;
float t2 = t * t;


// old version, before free tangents
//Vector3 tangent =
// n1.Position * (-omt2) +
// n1.Direction * (3 * omt2 - 2 * omt) +
// GetInverseDirection() * (-3 * t2 + 2 * t) +
// n2.Position * (t2);

Vector3 tangent =
n1.Position * (-omt2) +
n1.Direction * (3 * omt2 - 2 * omt) +
GetInverseDirection() * (-3 * t2 + 2 * t) +
n1.DirectionOut * (3 * omt2 - 2 * omt) +
n2.DirectionIn * (-3 * t2 + 2 * t) +
n2.Position * (t2);

return tangent.normalized;
}

Expand Down
75 changes: 75 additions & 0 deletions Assets/SplineMesh/Scripts/Bezier/Spline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,81 @@ public void InsertNode(int index, SplineNode node) {
updateLoopBinding();
}

/// <summary>
/// Split the spline by adding a node at the specific time
/// the tangents of previous and following node are modified
/// in order to not alter the curve shape.
///
/// previous and next node tangent type become SplineNode.TangentType.Free
/// </summary>
/// <param name="time"></param>
public void SplitAtTime(float time)
{
if (time <= 0f || time >= (float)nodes.Count - 1)
throw new Exception(string.Format("Can't split at time {0}. Use a value between 0 and {1}", time, (float)nodes.Count - 1));

CurveSample time_sample = GetSample(time);
Vector3 new_point_position = time_sample.location;


// percent position between two nodes
float percentage = time % 1;
int index = Mathf.FloorToInt(time);

/**
* P0 = starting point
* P3 = ending point
*
* P1 = P0 control point
* P2 = mirror of P3 control point (we need the inverse, not the real cp)
*/

SplineNode starting_node = nodes[index];

Vector3 p0 = starting_node.Position;
Vector3 p1 = starting_node.DirectionOut;

SplineNode ending_node = nodes[index + 1];
Vector3 p3 = ending_node.Position;
Vector3 p2 = ending_node.DirectionIn;


// we need to find a positoin at percentage% between P0 and P1
Vector3 m0 = p0 + (p1 - p0) * percentage;
Vector3 m1 = p1 + (p2 - p1) * percentage;
Vector3 m2 = p2 + (p3 - p2) * percentage;

Vector3 q0 = m0 + (m1 - m0) * percentage;
Vector3 q1 = m1 + (m2 - m1) * percentage;

Vector3 new_point_direction_in = q0;
Vector3 new_point_direction_out = q1;

// create the new node with previous calculated params
SplineNode n = new SplineNode(new_point_position, new_point_direction_out, new_point_direction_in); //time_sample.tangent);
n.DirectionType = SplineNode.TangentType.Free;


// we also need to alter the directionOut of the previous point
// its new direction is m0
// in order to alter it, the tangent type must be free
if (nodes[index].DirectionType != SplineNode.TangentType.Free)
{
nodes[index].DirectionType = SplineNode.TangentType.Free;
}
nodes[index].DirectionOut = m0;

// we also need to alter the directionIn of the final point
// its new direction is m2
// in order to alter it, the tangent type must be free
if (nodes[index + 1].DirectionType != SplineNode.TangentType.Free)
{
nodes[index + 1].DirectionType = SplineNode.TangentType.Free;
}
nodes[index + 1].DirectionIn = m2;
InsertNode(index + 1, n);
}

/// <summary>
/// Remove the given node from the spline. The given node must exist and the spline must have more than 2 nodes.
/// </summary>
Expand Down
198 changes: 178 additions & 20 deletions Assets/SplineMesh/Scripts/Bezier/SplineNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,54 +4,189 @@
using UnityEngine;
using UnityEngine.Events;

namespace SplineMesh {
namespace SplineMesh
{
/// <summary>
/// Spline node storing a position and a direction (tangent).
/// Note : you shouldn't modify position and direction manualy but use dedicated methods instead, to insure event raising.
/// </summary>
[Serializable]
public class SplineNode {
public class SplineNode
{


/// <summary>
/// Node position
/// </summary>
public Vector3 Position {
public Vector3 Position
{
get { return position; }
set {
set
{
if (position.Equals(value)) return;
position.x = value.x;
position.y = value.y;
position.z = value.z;
if(Changed != null) Changed(this, EventArgs.Empty);
if (Changed != null) Changed(this, EventArgs.Empty);
}
}
[SerializeField]
private Vector3 position;


/// <summary>
/// Tangent vector type of the node
/// - Mirrored (default): The in and out tangent vectors are symetrical around the node.
/// - Aligned: the in and out tangent vectors are also opposed but they can have different lengths, hence different curvature
/// ( to be implemented )
/// - Free: the in and out vectors can be completly independant.
/// </summary>
public enum TangentType { Mirrored, Free };

/// <summary>
/// Node direction
/// Node tangent type
/// </summary>
public Vector3 Direction {
get { return direction; }
set {
if (direction.Equals(value)) return;
direction.x = value.x;
direction.y = value.y;
direction.z = value.z;
public TangentType DirectionType
{
get { return directionType; }
set
{
if (directionType.Equals(value)) return;
directionType = value;
if (Changed != null) Changed(this, EventArgs.Empty);
}
}

[SerializeField]
public TangentType directionType = TangentType.Mirrored;

/// <summary>
/// Node direction;
/// this parameter could be removed in a future version, use
/// directionIn / directionOut
/// USE DirectionOut and DirectionIn
/// </summary>
public Vector3 Direction
{
get
{
return DirectionOut;
}
set
{
DirectionOut = value;
}
}


[SerializeField]
private Vector3 direction;



public Vector3 DirectionIn
{
get {
/*
* for backward compatibility:
* saved nodes will have direction not zero, and directionout == Vector3.zero
*
* if this situation occurs, we update directionOut
*/

if (directionIn == Vector3.zero && direction != Vector3.zero)
{
directionIn.x = 2 * position.x - direction.x;
directionIn.y = 2 * position.y - direction.y;
directionIn.z = 2 * position.z - direction.z;
}

return directionIn;
}
set
{

if (directionIn.Equals(value)) return;
directionIn.x = value.x;
directionIn.y = value.y;
directionIn.z = value.z;


// we are setting DirectionIn, but the TangentType is mirrored:
// we need that directionOut is altered too, with the opposite value

if (directionType == TangentType.Mirrored)
{
directionOut.x = 2 * position.x - directionIn.x;
directionOut.y = 2 * position.y - directionIn.y;
directionOut.z = 2 * position.z - directionIn.z;
}


if (Changed != null) Changed(this, EventArgs.Empty);
}
}

[SerializeField]
private Vector3 directionIn;




public Vector3 DirectionOut
{
get {
/*
* for backward compatibility:
* saved nodes will have direction not zero, and directionout == Vector3.zero
*
* if this situation occurs, we update directionOut
*/

if(directionOut == Vector3.zero && direction != Vector3.zero)
{
directionOut = direction;
}

return directionOut;
}
set
{
if (directionOut.Equals(value)) return;
directionOut.x = value.x;
directionOut.y = value.y;
directionOut.z = value.z;


// we are setting DirectionOut, but the TangentType is mirrored:
// we need that directionIn is altered too, with the opposite value
if (directionType == TangentType.Mirrored)
{

directionIn.x = 2 * position.x - directionOut.x;
directionIn.y = 2 * position.y - directionOut.y;
directionIn.z = 2 * position.z - directionOut.z;

}

if (Changed != null) Changed(this, EventArgs.Empty);
}
}

[SerializeField]
private Vector3 directionOut;


/// <summary>
/// Up vector to apply at this node.
/// Usefull to specify the orientation when the tangent blend with the world UP (gimball lock)
/// This value is not used on the spline itself but is commonly used on bended content.
/// </summary>
public Vector3 Up {
public Vector3 Up
{
get { return up; }
set {
set
{
if (up.Equals(value)) return;
up.x = value.x;
up.y = value.y;
Expand All @@ -66,9 +201,11 @@ public Vector3 Up {
/// Scale to apply at this node.
/// This value is not used on the spline itself but is commonly used on bended content.
/// </summary>
public Vector2 Scale {
public Vector2 Scale
{
get { return scale; }
set {
set
{
if (scale.Equals(value)) return;
scale.x = value.x;
scale.y = value.y;
Expand All @@ -82,9 +219,11 @@ public Vector2 Scale {
/// Roll to apply at this node.
/// This value is not used on the spline itself but is commonly used on bended content.
/// </summary>
public float Roll {
public float Roll
{
get { return roll; }
set {
set
{
if (roll == value) return;
roll = value;
if (Changed != null) Changed(this, EventArgs.Empty);
Expand All @@ -93,11 +232,30 @@ public float Roll {
[SerializeField]
private float roll;

public SplineNode(Vector3 position, Vector3 direction) {
public SplineNode(Vector3 position, Vector3 direction)
{
Position = position;
Direction = direction;
}

public SplineNode(Vector3 position, Vector3 new_directionOut, Vector3 new_directionIn)
{


// this causes a side effect in DirectionOut that I could not solve
//DirectionOut = directionOut;
//DirectionIn = directionIn;

directionOut = new_directionOut;
directionIn = new_directionIn;


// due to the previous issue, we set position as last item so that the event handler is notified
Position = position;


}

/// <summary>
/// Event raised when position, direction, scale or roll changes.
/// </summary>
Expand Down
Loading