├── .gitignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── Editor.meta ├── Editor ├── SplineScrubber.Editor.asmdef ├── SplineScrubber.Editor.asmdef.meta ├── SplineSpeedClipEditor.cs ├── SplineSpeedClipEditor.cs.meta ├── SplineSpeedDrawer.cs ├── SplineSpeedDrawer.cs.meta ├── SplineTweenClipEditor.cs ├── SplineTweenClipEditor.cs.meta ├── SplineTweenDrawer.cs └── SplineTweenDrawer.cs.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── SplineCart.cs ├── SplineCart.cs.meta ├── SplineEvaluateRunner.cs ├── SplineEvaluateRunner.cs.meta ├── SplineJobController.cs ├── SplineJobController.cs.meta ├── SplineJobs.cs ├── SplineJobs.cs.meta ├── SplineJobsScheduler.cs ├── SplineJobsScheduler.cs.meta ├── Timeline.meta ├── Timeline │ ├── Clips.meta │ ├── Clips │ │ ├── BaseSplineBehaviour.cs │ │ ├── BaseSplineBehaviour.cs.meta │ │ ├── SplineSpeedBehaviour.cs │ │ ├── SplineSpeedBehaviour.cs.meta │ │ ├── SplineSpeedClip.cs │ │ ├── SplineSpeedClip.cs.meta │ │ ├── SplineTweenBehaviour.cs │ │ ├── SplineTweenBehaviour.cs.meta │ │ ├── SplineTweenClip.cs │ │ └── SplineTweenClip.cs.meta │ ├── SplineMixerBehaviour.cs │ ├── SplineMixerBehaviour.cs.meta │ ├── SplineTrack.cs │ └── SplineTrack.cs.meta ├── TransformUpdateRunner.cs └── TransformUpdateRunner.cs.meta ├── SplineScrubber.asmdef ├── SplineScrubber.asmdef.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | /**/.DS_Store 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 4 | 5 | ## [0.3.4] - 2024-11 6 | 7 | ### Added 8 | 9 | * New TweenClip additional to the speed based clip 10 | * Support for linear acceleration & deceleration per speed based clips 11 | * Support for clip extrapolation 12 | 13 | ### Changed 14 | 15 | * Renaming `SplineClipData` -> `SplineJobController` 16 | * Renaming `SplineMoveHandler` -> `SplineJobsScheduler` 17 | * UX: auto link `SplineContainer` reference for `SplineJobController` 18 | * Moved evaluation call from mixer in to `SplineCart` for better extendability 19 | * Use `Unity.mathematics.quaternion` for better burst 20 | * Calculate rotation from tan&up in `SplineEvaluate` Job 21 | * Spline localToWorld now handled in `SplineEvaluate` not via `NativeSpline` construction 22 | 23 | ### Bug Fixes 24 | 25 | * Fixed `SplineJobController` not updating when spline transform changes 26 | * Fixed crash/exceptions on `SplineJobController` disable/enable during edit mode 27 | * Fixed `SplineClipData::Length` for timeline starting on awake first frame 28 | * Fixed life-cycle issue when disabling/deleting `SplineJobController` 29 | 30 | ## [0.2.0] - 2023-07 31 | 32 | ### Added 33 | 34 | ### Changed -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1251c2e9cd5447428fede6541c5ae592 3 | timeCreated: 1691001809 -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9fb0b2e9d0924de887a5a32ebe07de3c 3 | timeCreated: 1639656228 -------------------------------------------------------------------------------- /Editor/SplineScrubber.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SplineScrubber.Editor", 3 | "rootNamespace": "SplineScrubber.Editor", 4 | "references": [ 5 | "GUID:bac96045e059c4c0c9d718ae60938f75", 6 | "GUID:02f771204943f4a40949438e873e3eff", 7 | "GUID:f06555f75b070af458a003d92f9efb00" 8 | ], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": false, 14 | "overrideReferences": false, 15 | "precompiledReferences": [], 16 | "autoReferenced": true, 17 | "defineConstraints": [], 18 | "versionDefines": [], 19 | "noEngineReferences": false 20 | } -------------------------------------------------------------------------------- /Editor/SplineScrubber.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ab7a0fb7842947248c8d8b407511a1c 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/SplineSpeedClipEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor.Timeline; 2 | using UnityEngine; 3 | using UnityEngine.Timeline; 4 | using SplineScrubber.Timeline.Clips; 5 | 6 | namespace SplineScrubber.Editor 7 | { 8 | [CustomTimelineEditor(typeof(SplineSpeedClip))] 9 | public class SplineSpeedClipEditor : ClipEditor 10 | { 11 | public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom) 12 | { 13 | var asset = clip.asset as SplineSpeedClip; 14 | base.OnCreate(clip, track, clonedFrom); 15 | asset.InitialClipDurationSet = clonedFrom != null; 16 | } 17 | 18 | public override void OnClipChanged(TimelineClip clip) 19 | { 20 | base.OnClipChanged(clip); 21 | var asset = clip.asset as SplineSpeedClip; 22 | 23 | if (asset.InitialClipDurationSet) return; 24 | 25 | if (!Mathf.Approximately(asset.PathLength, 0)) 26 | { 27 | clip.duration = asset.duration - clip.clipIn; 28 | asset.InitialClipDurationSet = true; 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Editor/SplineSpeedClipEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fd6783e418864ad0bacdfa271a10618a 3 | timeCreated: 1687604031 -------------------------------------------------------------------------------- /Editor/SplineSpeedDrawer.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | using SplineScrubber.Timeline.Clips; 4 | 5 | namespace SplineScrubber.Editor 6 | { 7 | [CustomPropertyDrawer(typeof(SplineSpeedBehaviour))] 8 | public class SplineSpeedDrawer : PropertyDrawer 9 | { 10 | private bool _showAccFoldOut = true; 11 | private bool _showDecFoldOut = true; 12 | 13 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) 14 | { 15 | var speedProp = property.FindPropertyRelative("_speed"); 16 | 17 | EditorGUILayout.PropertyField(speedProp); 18 | FoldOut("_accTime", "_accDistance", "_accCurve", ref _showAccFoldOut, "Acceleration"); 19 | FoldOut("_decTime", "_decDistance", "_decCurve", ref _showDecFoldOut, "Deceleration"); 20 | 21 | void FoldOut(string time, string distance, 22 | string curve, ref bool active, string label) 23 | { 24 | active = EditorGUILayout.Foldout(active, label); 25 | if (!active) return; 26 | 27 | var timeProp = property.FindPropertyRelative(time); 28 | var curveProp = property.FindPropertyRelative(curve); 29 | var distanceProp = property.FindPropertyRelative(distance); 30 | 31 | EditorGUI.indentLevel += 1; 32 | EditorGUILayout.BeginHorizontal(); 33 | EditorGUILayout.PropertyField(timeProp); 34 | EditorGUILayout.LabelField($"~{distanceProp.floatValue:F2}m"); 35 | EditorGUILayout.EndHorizontal(); 36 | 37 | // EditorGUILayout.PropertyField(curveProp); 38 | EditorGUI.indentLevel -= 1; 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Editor/SplineSpeedDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2061037b85184367b500a29b374790a1 3 | timeCreated: 1687605318 -------------------------------------------------------------------------------- /Editor/SplineTweenClipEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor.Timeline; 2 | using UnityEngine.Timeline; 3 | using SplineScrubber.Timeline.Clips; 4 | 5 | namespace SplineScrubber.Editor 6 | { 7 | [CustomTimelineEditor(typeof(SplineTweenClip))] 8 | public class SplineTweenClipEditor : ClipEditor 9 | { 10 | public override void OnClipChanged(TimelineClip clip) 11 | { 12 | base.OnClipChanged(clip); 13 | var asset = clip.asset as SplineTweenClip; 14 | 15 | asset.Duration = clip.duration + clip.clipIn; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Editor/SplineTweenClipEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 53ac62c79ce24cc6b36e29a5964ce5e7 3 | timeCreated: 1699226467 -------------------------------------------------------------------------------- /Editor/SplineTweenDrawer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using SplineScrubber.Timeline.Clips; 4 | 5 | [CustomPropertyDrawer(typeof(SplineTweenBehaviour))] 6 | public class SplineTweenDrawer : PropertyDrawer 7 | { 8 | public override float GetPropertyHeight (SerializedProperty property, GUIContent label) 9 | { 10 | int fieldCount = property.FindPropertyRelative ("_tweenType").enumValueIndex == (int)SplineTweenBehaviour.TweenType.Custom ? 4 : 3; 11 | return fieldCount * (EditorGUIUtility.singleLineHeight); 12 | } 13 | 14 | public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) 15 | { 16 | 17 | SerializedProperty fromProp = property.FindPropertyRelative ("_from"); 18 | SerializedProperty toProp = property.FindPropertyRelative ("_to"); 19 | SerializedProperty tweenTypeProp = property.FindPropertyRelative ("_tweenType"); 20 | 21 | Rect singleFieldRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight); 22 | EditorGUI.PropertyField(singleFieldRect, fromProp); 23 | singleFieldRect.y += EditorGUIUtility.singleLineHeight; 24 | EditorGUI.PropertyField(singleFieldRect, toProp); 25 | 26 | singleFieldRect.y += EditorGUIUtility.singleLineHeight; 27 | EditorGUI.PropertyField(singleFieldRect, tweenTypeProp); 28 | 29 | if (tweenTypeProp.enumValueIndex == (int)SplineTweenBehaviour.TweenType.Custom) 30 | { 31 | var customCurveProp = property.FindPropertyRelative ("_customCurve"); 32 | singleFieldRect.y += EditorGUIUtility.singleLineHeight; 33 | EditorGUI.PropertyField (singleFieldRect, customCurveProp); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Editor/SplineTweenDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f0ba783bdaf6492a85e44c32babc80b5 3 | timeCreated: 1699262083 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Felix Lange 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d79c7bf728f1c4cb3a4ae8cc9a95138a 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spline Scrubber 2 | 3 | **Spline Scrubber** is a Unity plugin that integrates Unity Spline package with the Unity Timeline to choreograph spline-driven animations. 4 | It offers custom timeline tracks, enabling precise animation sequencing along splines. 5 | 6 | By leveraging the performance benefits of the C# job system and burst compiler, the plugin efficiently evaluates splines and updates transforms in a multithreaded manner, at runtime and during edit mode. 7 | 8 | ## Dependencies 9 | 10 | * Unity 2022.3 11 | * com.unity.splines 12 | * com.unity.timeline 13 | * com.unity.collections 14 | 15 | ## Installation 16 | 17 | Install via Package Manager 18 | * [Add package via git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html): 19 | * `https://github.com/fx-lange/unity-spline-scrubber.git` 20 | 21 | ## How to use 22 | 23 | To choreograph spline-driven animations with Spline Scrubber: 24 | 25 | * `SplineCart`: Attach this to the game objects you wish to animate. It serves as the track binding for the SplineTrack. 26 | * `SplineTrack`: For each object, add this custom timeline track to your timeline assets. 27 | * `SplineClip`: Use this custom timeline clip within the SplineTrack to dictate the object's movement along the spline for the clip's duration. 28 | * `SplineJobController`: For every Spline(Container), include this component to pre-process and cache spline data, optimizing job execution. 29 | * `SplineJobsScheduler`: Ensure one instance of this singleton exists in your scene. It manages the real-time evaluation of splines and updates object transforms each frame. -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f831efd2c72a6441f93eb897d7cd0434 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b783e3c0ebe24cd7a40cce57a8fa8703 3 | timeCreated: 1683463335 -------------------------------------------------------------------------------- /Runtime/SplineCart.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace SplineScrubber 4 | { 5 | public class SplineCart : MonoBehaviour 6 | { 7 | public virtual void UpdatePosition(SplineJobController controller, float t, float length) 8 | { 9 | controller.HandlePosUpdate(transform, t); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Runtime/SplineCart.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 53428d1211f4469f9dfa7f9d67975e47 3 | timeCreated: 1637059573 -------------------------------------------------------------------------------- /Runtime/SplineEvaluateRunner.cs: -------------------------------------------------------------------------------- 1 | using Unity.Collections; 2 | using Unity.Jobs; 3 | using Unity.Mathematics; 4 | using UnityEngine; 5 | using UnityEngine.Splines; 6 | 7 | namespace SplineScrubber 8 | { 9 | public class SplineEvaluateRunner 10 | { 11 | public int Count => Indices.Length; 12 | public bool ReadyForInput { get; private set; } = true; 13 | 14 | public NativeList Indices { get; private set; } 15 | public NativeArray Pos { get; private set; } 16 | public NativeArray Rotation { get; private set; } 17 | public NativeSpline Spline { get; set; } 18 | public Transform SplineTransform { get; set; } 19 | 20 | private NativeList _ratios; 21 | 22 | private JobHandle _currJob; 23 | private bool _preparedTemp = false; 24 | 25 | public SplineEvaluateRunner(int capacity) 26 | { 27 | Indices = new NativeList(capacity, Allocator.Persistent); 28 | _ratios = new NativeList(capacity, Allocator.Persistent); 29 | } 30 | 31 | public void HandlePosUpdate(float t, int idx) 32 | { 33 | _ratios.Add(t); 34 | Indices.Add(idx); 35 | } 36 | 37 | public void Prepare() 38 | { 39 | ReadyForInput = false; 40 | _preparedTemp = true; 41 | Pos = new NativeArray(Count, Allocator.TempJob); 42 | Rotation = new NativeArray(Count, Allocator.TempJob); 43 | } 44 | 45 | public JobHandle Run(int batchCount = 2) 46 | { 47 | if (SplineTransform == null) //TODO Workaround - to expensive 48 | { 49 | return new JobHandle(); 50 | } 51 | SplineEvaluate evaluateJob = new() 52 | { 53 | Spline = Spline, 54 | Ratios = _ratios.AsArray(), 55 | Pos = Pos, 56 | Rotation = Rotation, 57 | LocalToWorld = SplineTransform.localToWorldMatrix, 58 | SplineRotation = SplineTransform.rotation 59 | }; 60 | _currJob = evaluateJob.Schedule(_ratios.Length, batchCount); 61 | return _currJob; 62 | } 63 | 64 | public void Abort() 65 | { 66 | if (!_currJob.IsCompleted) 67 | { 68 | _currJob.Complete(); 69 | } 70 | 71 | DisposeTemp(); 72 | } 73 | 74 | public void ClearAndDispose() 75 | { 76 | Indices.Clear(); 77 | _ratios.Clear(); 78 | DisposeTemp(); 79 | ReadyForInput = true; 80 | } 81 | 82 | private void DisposeTemp() 83 | { 84 | if (!_preparedTemp) return; 85 | Pos.Dispose(); 86 | Rotation.Dispose(); 87 | _preparedTemp = false; 88 | } 89 | 90 | ~SplineEvaluateRunner() 91 | { 92 | _ratios.Dispose(); 93 | Indices.Dispose(); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Runtime/SplineEvaluateRunner.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62c231b7dd764e95917ce66c7a614c63 3 | timeCreated: 1687669315 -------------------------------------------------------------------------------- /Runtime/SplineJobController.cs: -------------------------------------------------------------------------------- 1 | using Unity.Collections; 2 | using UnityEngine; 3 | using UnityEngine.Splines; 4 | 5 | namespace SplineScrubber 6 | { 7 | [ExecuteAlways] 8 | [DisallowMultipleComponent] 9 | public class SplineJobController : MonoBehaviour 10 | { 11 | [SerializeField] private SplineContainer _container; 12 | 13 | public float Length 14 | { 15 | get { 16 | if (!_lengthCached) 17 | { 18 | CacheLength(); 19 | } 20 | return _length; 21 | } 22 | } 23 | 24 | public SplinePath SplinePath => _path; 25 | 26 | private SplineJobsScheduler _scheduler; 27 | private SplineEvaluateRunner _evaluateRunner; 28 | private float _length; 29 | private bool _lengthCached; 30 | private SplinePath _path; 31 | private NativeSpline _nativeSpline; 32 | private bool _init; 33 | private bool _disposable; 34 | 35 | public void HandlePosUpdate(Transform target, float t) 36 | { 37 | if (!enabled) return; 38 | if (!_evaluateRunner.ReadyForInput) return; //can happen during drag clip 39 | 40 | var idx = _scheduler.Schedule(target); 41 | if (idx < 0) return; 42 | 43 | _evaluateRunner.HandlePosUpdate(t,idx); 44 | } 45 | 46 | private void OnEnable() 47 | { 48 | if (_init) return; 49 | Init(); 50 | } 51 | 52 | private void Init() 53 | { 54 | if (_container == null) 55 | { 56 | if (!TryGetComponent(out _container)) 57 | { 58 | Debug.LogError("Missing SplineContainer!", this); 59 | enabled = false; 60 | return; 61 | } 62 | } 63 | 64 | if (_scheduler == null) 65 | { 66 | _scheduler = SplineJobsScheduler.Instance; 67 | if (_scheduler == null) 68 | { 69 | Debug.LogWarning("Missing SplineJobsScheduler in the scene"); 70 | enabled = false; 71 | return; 72 | } 73 | } 74 | 75 | _evaluateRunner = new SplineEvaluateRunner(_scheduler.Capacity); 76 | _scheduler.Register(_evaluateRunner); 77 | 78 | Spline.Changed += OnSplineChanged; 79 | PrepareSplineData(); 80 | _init = true; 81 | } 82 | 83 | private void OnDisable() 84 | { 85 | Spline.Changed -= OnSplineChanged; 86 | 87 | if (_scheduler != null) 88 | { 89 | _scheduler.Unregister(_evaluateRunner); 90 | } 91 | Dispose(); 92 | 93 | _init = false; 94 | } 95 | 96 | private void OnSplineChanged(Spline spline, int _, SplineModification __) 97 | { 98 | OnSplineModified(spline); 99 | } 100 | 101 | private void OnSplineModified(Spline spline) 102 | { 103 | if (_container.Spline != spline) 104 | { 105 | return; 106 | } 107 | 108 | PrepareSplineData(); 109 | } 110 | 111 | private void PrepareSplineData() 112 | { 113 | CacheLength(); 114 | 115 | _path = new SplinePath(_container.Splines); 116 | 117 | Dispose(); 118 | _nativeSpline = new NativeSpline(_path, Allocator.Persistent); 119 | _evaluateRunner.Spline = _nativeSpline; 120 | _evaluateRunner.SplineTransform = _container.transform; 121 | _disposable = true; 122 | } 123 | 124 | private void CacheLength() 125 | { 126 | if (_container == null) 127 | { 128 | _length = 0; 129 | return; 130 | } 131 | 132 | _length = _container.CalculateLength(); 133 | _lengthCached = true; 134 | } 135 | 136 | private void Dispose() 137 | { 138 | if (!_disposable) 139 | { 140 | return; 141 | } 142 | 143 | _nativeSpline.Dispose(); 144 | _disposable = false; 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /Runtime/SplineJobController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac4c1eb45e4b4312bf436ae0bfb64945 3 | timeCreated: 1687578652 -------------------------------------------------------------------------------- /Runtime/SplineJobs.cs: -------------------------------------------------------------------------------- 1 | using Unity.Burst; 2 | using Unity.Collections; 3 | using Unity.Jobs; 4 | using Unity.Mathematics; 5 | using UnityEngine; 6 | using UnityEngine.Jobs; 7 | using UnityEngine.Splines; 8 | 9 | namespace SplineScrubber 10 | { 11 | [BurstCompile] 12 | public struct SplineEvaluateTransform : IJobParallelForTransform 13 | { 14 | [ReadOnly] public NativeArray ElapsedTimes; 15 | [ReadOnly] public NativeSpline Spline; 16 | 17 | public void Execute(int index, TransformAccess transform) 18 | { 19 | Spline.Evaluate(ElapsedTimes[index], out float3 pos, out float3 tan, out float3 up); 20 | var rotation = Quaternion.LookRotation(tan, up); 21 | transform.SetPositionAndRotation(pos, rotation); 22 | } 23 | } 24 | 25 | [BurstCompile] 26 | public struct SplineEvaluate : IJobParallelFor 27 | { 28 | [ReadOnly] public NativeArray Ratios; 29 | [ReadOnly] public NativeSpline Spline; 30 | [ReadOnly] public float4x4 LocalToWorld; 31 | [ReadOnly] public quaternion SplineRotation; 32 | 33 | public NativeArray Pos; 34 | public NativeArray Rotation; 35 | 36 | public void Execute(int index) 37 | { 38 | Spline.Evaluate(Ratios[index], out float3 position, out float3 tangent, out float3 up); 39 | Pos[index] = math.transform(LocalToWorld, position); 40 | Rotation[index] = math.mul(SplineRotation,quaternion.LookRotation(tangent, up)); 41 | } 42 | } 43 | 44 | [BurstCompile] 45 | public struct UpdateTransforms : IJobParallelForTransform 46 | { 47 | [ReadOnly] public NativeArray Pos; 48 | [ReadOnly] public NativeArray Rotation; 49 | public void Execute(int index, TransformAccess transform) 50 | { 51 | transform.SetPositionAndRotation(Pos[index], Rotation[index]); 52 | } 53 | } 54 | 55 | [BurstCompile] 56 | public struct UpdatePositions : IJobParallelForTransform 57 | { 58 | [ReadOnly] public NativeArray Pos; 59 | public void Execute(int index, TransformAccess transform) 60 | { 61 | transform.position = Pos[index]; 62 | } 63 | } 64 | 65 | [BurstCompile] 66 | public struct CollectResultsJob : IJob 67 | { 68 | [ReadOnly] public NativeList Indices; 69 | [ReadOnly] public NativeArray PosIn; 70 | [ReadOnly] public NativeArray RotateIn; 71 | 72 | [ReadOnly] public int Length; 73 | 74 | [WriteOnly] public NativeArray Pos; 75 | [WriteOnly] public NativeArray Rotation; 76 | 77 | public void Execute() 78 | { 79 | for (int i = 0; i < Length; i++) 80 | { 81 | int mappedIdx = Indices[i]; 82 | Pos[mappedIdx] = PosIn[i]; 83 | Rotation[mappedIdx] = RotateIn[i]; 84 | } 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /Runtime/SplineJobs.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c54bf9a771b740d9ad350717c31c1eb3 3 | timeCreated: 1687234903 -------------------------------------------------------------------------------- /Runtime/SplineJobsScheduler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Unity.Collections; 3 | using Unity.Jobs; 4 | using Unity.Profiling; 5 | using UnityEngine; 6 | 7 | namespace SplineScrubber 8 | { 9 | [ExecuteAlways] 10 | public class SplineJobsScheduler : MonoBehaviour 11 | { 12 | [SerializeField] private int _capacity = 1000; 13 | [SerializeField] private int _batchCount = 2; 14 | 15 | static readonly ProfilerMarker EvaluateMarker = new(ProfilerCategory.Scripts, "SplinesMoveHandler.Evaluate"); 16 | static readonly ProfilerMarker MoveMarker = new(ProfilerCategory.Scripts, "SplinesMoveHandler.Move"); 17 | 18 | private readonly List _evaluateRunners = new(); 19 | private TransformUpdateRunner _transformUpdateRunner = new(); 20 | 21 | private NativeArray _evaluateHandles; 22 | private JobHandle _prepareMoveHandle; 23 | private JobHandle _updateTransformHandle; 24 | 25 | private int _targetCount = 0; 26 | private bool _didPrepare; 27 | 28 | private static SplineJobsScheduler _instance; 29 | private static bool _initialized; 30 | 31 | public int Capacity => _capacity; 32 | 33 | public static SplineJobsScheduler Instance 34 | { 35 | get 36 | { 37 | if (!_initialized) 38 | { 39 | _instance = FindAnyObjectByType(); 40 | _initialized = _instance != null; 41 | } 42 | 43 | return _instance; 44 | } 45 | } 46 | 47 | private void OnEnable() 48 | { 49 | if (Instance != this) 50 | { 51 | Debug.LogError("Scheduler already exists, abort!"); 52 | } 53 | _transformUpdateRunner.Init(_capacity); 54 | } 55 | 56 | private void Update() 57 | { 58 | RunMove(_prepareMoveHandle); 59 | FinishFrame(); 60 | } 61 | 62 | private void LateUpdate() 63 | { 64 | RunEvaluate(); 65 | } 66 | 67 | public void Register(SplineEvaluateRunner runner) 68 | { 69 | _evaluateRunners.Add(runner); 70 | } 71 | 72 | public void Unregister(SplineEvaluateRunner runner) 73 | { 74 | _evaluateRunners.Remove(runner); 75 | if (!_prepareMoveHandle.IsCompleted) 76 | { 77 | Debug.LogWarning("Force complete due to disabling Evaluate Runner"); 78 | _prepareMoveHandle.Complete(); 79 | } 80 | 81 | runner.Abort(); 82 | } 83 | 84 | public int Schedule(Transform target) //TODO if disabled suddenly 85 | { 86 | if (!enabled) 87 | { 88 | return -1; 89 | } 90 | _transformUpdateRunner.Schedule(target); 91 | return _targetCount++; 92 | } 93 | 94 | private void RunEvaluate() 95 | { 96 | if (_targetCount == 0) 97 | { 98 | return; 99 | } 100 | 101 | EvaluateMarker.Begin(); 102 | Evaluate(); 103 | EvaluateMarker.End(); 104 | 105 | MoveMarker.Begin(); 106 | //collect results instead of running multiple transform jobs 107 | //for later blending support 108 | PrepareMove(); 109 | MoveMarker.End(); 110 | 111 | _didPrepare = true; 112 | return; 113 | 114 | void Evaluate() 115 | { 116 | //run all evaluate jobs 117 | var jobCount = _evaluateRunners.Count; 118 | _evaluateHandles = new NativeArray(jobCount, Allocator.TempJob); 119 | 120 | for (var idx = 0; idx < jobCount; idx++) 121 | { 122 | var evaluateRunner = _evaluateRunners[idx]; 123 | evaluateRunner.Prepare(); 124 | _evaluateHandles[idx] = evaluateRunner.Run(_batchCount); 125 | } 126 | } 127 | 128 | void PrepareMove() 129 | { 130 | var count = _targetCount; 131 | var evaluateHandle = JobHandle.CombineDependencies(_evaluateHandles); 132 | _prepareMoveHandle = _transformUpdateRunner.PrepareMove(count, _evaluateRunners, evaluateHandle); 133 | } 134 | } 135 | 136 | private void RunMove(JobHandle dependency) 137 | { 138 | if (!_didPrepare) return; 139 | _updateTransformHandle = _transformUpdateRunner.RunMove(dependency); 140 | } 141 | 142 | private void FinishFrame() 143 | { 144 | if (!_didPrepare) return; 145 | _updateTransformHandle.Complete(); 146 | DisposeAndClear(); 147 | } 148 | 149 | private void DisposeAndClear() 150 | { 151 | _didPrepare = false; 152 | _targetCount = 0; 153 | 154 | foreach (var evaluate in _evaluateRunners) 155 | { 156 | evaluate.ClearAndDispose(); 157 | } 158 | 159 | _transformUpdateRunner.Dispose(); 160 | _evaluateHandles.Dispose(); 161 | _transformUpdateRunner.Init(_capacity); 162 | } 163 | 164 | private void OnDisable() 165 | { 166 | _prepareMoveHandle.Complete(); 167 | FinishFrame(); 168 | _transformUpdateRunner.Dispose(); 169 | _initialized = false; 170 | } 171 | } 172 | } -------------------------------------------------------------------------------- /Runtime/SplineJobsScheduler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2c398c531394f8783f01c4f51a943b6 3 | timeCreated: 1687613927 -------------------------------------------------------------------------------- /Runtime/Timeline.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 964028bf65a44c359ef14dac8f16e129 3 | timeCreated: 1637059185 -------------------------------------------------------------------------------- /Runtime/Timeline/Clips.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 38afaa974489440480b4afdb63c0f708 3 | timeCreated: 1699259859 -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/BaseSplineBehaviour.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.Playables; 2 | 3 | namespace SplineScrubber.Timeline.Clips 4 | { 5 | public class BaseSplineBehaviour : PlayableBehaviour 6 | { 7 | public SplineJobController SplineController { get; set; } 8 | 9 | public virtual double EvaluateNormPos(double time) 10 | { 11 | return 0; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/BaseSplineBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af0623f9e8cb46c98c70cbf6c3ce219b 3 | timeCreated: 1699225549 -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/SplineSpeedBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Unity.Mathematics; 3 | using UnityEngine; 4 | using UnityEngine.Playables; 5 | using UnityEngine.Timeline; 6 | 7 | namespace SplineScrubber.Timeline.Clips 8 | { 9 | [Serializable] 10 | public class SplineSpeedBehaviour : BaseSplineBehaviour 11 | { 12 | [NotKeyable] [Min(0.0001f)] [SerializeField] 13 | private float _speed = 1; 14 | 15 | [NotKeyable] [Min(0)] [SerializeField] private float _accTime; 16 | [NotKeyable] [Min(0)] [SerializeField] private float _decTime; 17 | // [SerializeField] private AnimationCurve _accCurve; 18 | // [SerializeField] private AnimationCurve _decCurve; 19 | 20 | [NotKeyable] [Min(0)] [SerializeField] private float _accDistance; 21 | [NotKeyable] [Min(0)] [SerializeField] private float _decDistance; 22 | 23 | public float Duration { private get; set; } 24 | public float Speed => _speed; 25 | public float AccTime => _accTime; 26 | 27 | public float DecTime => _decTime; 28 | 29 | public void UpdateAccDecDistance() 30 | { 31 | _accDistance = AccTime * Speed / 2f; 32 | _decDistance = DecTime * Speed / 2f; 33 | } 34 | 35 | public override double EvaluateNormPos(double time) 36 | { 37 | if (Duration == 0) return 0; 38 | 39 | var innerTime = time % Duration; 40 | var distance = EvalInnerDistance(innerTime); 41 | return distance / SplineController.Length; 42 | 43 | double EvalInnerDistance(double t) 44 | { 45 | var mixInDur = AccTime; 46 | var mixOutDur = DecTime; 47 | var mixOutStart = Duration - mixOutDur; 48 | 49 | double mixInDistance = 0; 50 | if (mixInDur > 0) 51 | { 52 | var mixInTime = math.min(t, mixInDur); 53 | var mixInSpeed = mixInTime * Speed / mixInDur; 54 | mixInDistance = mixInTime * mixInSpeed / 2f; 55 | } 56 | 57 | double mixOutDistance = 0; 58 | if (mixOutDur > 0) 59 | { 60 | var mixOutTime = mixOutDur - math.clamp(t - mixOutStart, 0, mixOutDur); 61 | var mixOutSpeed = mixOutTime * Speed / mixOutDur; 62 | mixOutDistance = mixOutDur * Speed / 2f - mixOutTime * mixOutSpeed / 2f; 63 | } 64 | 65 | var centerDistance = math.clamp(t - mixInDur, 0, mixOutStart - mixInDur) * Speed; 66 | return mixInDistance + centerDistance + mixOutDistance; 67 | } 68 | } 69 | 70 | public override void OnPlayableCreate(Playable playable) 71 | { 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/SplineSpeedBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 22223318d68f45c3bebf0090e135e580 3 | timeCreated: 1687583066 -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/SplineSpeedClip.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.Playables; 4 | using UnityEngine.Timeline; 5 | 6 | namespace SplineScrubber.Timeline.Clips 7 | { 8 | [Serializable] 9 | public class SplineSpeedClip : PlayableAsset, ITimelineClipAsset 10 | { 11 | [SerializeField] private ExposedReference _splineController; 12 | [SerializeField] private SplineSpeedBehaviour _behaviour = new(); 13 | 14 | public ClipCaps clipCaps => ClipCaps.ClipIn | ClipCaps.Looping | ClipCaps.Extrapolation; 15 | 16 | public override double duration => GetDuration(); 17 | 18 | public float PathLength { get; set; } 19 | public bool InitialClipDurationSet { get; set; } 20 | 21 | public override Playable CreatePlayable(PlayableGraph graph, GameObject owner) 22 | { 23 | var playable = ScriptPlayable.Create(graph, _behaviour); 24 | var clone = playable.GetBehaviour(); 25 | var splineController = _splineController.Resolve(graph.GetResolver()); 26 | if (splineController) 27 | { 28 | PathLength = splineController.Length; 29 | clone.SplineController = splineController; 30 | } 31 | 32 | clone.Duration = GetDuration(); 33 | return playable; 34 | } 35 | 36 | private float GetDuration() 37 | { 38 | var mixDuration = _behaviour.AccTime + _behaviour.DecTime; 39 | if (mixDuration <= 0) return PathLength / _behaviour.Speed; 40 | 41 | //TODO simplified to be linear 42 | var mixInDistance = _behaviour.AccTime * _behaviour.Speed / 2f; 43 | var mixOutDistance = _behaviour.DecTime * _behaviour.Speed / 2f; 44 | 45 | var centerDistance = PathLength - mixInDistance - mixOutDistance; 46 | return mixDuration + (centerDistance / _behaviour.Speed); 47 | } 48 | 49 | private void OnValidate() 50 | { 51 | // Debug.Log("OnValidate"); 52 | _behaviour.UpdateAccDecDistance(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/SplineSpeedClip.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 14ca4b3f315b4068be77d33c6e62aa29 3 | timeCreated: 1687583578 -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/SplineTweenBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Unity.Mathematics; 3 | using UnityEngine; 4 | using UnityEngine.Timeline; 5 | 6 | namespace SplineScrubber.Timeline.Clips 7 | { 8 | [Serializable] 9 | public class SplineTweenBehaviour : BaseSplineBehaviour 10 | { 11 | [SerializeField] [NotKeyable] [Range(0,1)] private float _from; 12 | [SerializeField] [NotKeyable] [Range(0,1)] private float _to = 1f; 13 | [SerializeField] private TweenType _tweenType; 14 | [SerializeField] private AnimationCurve _customCurve = AnimationCurve.Linear(0,0,1,1); 15 | 16 | public double Duration { private get; set; } 17 | 18 | public enum TweenType 19 | { 20 | Linear, 21 | EaseInOut, 22 | Custom 23 | } 24 | 25 | private AnimationCurve _linear = AnimationCurve.Linear(0, 0, 1, 1); 26 | private AnimationCurve _easeInOut = AnimationCurve.EaseInOut(0, 0, 1, 1); 27 | 28 | public override double EvaluateNormPos(double time) 29 | { 30 | if (_tweenType == TweenType.Custom && !IsCustomCurveNormalised ()) 31 | { 32 | Debug.LogError("Custom Curve is not normalised. Curve must start at 0,0 and end at 1,1."); 33 | return 0f; 34 | } 35 | 36 | var timeNormalized = (float)(time / Duration); 37 | timeNormalized = _tweenType switch 38 | { 39 | TweenType.Linear => _linear.Evaluate(timeNormalized), 40 | TweenType.EaseInOut => _easeInOut.Evaluate(timeNormalized), 41 | TweenType.Custom => _customCurve.Evaluate(timeNormalized), 42 | _ => throw new ArgumentOutOfRangeException() 43 | }; 44 | 45 | var pos = math.lerp(_from, _to, timeNormalized); 46 | return pos; 47 | } 48 | 49 | private bool IsCustomCurveNormalised () 50 | { 51 | if (!Mathf.Approximately (_customCurve[0].time, 0f)) 52 | return false; 53 | 54 | if (!Mathf.Approximately (_customCurve[0].value, 0f)) 55 | return false; 56 | 57 | if (!Mathf.Approximately (_customCurve[_customCurve.length - 1].time, 1f)) 58 | return false; 59 | 60 | return Mathf.Approximately (_customCurve[_customCurve.length - 1].value, 1f); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/SplineTweenBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 857cce446b29486d94e1c798a0380c0d 3 | timeCreated: 1699224093 -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/SplineTweenClip.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Playables; 3 | using UnityEngine.Timeline; 4 | 5 | namespace SplineScrubber.Timeline.Clips 6 | { 7 | public class SplineTweenClip : PlayableAsset, ITimelineClipAsset 8 | { 9 | [SerializeField] private ExposedReference _splineController; 10 | [SerializeField] private SplineTweenBehaviour _behaviour = new(); 11 | 12 | public ClipCaps clipCaps => ClipCaps.ClipIn | ClipCaps.Extrapolation; 13 | 14 | public double Duration { 15 | set => _behaviour.Duration = value; 16 | } 17 | 18 | public override Playable CreatePlayable(PlayableGraph graph, GameObject owner) 19 | { 20 | var playable = ScriptPlayable.Create(graph, _behaviour); 21 | var clone = playable.GetBehaviour(); 22 | var splineController = _splineController.Resolve(graph.GetResolver()); 23 | if (splineController) 24 | { 25 | clone.SplineController = splineController; 26 | } 27 | 28 | return playable; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Runtime/Timeline/Clips/SplineTweenClip.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fee4296ce5764c9d9fe9e70d6d6fc1a2 3 | timeCreated: 1699223185 -------------------------------------------------------------------------------- /Runtime/Timeline/SplineMixerBehaviour.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.Playables; 2 | using SplineScrubber.Timeline.Clips; 3 | 4 | namespace SplineScrubber.Timeline 5 | { 6 | public class SplineMixerBehaviour : PlayableBehaviour 7 | { 8 | public override void ProcessFrame(Playable playable, FrameData info, object playerData) 9 | { 10 | if (playerData is not SplineCart cart) 11 | return; 12 | 13 | var inputCount = playable.GetInputCount(); 14 | 15 | for (var i = 0; i < inputCount; i++) 16 | { 17 | var inputWeight = playable.GetInputWeight(i); 18 | var inputPlayable = (ScriptPlayable)playable.GetInput(i); 19 | var input = inputPlayable.GetBehaviour (); 20 | 21 | if (inputWeight <= 0f) 22 | { 23 | continue; 24 | } 25 | 26 | var splineController = input.SplineController; 27 | if (splineController == null) 28 | { 29 | return; 30 | } 31 | 32 | var tPos = input.EvaluateNormPos(inputPlayable.GetTime()); 33 | cart.UpdatePosition(splineController, (float)tPos, splineController.Length); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Runtime/Timeline/SplineMixerBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a8c6765d4f8340cb81942f7cafb24d89 3 | timeCreated: 1687578464 -------------------------------------------------------------------------------- /Runtime/Timeline/SplineTrack.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using UnityEngine; 3 | using UnityEngine.Playables; 4 | using UnityEngine.Timeline; 5 | using SplineScrubber.Timeline.Clips; 6 | 7 | namespace SplineScrubber.Timeline 8 | { 9 | [TrackClipType(typeof(SplineSpeedClip))] 10 | [TrackClipType(typeof(SplineTweenClip))] 11 | [TrackBindingType(typeof(SplineCart))] 12 | [TrackColor(0f, 0.4150943f, 0.8301887f)] 13 | [DisplayName("SplineScrubber/Track")] 14 | public partial class SplineTrack : TrackAsset 15 | { 16 | public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) 17 | { 18 | return ScriptPlayable.Create(graph, inputCount); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Runtime/Timeline/SplineTrack.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c6865b710e164f9386f0bb40f4b4a334 3 | timeCreated: 1687578351 -------------------------------------------------------------------------------- /Runtime/TransformUpdateRunner.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Unity.Collections; 3 | using Unity.Jobs; 4 | using Unity.Mathematics; 5 | using UnityEngine; 6 | using UnityEngine.Jobs; 7 | 8 | namespace SplineScrubber 9 | { 10 | public class TransformUpdateRunner 11 | { 12 | private TransformAccessArray _transformsAccess; 13 | 14 | private NativeArray _pos; 15 | private NativeArray _rotation; 16 | 17 | private bool _prepared = false; 18 | 19 | public void Init(int capacity) 20 | { 21 | _transformsAccess = new TransformAccessArray(capacity); 22 | } 23 | 24 | public void Schedule(Transform target) 25 | { 26 | _transformsAccess.Add(target); 27 | } 28 | 29 | public JobHandle PrepareMove(int count, List evaluateRunners, JobHandle dependency) 30 | { 31 | _pos = new NativeArray(count, Allocator.TempJob); 32 | _rotation = new NativeArray(count, Allocator.TempJob); 33 | 34 | foreach (var evaluateRunner in evaluateRunners) 35 | { 36 | CollectResultsJob collectJob = new() 37 | { 38 | Indices = evaluateRunner.Indices, 39 | PosIn = evaluateRunner.Pos, 40 | RotateIn = evaluateRunner.Rotation, 41 | Length = evaluateRunner.Count, 42 | Pos = _pos, 43 | Rotation = _rotation, 44 | }; 45 | dependency = collectJob.Schedule(dependency); 46 | } 47 | 48 | _prepared = true; 49 | return dependency; 50 | } 51 | 52 | public JobHandle RunMove(JobHandle dependency) 53 | { 54 | UpdateTransforms transformJob = new() 55 | { 56 | Pos = _pos, 57 | Rotation = _rotation 58 | }; 59 | 60 | return transformJob.Schedule(_transformsAccess, dependency); 61 | } 62 | 63 | public void Dispose() 64 | { 65 | _transformsAccess.Dispose(); 66 | if (!_prepared) 67 | { 68 | return; 69 | } 70 | 71 | _pos.Dispose(); 72 | _rotation.Dispose(); 73 | 74 | _prepared = false; 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /Runtime/TransformUpdateRunner.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da65ab8d48b24678a1e37144999fb485 3 | timeCreated: 1697536356 -------------------------------------------------------------------------------- /SplineScrubber.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SplineScrubber", 3 | "rootNamespace": "SplineScrubber", 4 | "references": [ 5 | "GUID:f06555f75b070af458a003d92f9efb00", 6 | "GUID:d8b63aba1907145bea998dd612889d6b", 7 | "GUID:21d1eb854b91ade49bc69a263d12bee2", 8 | "GUID:4307f53044263cf4b835bd812fc161a4", 9 | "GUID:2665a8d13d1b3f18800f46e256720795", 10 | "GUID:e0cd26848372d4e5c891c569017e11f1" 11 | ], 12 | "includePlatforms": [], 13 | "excludePlatforms": [], 14 | "allowUnsafeCode": false, 15 | "overrideReferences": false, 16 | "precompiledReferences": [], 17 | "autoReferenced": true, 18 | "defineConstraints": [], 19 | "versionDefines": [], 20 | "noEngineReferences": false 21 | } -------------------------------------------------------------------------------- /SplineScrubber.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bac96045e059c4c0c9d718ae60938f75 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.fxlange.spline-scrubber", 3 | "version": "0.3.4", 4 | "displayName": "Spline Scrubber", 5 | "description": "Efficient timeline integration for splines using c# job system", 6 | "unity": "2022.3", 7 | "author": { 8 | "name": "Felix Lange", 9 | "email": "mail@felixlange.dev", 10 | "url": "felixlange.dev" 11 | }, 12 | "dependencies": { 13 | "com.unity.timeline": "1.7.5", 14 | "com.unity.splines": "2.3.0", 15 | "com.unity.collections": "2.1.4" 16 | }, 17 | "licensesUrl": "https://github.com/fx-lange/unity-spline-scrubber/blob/main/LICENSE", 18 | "changelogUrl": "https://github.com/fx-lange/unity-spline-scrubber/blob/main/CHANGELOG.md", 19 | "documentationUrl": "https://github.com/fx-lange/unity-spline-scrubber#spline-scrubber" 20 | } -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: be8cb51e6cdf94edeb46d4b9030ba5d4 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------