initial commit

This commit is contained in:
Jo 2025-01-07 02:06:59 +01:00
parent 6715289efe
commit 788c3389af
37645 changed files with 2526849 additions and 80 deletions

View file

@ -0,0 +1,12 @@
using Unity.Splines.Examples;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(AnimateCarAlongSpline))]
public class AnimateCarAlongSplineEditor : Editor
{
void OnEnable()
{
((AnimateCarAlongSpline)target).Initialize();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b2f7adbf743913a4ea009f06573bd6bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,70 @@
using System;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using UnityEngine.Splines;
namespace Unity.Splines.Examples
{
[CustomEditor(typeof(DisplayCurvatureOnSpline))]
public class DisplayCurvatureOnSplineEditor : UnityEditor.Editor
{
void OnSceneGUI()
{
var displayScript = ( (DisplayCurvatureOnSpline)target );
var curvatureTimes = displayScript.m_CurvatureTimes;
var container = displayScript.container;
if(container.Spline == null || Event.current.type != EventType.Repaint)
return;
using var nativeSpline = new NativeSpline(container.Spline, container.transform.localToWorldMatrix);
foreach(var config in curvatureTimes)
{
if(!config.display)
continue;
var t = math.clamp(config.time, 0f, 1f);
if(container.transform.lossyScale != Vector3.one)
{
//Convert t to be the same for the spline and the spline data in case
//a scale is applied on the SplineContainer GameObject
var curveIndex = container.Spline.SplineToCurveT(t, out float curveT);
t = nativeSpline.CurveToSplineT(curveIndex + curveT);
}
//Compute Spline Position in World Space
var nativeSplinePos = nativeSpline.EvaluatePosition(t);
//Compute Curvature at t, Curvature k = 1/radius
var curvature = nativeSpline.EvaluateCurvature(t);
//Compute the curvature center = i.e the center point of the tangent circle at the spline at t
var curvatureCenter = nativeSpline.EvaluateCurvatureCenter(t);
//Computing signed curvature :
//Evaluate on which side of the spline is the curvature bending
var up = nativeSpline.EvaluateUpVector(t);
var velocity = nativeSpline.EvaluateTangent(t);
var acceleration = nativeSpline.EvaluateAcceleration(t);
var curvatureUp = math.normalize(math.cross(acceleration, velocity));
var c = curvature * math.sign(math.dot(up, curvatureUp));
c = math.clamp(5f* c, -1f, 1f);
var curvatureColor = new Color(
c < 0 ? c + 1 : 1,
math.abs(c),
c < 0 ? 1 : 1 - c);
using(new Handles.DrawingScope(curvatureColor))
Handles.DrawSolidDisc(curvatureCenter, curvatureUp, math.length(curvatureCenter - nativeSplinePos));
using(new Handles.DrawingScope(Color.black))
Handles.SphereHandleCap(-1, nativeSplinePos, Quaternion.identity, 0.15f * HandleUtility.GetHandleSize(nativeSplinePos), EventType.Repaint);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98e3ce8b481f2794eafb225cb351c182
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,20 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Unity.Splines.Examples.Editor
{
[CustomEditor(typeof(LoftRoadBehaviour))]
class RoadTool : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
base.OnInspectorGUI();
if (EditorGUI.EndChangeCheck())
((LoftRoadBehaviour)target).Loft();
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b853bdae9b934578bcdc53c189a69514
timeCreated: 1617911316

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d201921c91066614f860be50a2824614
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,146 @@
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.Splines;
using UnityEngine;
using UnityEngine.Splines;
using Interpolators = UnityEngine.Splines.Interpolators;
namespace Unity.Splines.Examples
{
[EditorTool("Border Tool", typeof(SpawnWithinSplineBounds))]
public class BorderTool : SplineDataToolBase<float>, IDrawSelectedHandles
{
const float k_HandleOffset = 2f;
const float k_LineLengthsSize = 4f;
const int k_SamplesPerCurve = 15;
List<Vector3> m_LineSegments = new List<Vector3>();
GUIContent m_IconContent;
public override GUIContent toolbarIcon => m_IconContent;
void OnEnable()
{
m_IconContent = new GUIContent()
{
image = Resources.Load<Texture2D>("Icons/BorderTool"),
text = "Border Tool",
tooltip = "Define the border limit of the area defined by the spline."
};
}
public override void OnToolGUI(EditorWindow window)
{
var splineDataTarget = target as SpawnWithinSplineBounds;
var nativeSpline = new NativeSpline(splineDataTarget.splineContainer.Spline, splineDataTarget.splineContainer.transform.localToWorldMatrix);
Undo.RecordObject(splineDataTarget,"Modifying Border SplineData");
Handles.color = Color.yellow;
//User defined : Handles to manipulate Border data
DrawDataPoints(nativeSpline, splineDataTarget.spawnBorderData);
//Use defined : Draws a line along the whole Border SplineData
DrawSplineData(nativeSpline, splineDataTarget.spawnBorderData);
//Using the out-of the box behaviour to manipulate SplineData indexes
nativeSpline.DataPointHandles(splineDataTarget.spawnBorderData);
}
public void OnDrawHandles()
{
var splineDataTarget = target as SpawnWithinSplineBounds;
if(ToolManager.IsActiveTool(this) || splineDataTarget.splineContainer == null)
return;
//Reduce number of time we have to convert spline To NativeSpline
if(Event.current.type != EventType.Repaint)
return;
var nativeSpline = new NativeSpline(splineDataTarget.splineContainer.Spline, splineDataTarget.splineContainer.transform.localToWorldMatrix);
Color color = Color.yellow;
color.a = 0.5f;
Handles.color = color;
DrawSplineData(nativeSpline,splineDataTarget.spawnBorderData);
}
protected override bool DrawDataPoint(
Vector3 position,
Vector3 tangent,
Vector3 up,
float inValue,
out float outValue)
{
var controlID = GUIUtility.GetControlID(FocusType.Passive);
outValue = inValue;
var handleColor = Handles.color;
if(GUIUtility.hotControl == 0 && HandleUtility.nearestControl == controlID)
handleColor = Handles.preselectionColor;
var right = Vector3.Cross(tangent.normalized, up.normalized);
var borderPos = position + right * inValue;
var size = k_HandleSize * HandleUtility.GetHandleSize(borderPos);
var sliderOffset = GetBorderHandleOffset(borderPos);
var handleMatrix = Handles.matrix * Matrix4x4.TRS(sliderOffset, Quaternion.identity, Vector3.one);
var inUse = false;
using (new Handles.DrawingScope(handleColor, handleMatrix))
{
EditorGUI.BeginChangeCheck();
var newBorderPos = Handles.Slider(controlID, borderPos, right, size, Handles.RectangleHandleCap, 0f);
if (EditorGUI.EndChangeCheck())
{
var delta = newBorderPos - borderPos;
outValue = Mathf.Max(0f, inValue + (Vector3.Dot(right, delta) > 0 ? delta.magnitude : -delta.magnitude));
inUse = true;
}
}
return inUse;
}
void DrawSplineData(
ISpline spline,
SplineData<float> splineData)
{
m_LineSegments.Clear();
var curveCount = spline.Closed ? spline.Count : spline.Count - 1;
var stepSize = 1f / k_SamplesPerCurve;
var prevBorderPos = Vector3.zero;
for (int curveIndex = 0; curveIndex < curveCount; ++curveIndex)
{
for (int step = 0; step < k_SamplesPerCurve; ++step)
{
var splineTime = spline.CurveToSplineT(curveIndex + step * stepSize);
spline.Evaluate(splineTime, out var position, out var tangent, out var upVector);
var right = math.cross(math.normalize(tangent), upVector);
var border = splineData.Evaluate(spline, splineTime, PathIndexUnit.Normalized, new Interpolators.LerpFloat());
var borderPos = position + right * border;
borderPos += (float3) GetBorderHandleOffset(borderPos);
if (curveIndex > 0 || step > 0)
{
m_LineSegments.Add(prevBorderPos);
m_LineSegments.Add(borderPos);
}
prevBorderPos = borderPos;
}
}
Handles.DrawDottedLines(m_LineSegments.ToArray(), k_LineLengthsSize);
}
Vector3 GetBorderHandleOffset(Vector3 borderPos)
{
var size = k_HandleSize * HandleUtility.GetHandleSize(borderPos);
return Vector3.up * size * k_HandleOffset;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 587e928622d803146a2c2b07253c78e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,163 @@
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.Splines;
using UnityEngine;
using UnityEngine.Splines;
using Interpolators = UnityEngine.Splines.Interpolators;
namespace Unity.Splines.Examples
{
[EditorTool("Drift Tool", typeof(DriftSplineData))]
public class DriftTool : SplineDataToolBase<float>, IDrawSelectedHandles
{
float m_DisplaySpace = 0.2f;
List<Vector3> m_LineSegments = new List<Vector3>();
GUIContent m_IconContent;
public override GUIContent toolbarIcon => m_IconContent;
bool m_DriftInUse;
void OnEnable()
{
m_IconContent = new GUIContent()
{
image = Resources.Load<Texture2D>("Icons/DriftTool"),
text = "Drift Tool",
tooltip = "Adjust how much the vehicle is drifting away from the spline."
};
}
public override void OnToolGUI(EditorWindow window)
{
var splineDataTarget = target as DriftSplineData;
if(splineDataTarget == null || splineDataTarget.container == null)
return;
Undo.RecordObject(splineDataTarget,"Modifying Drift SplineData");
var nativeSpline = new NativeSpline(splineDataTarget.container.Spline, splineDataTarget.container.transform.localToWorldMatrix);
Handles.color = Color.green;
//User defined : Handles to manipulate Drift data
m_DriftInUse = DrawDataPoints(nativeSpline, splineDataTarget.drift);
//Use defined : Draws a line along the whole Drift SplineData
DrawSplineData(nativeSpline, splineDataTarget.drift);
//Using the out-of the box behaviour to manipulate SplineData indexes
nativeSpline.DataPointHandles(splineDataTarget.drift);
}
public void OnDrawHandles()
{
var splineDataTarget = target as DriftSplineData;
if(ToolManager.IsActiveTool(this) || splineDataTarget.container == null)
return;
if(Event.current.type != EventType.Repaint)
return;
var nativeSpline = new NativeSpline(splineDataTarget.container.Spline, splineDataTarget.container.transform.localToWorldMatrix);
Color color = Color.green;
color.a = 0.5f;
Handles.color = color;
DrawSplineData(nativeSpline,splineDataTarget.drift);
}
protected override bool DrawDataPoint(
Vector3 position,
Vector3 tangent,
Vector3 up,
float inValue,
out float outValue)
{
outValue = 0f;
if(tangent == Vector3.zero)
return false;
var controlID = GUIUtility.GetControlID(FocusType.Passive);
var handleColor = Handles.color;
if(GUIUtility.hotControl == controlID)
handleColor = Handles.selectedColor;
else if(GUIUtility.hotControl == 0 && HandleUtility.nearestControl==controlID)
handleColor = Handles.preselectionColor;
var right = math.normalize(math.cross(up, tangent));
var extremity = position + inValue * (Vector3)right;
using(new Handles.DrawingScope(handleColor))
{
var size = 1.5f * k_HandleSize * HandleUtility.GetHandleSize(position);
Handles.DrawLine(position, extremity);
var val = Handles.Slider(
controlID,
extremity,
inValue == 0 ? right : right*math.sign(inValue),
size,
Handles.ConeHandleCap,
0);
Handles.Label(extremity + 2f * size * Vector3.up, inValue.ToString());
if(GUIUtility.hotControl == controlID)
{
outValue = (val - position).magnitude * math.sign(math.dot(val - position, right));
return true;
}
}
return false;
}
void DrawSplineData(NativeSpline spline, SplineData<float> splineData)
{
m_LineSegments.Clear();
if(GUIUtility.hotControl == 0
|| m_DriftInUse
|| !ToolManager.IsActiveTool(this)
|| Tools.viewToolActive)
{
var data = splineData.Evaluate(spline, 0, PathIndexUnit.Distance, new Interpolators.LerpFloat());
spline.Evaluate(0, out var position, out var direction, out var upDirection);
var right = math.normalize(math.cross(upDirection, direction));
var previousExtremity = (Vector3)position + data * (Vector3)right;
var currentOffset = m_DisplaySpace;
while(currentOffset < spline.GetLength())
{
var t = currentOffset / spline.GetLength();
spline.Evaluate(t, out position, out direction, out upDirection);
right = math.normalize(math.cross(upDirection, direction));
data = splineData.Evaluate(spline, currentOffset, PathIndexUnit.Distance, new Interpolators.LerpFloat());
var extremity = (Vector3)position + data * (Vector3)right;
m_LineSegments.Add(previousExtremity);
m_LineSegments.Add(extremity);
currentOffset += m_DisplaySpace;
previousExtremity = extremity;
}
spline.Evaluate(1, out position, out direction, out upDirection);
right = math.normalize(math.cross(upDirection, direction));
data = splineData.Evaluate(spline, 1f, PathIndexUnit.Normalized, new Interpolators.LerpFloat());
var lastExtremity = (Vector3)position + data * (Vector3)right;
m_LineSegments.Add(previousExtremity);
m_LineSegments.Add(lastExtremity);
}
Handles.DrawLines(m_LineSegments.ToArray());
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a02b7ee8b850af34e906a2a59186f9ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9da031aacf1c1d649934f9377349661d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,46 @@
using System;
using UnityEditor;
using UnityEditor.Toolbars;
using UnityEngine;
namespace Unity.Splines.Examples
{
[EditorToolbarElement("SpeedTiltTool/SplineDataType")]
public class SpeedTiltDropdown : EditorToolbarDropdown
{
string[] m_SplineDataTypes = new []
{
SpeedTiltTool.SplineDataType.SpeedData.ToString(),
SpeedTiltTool.SplineDataType.TiltData.ToString()
};
public string k_Tooltip = "Select the SplineData to target for interactions.";
public SpeedTiltDropdown()
{
name = "SplineData Target Type";
clicked += OpenContextMenu;
text = m_SplineDataTypes[(int)SpeedTiltTool.selectedSplineData];
}
void OpenContextMenu()
{
var menu = new GenericMenu();
for(int i = 0; i< m_SplineDataTypes.Length; i++)
{
var index = i;
var component = m_SplineDataTypes[i];
menu.AddItem(new GUIContent(component, k_Tooltip), text == component,
() => SetSelectedComponent(index));
}
menu.DropDown(worldBound);
}
void SetSelectedComponent(int selectedIndex)
{
text = m_SplineDataTypes[selectedIndex];
SpeedTiltTool.selectedSplineData = (SpeedTiltTool.SplineDataType)selectedIndex;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d4c650b6f99c0d149be6ca04cbb10e7e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,102 @@
using UnityEditor;
using UnityEditor.Splines;
using UnityEngine;
using UnityEngine.Splines;
using Unity.Mathematics;
using UnityEditor.EditorTools;
namespace Unity.Splines.Examples
{
[EditorTool("LookAtPoint Tool", typeof(PointSplineData))]
public class LookAtTool : SplineDataToolBase<float2>, IDrawSelectedHandles
{
GUIContent m_IconContent;
public override GUIContent toolbarIcon => m_IconContent;
bool m_DisableHandles;
void OnEnable()
{
m_IconContent = new GUIContent()
{
image = Resources.Load<Texture2D>("Icons/LookAtTool"),
text = "LookAt Tool",
tooltip = "Adjust the LookAt DataPoint along the spline."
};
}
public override void OnToolGUI(EditorWindow window)
{
var splineDataTarget = target as PointSplineData;
if(splineDataTarget == null || splineDataTarget.container == null)
return;
var nativeSpline = new NativeSpline(splineDataTarget.container.Spline, splineDataTarget.container.transform.localToWorldMatrix);
Handles.color = Color.yellow;
m_DisableHandles = false;
Undo.RecordObject(splineDataTarget,"Modifying LookAt SplineData");
//User defined : Handles to manipulate LookAtPoint data
DrawDataPoints(nativeSpline, splineDataTarget.points);
//Using the out-of the box behaviour to manipulate SplineData indexes
nativeSpline.DataPointHandles(splineDataTarget.points);
}
public void OnDrawHandles()
{
var splineDataTarget = target as PointSplineData;
if(ToolManager.IsActiveTool(this) || splineDataTarget.container == null)
return;
if(Event.current.type != EventType.Repaint)
return;
var nativeSpline = new NativeSpline(splineDataTarget.container.Spline, splineDataTarget.container.transform.localToWorldMatrix);
Color color = Color.yellow;
color.a = 0.5f;
Handles.color = color;
m_DisableHandles = true;
DrawDataPoints(nativeSpline,splineDataTarget.points);
}
protected override bool DrawDataPoint(
Vector3 position,
Vector3 tangent,
Vector3 up,
float2 inValue,
out float2 outValue)
{
var controlID = m_DisableHandles ? -1 : GUIUtility.GetControlID(FocusType.Passive);
outValue = float2.zero;
var handleColor = Handles.color;
if(GUIUtility.hotControl == 0
&& HandleUtility.nearestControl!= -1
&& HandleUtility.nearestControl == controlID)
handleColor = Handles.preselectionColor;
var pointValue = new float3(inValue.x, 0f, inValue.y);
var size = k_HandleSize * HandleUtility.GetHandleSize(pointValue);
using (new Handles.DrawingScope(handleColor))
{
EditorGUI.BeginChangeCheck();
Handles.DrawLine(position, pointValue);
var newPointValue = (float3)Handles.Slider2D(controlID, pointValue, -Vector3.up, Vector3.right, Vector3.forward, size, Handles.ConeHandleCap, Vector2.zero, true);
if (EditorGUI.EndChangeCheck())
{
var delta = newPointValue - pointValue;
outValue = inValue + new float2(delta.x, delta.z);
return true;
}
}
return false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e81ed8fed864d88408649c082a9924bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,406 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Mathematics;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.Splines;
using UnityEngine;
using UnityEngine.Splines;
#if UNITY_2022_1_OR_NEWER
using UnityEditor.Overlays;
#else
using System.Reflection;
using UnityEditor.Toolbars;
using UnityEngine.UIElements;
#endif
using Interpolators = UnityEngine.Splines.Interpolators;
namespace Unity.Splines.Examples
{
[CustomEditor(typeof(SpeedTiltTool))]
#if UNITY_2022_1_OR_NEWER
class SplineDataPointToolSettings : UnityEditor.Editor, ICreateToolbar
#else
class SplineDataPointToolSettings : UnityEditor.Editor
#endif
{
public virtual IEnumerable<string> toolbarElements
{
get
{
yield return "Tool Settings/Pivot Mode";
yield return "Tool Settings/Pivot Rotation";
yield return "SpeedTiltTool/SplineDataType";
}
}
#if !UNITY_2022_1_OR_NEWER
const string k_ElementClassName = "unity-editor-toolbar-element";
const string k_StyleSheetsPath = "StyleSheets/Toolbars/";
static VisualElement CreateToolbar()
{
var target = new VisualElement();
var path = k_StyleSheetsPath + "EditorToolbar";
var common = EditorGUIUtility.Load($"{path}Common.uss") as StyleSheet;
if (common != null)
target.styleSheets.Add(common);
var themeSpecificName = EditorGUIUtility.isProSkin ? "Dark" : "Light";
var themeSpecific = EditorGUIUtility.Load($"{path}{themeSpecificName}.uss") as StyleSheet;
if (themeSpecific != null)
target.styleSheets.Add(themeSpecific);
target.AddToClassList("unity-toolbar-overlay");
target.style.flexDirection = FlexDirection.Row;
return target;
}
public override VisualElement CreateInspectorGUI()
{
var root = CreateToolbar();
var elements = TypeCache.GetTypesWithAttribute(typeof(EditorToolbarElementAttribute));
foreach (var element in toolbarElements)
{
var type = elements.FirstOrDefault(x =>
{
var attrib = x.GetCustomAttribute<EditorToolbarElementAttribute>();
return attrib != null && attrib.id == element;
});
if (type != null)
{
try
{
const BindingFlags flags = BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.CreateInstance;
var ve = (VisualElement)Activator.CreateInstance(type, flags, null, null, null, null);
ve.AddToClassList(k_ElementClassName);
root.Add(ve);
}
catch (Exception e)
{
Debug.LogError($"Failed creating toolbar element from ID \"{element}\".\n{e}");
}
}
}
EditorToolbarUtility.SetupChildrenAsButtonStrip(root);
return root;
}
#endif
}
[EditorTool("Speed & Tilt Tool", typeof(AnimateCarAlongSpline))]
public class SpeedTiltTool : EditorTool, IDrawSelectedHandles
{
internal enum SplineDataType
{
SpeedData,
TiltData
};
//Speed handles parameters
const float k_SpeedScaleFactor = 10f;
const float k_DisplaySpace = 0.5f;
//Tilt handles parameters
Quaternion m_StartingRotation;
const float k_HandleSize = 0.15f;
Color[] m_HandlesColors = {Color.red, new (1f,0.6f,0f)};
List<Vector3> m_LineSegments = new List<Vector3>();
static SplineDataType s_SelectedSplineData = SplineDataType.SpeedData;
internal static SplineDataType selectedSplineData
{
get => s_SelectedSplineData;
set => s_SelectedSplineData = value;
}
GUIContent m_IconContent;
public override GUIContent toolbarIcon => m_IconContent;
bool m_DisableHandles;
bool m_SpeedInUse;
bool m_TiltInUse;
void OnEnable()
{
m_IconContent = new GUIContent()
{
image = Resources.Load<Texture2D>("Icons/SpeedTiltTool"),
text = "Speed & Tilt Tool",
tooltip = "Adjust the vehicle speed and tilt DataPoints along the spline."
};
}
public override void OnToolGUI(EditorWindow window)
{
var splineDataTarget = target as AnimateCarAlongSpline;
if(splineDataTarget == null || splineDataTarget.splineContainer == null)
return;
var nativeSpline = new NativeSpline(splineDataTarget.splineContainer.Spline, splineDataTarget.splineContainer.transform.localToWorldMatrix);
Undo.RecordObject(splineDataTarget, "Modifying Speed and Tilt SplineData");
m_DisableHandles = false;
//Speed handles section
Handles.color = m_HandlesColors[(int)SplineDataType.SpeedData];
//User defined : Handles to manipulate Speed data
m_SpeedInUse = DrawSpeedDataPoints(nativeSpline, splineDataTarget.speed, splineDataTarget.m_MaxSpeed, true);
//Use defined : Draws a line along the whole Speed SplineData
DrawSpeedSplineData(nativeSpline, splineDataTarget.speed);
//Tilt handles section
Handles.color = m_HandlesColors[(int)SplineDataType.TiltData];
//User defined : Handles to manipulate Tilt data
m_TiltInUse = DrawTiltDataPoints(nativeSpline, splineDataTarget.tilt);
//Use defined : Draws a line along the whole Tilt SplineData
DrawTiltSplineData(nativeSpline, splineDataTarget.tilt);
//Draw DataPoint default Manipulation handles
Handles.color = m_HandlesColors[(int)s_SelectedSplineData];
if(s_SelectedSplineData == SplineDataType.SpeedData)
nativeSpline.DataPointHandles(splineDataTarget.speed);
else
nativeSpline.DataPointHandles(splineDataTarget.tilt);
}
public void OnDrawHandles()
{
var splineDataTarget = target as AnimateCarAlongSpline;
if(ToolManager.IsActiveTool(this) || splineDataTarget.splineContainer == null)
return;
if(Event.current.type != EventType.Repaint)
return;
m_DisableHandles = true;
var nativeSpline = new NativeSpline(splineDataTarget.splineContainer.Spline, splineDataTarget.splineContainer.transform.localToWorldMatrix);
Color color = m_HandlesColors[(int)SplineDataType.SpeedData];
color.a = 0.5f;
Handles.color = color;
DrawSpeedDataPoints(nativeSpline, splineDataTarget.speed, splineDataTarget.m_MaxSpeed, false);
DrawSpeedSplineData(nativeSpline, splineDataTarget.speed);
color = m_HandlesColors[(int)SplineDataType.TiltData];
color.a = 0.5f;
Handles.color = color;
DrawTiltSplineData(nativeSpline,splineDataTarget.tilt);
}
bool DrawSpeedDataPoints(NativeSpline spline, SplineData<float> speedSplineData, float maxSpeed, bool drawLabel)
{
var inUse = false;
for(int dataFrameIndex = 0; dataFrameIndex < speedSplineData.Count; dataFrameIndex++)
{
var dataPoint = speedSplineData[dataFrameIndex];
var normalizedT = SplineUtility.GetNormalizedInterpolation(spline, dataPoint.Index, speedSplineData.PathIndexUnit);
var position = spline.EvaluatePosition(normalizedT);
var speedValue = dataPoint.Value;
if(speedValue > maxSpeed)
{
speedValue = maxSpeed;
dataPoint.Value = maxSpeed;
speedSplineData[dataFrameIndex] = dataPoint;
}
var id = m_DisableHandles ? -1 : GUIUtility.GetControlID(FocusType.Passive);
if(DrawSpeedDataPoint(id, position, speedValue, drawLabel, out var result))
{
dataPoint.Value = Mathf.Clamp(result, 0.01f, maxSpeed);
speedSplineData[dataFrameIndex] = dataPoint;
inUse = true;
}
}
return inUse;
}
bool DrawSpeedDataPoint(
int controlID,
Vector3 position,
float inValue,
bool drawLabel,
out float outValue)
{
outValue = 0f;
var handleColor = Handles.color;
if(GUIUtility.hotControl == controlID)
handleColor = Handles.selectedColor;
else if(GUIUtility.hotControl == 0 && HandleUtility.nearestControl==controlID)
handleColor = Handles.preselectionColor;
var extremity = position + (inValue / k_SpeedScaleFactor) * Vector3.up;
using(new Handles.DrawingScope(handleColor))
{
var size = k_HandleSize * HandleUtility.GetHandleSize(position);
Handles.DrawLine(position, extremity);
var val = Handles.Slider(controlID, extremity, Vector3.up, size, Handles.SphereHandleCap, 0);
if(drawLabel)
Handles.Label(extremity + 2f * size * Vector3.up, inValue.ToString());
if(GUIUtility.hotControl == controlID)
{
outValue = k_SpeedScaleFactor * (val - position).magnitude * math.sign(math.dot(val - position, Vector3.up));
return true;
}
}
return false;
}
bool DrawTiltDataPoints(NativeSpline spline, SplineData<float3> tiltSplineData)
{
var inUse = false;
for(int dataFrameIndex = 0; dataFrameIndex < tiltSplineData.Count; dataFrameIndex++)
{
var dataPoint = tiltSplineData[dataFrameIndex];
var normalizedT = SplineUtility.GetNormalizedInterpolation(spline, dataPoint.Index, tiltSplineData.PathIndexUnit);
spline.Evaluate(normalizedT, out var position, out var tangent, out var up);
var id = m_DisableHandles ? -1 : GUIUtility.GetControlID(FocusType.Passive);
if(DrawTiltDataPoint(id, position, tangent, up, dataPoint.Value, out var result))
{
dataPoint.Value = result;
tiltSplineData[dataFrameIndex] = dataPoint;
inUse = true;
}
}
return inUse;
}
bool DrawTiltDataPoint(
int controlID,
Vector3 position,
Vector3 tangent,
Vector3 up,
float3 inValue,
out float3 outValue)
{
outValue = float3.zero;
if(tangent == Vector3.zero)
return false;
Matrix4x4 localMatrix = Matrix4x4.identity;
localMatrix.SetTRS(position, Quaternion.LookRotation(tangent, up), Vector3.one);
var matrix = Handles.matrix * localMatrix;
using(new Handles.DrawingScope(matrix))
{
var dataPointRotation = Quaternion.FromToRotation(Vector3.up, inValue);
if(GUIUtility.hotControl == 0)
m_StartingRotation = dataPointRotation;
var color = Handles.color;
if(!m_TiltInUse)
color.a = 0.33f;
using(new Handles.DrawingScope(color))
Handles.ArrowHandleCap(-1, Vector3.zero, Quaternion.FromToRotation(Vector3.forward, inValue), 1f, EventType.Repaint);
var rotation = Handles.Disc(controlID, dataPointRotation, Vector3.zero, Vector3.forward, 1, false, 0);
if(GUIUtility.hotControl == controlID)
{
var deltaRot = Quaternion.Inverse(m_StartingRotation) * rotation;
outValue = deltaRot * m_StartingRotation * Vector3.up;
return true;
}
}
return false;
}
void DrawSpeedSplineData(NativeSpline spline, SplineData<float> splineData)
{
m_LineSegments.Clear();
if(GUIUtility.hotControl == 0
|| m_SpeedInUse
|| !ToolManager.IsActiveTool(this)
|| Tools.viewToolActive)
{
var data = splineData.Evaluate(spline, 0, PathIndexUnit.Distance, new Interpolators.LerpFloat());
var position = spline.EvaluatePosition(0);
var previousExtremity = (Vector3)position + ( data / k_SpeedScaleFactor ) * Vector3.up;
var currentOffset = k_DisplaySpace;
while(currentOffset < spline.GetLength())
{
var t = currentOffset / spline.GetLength();
position = spline.EvaluatePosition(t);
data = splineData.Evaluate(spline, currentOffset, PathIndexUnit.Distance, new Interpolators.LerpFloat());
var extremity = (Vector3)position + ( data / k_SpeedScaleFactor ) * Vector3.up;
m_LineSegments.Add(previousExtremity);
m_LineSegments.Add(extremity);
currentOffset += k_DisplaySpace;
previousExtremity = extremity;
}
position = spline.EvaluatePosition(1);
data = splineData.Evaluate(spline, spline.GetLength(), PathIndexUnit.Distance, new Interpolators.LerpFloat());
var lastExtremity = (Vector3)position + ( data / k_SpeedScaleFactor ) * Vector3.up;
m_LineSegments.Add(previousExtremity);
m_LineSegments.Add(lastExtremity);
}
Handles.DrawLines(m_LineSegments.ToArray());
}
void DrawTiltSplineData(NativeSpline spline, SplineData<float3> splineData)
{
m_LineSegments.Clear();
if(GUIUtility.hotControl == 0
|| m_TiltInUse
|| !ToolManager.IsActiveTool(this)
|| Tools.viewToolActive)
{
var currentOffset = k_DisplaySpace;
while(currentOffset < spline.GetLength())
{
var t = currentOffset / spline.GetLength();
spline.Evaluate(t, out float3 position, out float3 direction, out float3 up);
var data = splineData.Evaluate(spline, t, PathIndexUnit.Normalized,
new Interpolators.LerpFloat3());
Matrix4x4 localMatrix = Matrix4x4.identity;
localMatrix.SetTRS(position, Quaternion.LookRotation(direction, up), Vector3.one);
m_LineSegments.Add(localMatrix.GetPosition());
m_LineSegments.Add(localMatrix.MultiplyPoint(math.normalize(data)));
currentOffset += k_DisplaySpace;
}
}
var color = Handles.color;
if(!m_TiltInUse)
color.a = 0.33f;
using(new Handles.DrawingScope(color))
Handles.DrawLines(m_LineSegments.ToArray());
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 13191b70b1bbf4348a215f42c3e852cf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,47 @@
using UnityEditor.EditorTools;
using UnityEngine;
using UnityEngine.Splines;
namespace Unity.Splines.Examples
{
public abstract class SplineDataToolBase<DataType> : EditorTool
{
protected const float k_HandleSize = 0.15f;
protected bool DrawDataPoints(ISpline spline, SplineData<DataType> splineData)
{
var inUse = false;
for(int dataFrameIndex = 0; dataFrameIndex < splineData.Count; dataFrameIndex++)
{
var dataPoint = splineData[dataFrameIndex];
var normalizedT = SplineUtility.GetNormalizedInterpolation(spline, dataPoint.Index, splineData.PathIndexUnit);
spline.Evaluate(normalizedT, out var position, out var tangent, out var up);
if(DrawDataPoint(position, tangent, up, dataPoint.Value, out var result))
{
dataPoint.Value = result;
splineData[dataFrameIndex] = dataPoint;
inUse = true;
}
}
return inUse;
}
/// <summary>
/// User defined method, for simplicity here, all the SplineData Tools have to override the same DrawDataPoint method for consistency between tools
/// </summary>
/// <param name="position"></param>
/// <param name="tangent"></param>
/// <param name="up"></param>
/// <param name="inValue"></param>
/// <param name="outValue"></param>
/// <returns>True if the dataPoint is manipulated, else false.</returns>
protected abstract bool DrawDataPoint(
Vector3 position,
Vector3 tangent,
Vector3 up,
DataType inValue,
out DataType outValue);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: af7617c1ec3b5f94fb17427d7465e15b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,125 @@
using Unity.Mathematics;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.Splines;
using UnityEngine;
using UnityEngine.Splines;
namespace Unity.Splines.Examples
{
[EditorTool("Width Tool", typeof(WidthSplineData))]
public class WidthTool : SplineDataToolBase<float>, IDrawSelectedHandles
{
GUIContent m_IconContent;
public override GUIContent toolbarIcon => m_IconContent;
bool m_DisableHandles = false;
void OnEnable()
{
m_IconContent = new GUIContent()
{
image = Resources.Load<Texture2D>("Icons/WidthTool"),
text = "Width Tool",
tooltip = "Adjust the width of the created road mesh."
};
}
public override void OnToolGUI(EditorWindow window)
{
var splineDataTarget = target as WidthSplineData;
if(splineDataTarget == null || splineDataTarget.container == null)
return;
var nativeSpline = new NativeSpline(splineDataTarget.container.Spline, splineDataTarget.container.transform.localToWorldMatrix);
Undo.RecordObject(splineDataTarget,"Modifying Width SplineData");
Handles.color = Color.blue;
m_DisableHandles = false;
//User defined handles to manipulate width
DrawDataPoints(nativeSpline, splineDataTarget.width);
//Using the out-of the box behaviour to manipulate indexes
nativeSpline.DataPointHandles(splineDataTarget.width);
}
public void OnDrawHandles()
{
var splineDataTarget = target as WidthSplineData;
if(ToolManager.IsActiveTool(this) || splineDataTarget.container == null)
return;
var nativeSpline = new NativeSpline(splineDataTarget.container.Spline, splineDataTarget.container.transform.localToWorldMatrix);
Color color = Color.blue;
color.a = 0.5f;
Handles.color = color;
m_DisableHandles = true;
DrawDataPoints(nativeSpline,splineDataTarget.width);
}
protected override bool DrawDataPoint(
Vector3 position,
Vector3 tangent,
Vector3 up,
float inValue,
out float outValue)
{
int id1 = m_DisableHandles ? -1 : GUIUtility.GetControlID(FocusType.Passive);
int id2 = m_DisableHandles ? -1 : GUIUtility.GetControlID(FocusType.Passive);
outValue = 0f;
if(tangent == Vector3.zero)
return false;
if(Event.current.type == EventType.MouseUp
&& Event.current.button != 0
&& ( GUIUtility.hotControl == id1 || GUIUtility.hotControl == id2 ))
{
Event.current.Use();
return false;
}
var handleColor = Handles.color;
if(GUIUtility.hotControl == id1 || GUIUtility.hotControl == id2)
handleColor = Handles.selectedColor;
else if(GUIUtility.hotControl == 0 && (HandleUtility.nearestControl==id1 || HandleUtility.nearestControl==id2))
handleColor = Handles.preselectionColor;
var normalDirection = math.normalize(math.cross(tangent, up));
var extremity1 = position - inValue * (Vector3)normalDirection;
var extremity2 = position + inValue * (Vector3)normalDirection;
Vector3 val1, val2;
using(new Handles.DrawingScope(handleColor))
{
Handles.DrawLine(extremity1, extremity2);
val1 = Handles.Slider(id1, extremity1, normalDirection,
k_HandleSize * .5f * HandleUtility.GetHandleSize(position), CustomHandleCap, 0);
val2 = Handles.Slider(id2, extremity2, normalDirection,
k_HandleSize * .5f * HandleUtility.GetHandleSize(position), CustomHandleCap, 0);
}
if(GUIUtility.hotControl == id1 && math.abs(( val1 - extremity1 ).magnitude) > 0)
{
outValue = math.abs(( val1 - position ).magnitude);
return true;
}
if(GUIUtility.hotControl == id2 && math.abs(( val2 - extremity2 ).magnitude) > 0)
{
outValue = math.abs(( val2 - position ).magnitude);
return true;
}
return false;
}
public void CustomHandleCap(int controlID, Vector3 position, Quaternion rotation, float size, EventType eventType)
{
Handles.CubeHandleCap(controlID, position, rotation, size, m_DisableHandles ? EventType.Repaint : eventType);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 161dbe244d397fa478a292687ea673e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,21 @@
{
"name": "Unity.Splines.Examples.Editor",
"rootNamespace": "",
"references": [
"GUID:21d1eb854b91ade49bc69a263d12bee2",
"GUID:e43142fc3fec6554980dde6126631f1d",
"GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:9f08613db0663446b876a5eae626aa45"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a404f125045a6d14eae7fba9d72bf4da
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: