aboutsummaryrefslogtreecommitdiff
path: root/JamHelper/Assets/JamUtils/FastIK/Scripts
diff options
context:
space:
mode:
Diffstat (limited to 'JamHelper/Assets/JamUtils/FastIK/Scripts')
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK.meta8
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKCCD.cs95
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKCCD.cs.meta11
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKFabric.cs250
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKFabric.cs.meta11
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKLook.cs40
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKLook.cs.meta11
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/Sample.meta8
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleProcedualAnimation.cs45
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleProcedualAnimation.cs.meta11
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleRotator.cs14
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleRotator.cs.meta11
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleSinMover.cs21
-rw-r--r--JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleSinMover.cs.meta11
14 files changed, 547 insertions, 0 deletions
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK.meta b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK.meta
new file mode 100644
index 0000000..a9848af
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 69d93e855b2f3534f90112f45a5e2180
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKCCD.cs b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKCCD.cs
new file mode 100644
index 0000000..9fb4883
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKCCD.cs
@@ -0,0 +1,95 @@
+using UnityEngine;
+/*
+public class IKCCD : MonoBehaviour
+{
+ public int ChainLength = 2;
+ public Transform Target;
+ protected Quaternion TargetInitialRotation;
+ protected Quaternion EndInitialRotation;
+ public Transform Pole;
+ protected float CompleteLength;
+
+ public int Iterations = 10;
+ public float Delta = 0.001f;
+
+ protected Transform[] Bones;
+ //protected Quaternion[] InitialRotation;
+
+
+ // Start is called before the first frame update
+ void Awake()
+ {
+ //initial length
+ Bones = new Transform[ChainLength + 1];
+ //InitialRotation = new Quaternion[ChainLength + 1];
+ TargetInitialRotation = Target.rotation;
+ EndInitialRotation = transform.rotation;
+
+ var current = transform;
+ CompleteLength = 0;
+ for (int i = ChainLength - 1; i >= 0; i--)
+ {
+ CompleteLength += (current.position - current.parent.position).magnitude;
+ Bones[i + 1] = current;
+ Bones[i] = current.parent;
+ //InitialRotation[i + 1] = current.rotation;
+ //InitialRotation[i] = current.parent.rotation;
+ current = current.parent;
+ }
+ if (Bones[0] == null)
+ throw new UnityException("The chain value is longer than the ancestor chain!");
+ }
+
+ // Update is called once per frame
+ void LateUpdate()
+ {
+ //CCD
+ var lastBone = Bones[Bones.Length - 1];
+
+ //for (var i = 0; i < Bones.Length; i++)
+ // Bones[i].rotation = InitialRotation[i];
+
+ for (int iteration = 0; iteration < Iterations; iteration++)
+ {
+ for (var i = Bones.Length - 1; i >= 0; i--)
+ {
+ //https://www.youtube.com/watch?v=MA1nT9RAF3k
+
+ if (i == Bones.Length - 1)
+ {
+ Bones[i].rotation = Target.rotation * Quaternion.Inverse(TargetInitialRotation) * EndInitialRotation;
+ }
+ else
+ {
+ Bones[i].rotation = Quaternion.FromToRotation(lastBone.position - Bones[i].position, Target.position - Bones[i].position) * Bones[i].rotation;
+
+ //jitter to solve strait line
+ //if (iteration == 5 && i == 0 && (Target.position - lastBone.position).sqrMagnitude > 0.01f && (Target.position - Bones[i].position).sqrMagnitude < CompleteLength * CompleteLength)
+ // Bones[i].rotation = Quaternion.AngleAxis(10, Vector3.up) * Bones[i].rotation;
+
+ //move towards pole
+ if (Pole != null && i + 2 <= Bones.Length - 1)
+ {
+ var plane = new Plane(Bones[i + 2].position - Bones[i].position, Bones[i].position);
+ var projectedPole = plane.ClosestPointOnPlane(Pole.position);
+ var projectedBone = plane.ClosestPointOnPlane(Bones[i + 1].position);
+ if ((projectedBone - Bones[i].position).sqrMagnitude > 0.01f)
+ {
+ var angle = Vector3.SignedAngle(projectedBone - Bones[i].position, projectedPole - Bones[i].position, plane.normal);
+ Bones[i].rotation = Quaternion.AngleAxis(angle, plane.normal) * Bones[i].rotation;
+ }
+ }
+ }
+
+
+ //close enough?
+ if ((lastBone.position - Target.position).sqrMagnitude < Delta * Delta)
+ break;
+ }
+ }
+
+ }
+
+
+}
+*/ \ No newline at end of file
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKCCD.cs.meta b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKCCD.cs.meta
new file mode 100644
index 0000000..c7c447c
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKCCD.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 12ebedeac55c4bb4aa003bfe2e00556e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKFabric.cs b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKFabric.cs
new file mode 100644
index 0000000..a9f6ee1
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKFabric.cs
@@ -0,0 +1,250 @@
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+using UnityEngine;
+
+namespace DitzelGames.FastIK
+{
+ /// <summary>
+ /// Fabrik IK Solver
+ /// </summary>
+ public class FastIKFabric : MonoBehaviour
+ {
+ /// <summary>
+ /// Chain length of bones
+ /// </summary>
+ public int ChainLength = 2;
+
+ /// <summary>
+ /// Target the chain should bent to
+ /// </summary>
+ public Transform Target;
+ public Transform Pole;
+
+ /// <summary>
+ /// Solver iterations per update
+ /// </summary>
+ [Header("Solver Parameters")]
+ public int Iterations = 10;
+
+ /// <summary>
+ /// Distance when the solver stops
+ /// </summary>
+ public float Delta = 0.001f;
+
+ /// <summary>
+ /// Strength of going back to the start position.
+ /// </summary>
+ [Range(0, 1)]
+ public float SnapBackStrength = 1f;
+
+
+ protected float[] BonesLength; //Target to Origin
+ protected float CompleteLength;
+ protected Transform[] Bones;
+ protected Vector3[] Positions;
+ protected Vector3[] StartDirectionSucc;
+ protected Quaternion[] StartRotationBone;
+ protected Quaternion StartRotationTarget;
+ protected Transform Root;
+
+
+ // Start is called before the first frame update
+ void Awake()
+ {
+ Init();
+ }
+
+ void Init()
+ {
+ //initial array
+ Bones = new Transform[ChainLength + 1];
+ Positions = new Vector3[ChainLength + 1];
+ BonesLength = new float[ChainLength];
+ StartDirectionSucc = new Vector3[ChainLength + 1];
+ StartRotationBone = new Quaternion[ChainLength + 1];
+
+ //find root
+ Root = transform;
+ for (var i = 0; i <= ChainLength; i++)
+ {
+ if (Root == null)
+ throw new UnityException("The chain value is longer than the ancestor chain!");
+ Root = Root.parent;
+ }
+
+ //init target
+ if (Target == null)
+ {
+ Target = new GameObject(gameObject.name + " Target").transform;
+ SetPositionRootSpace(Target, GetPositionRootSpace(transform));
+ }
+ StartRotationTarget = GetRotationRootSpace(Target);
+
+
+ //init data
+ var current = transform;
+ CompleteLength = 0;
+ for (var i = Bones.Length - 1; i >= 0; i--)
+ {
+ Bones[i] = current;
+ StartRotationBone[i] = GetRotationRootSpace(current);
+
+ if (i == Bones.Length - 1)
+ {
+ //leaf
+ StartDirectionSucc[i] = GetPositionRootSpace(Target) - GetPositionRootSpace(current);
+ }
+ else
+ {
+ //mid bone
+ StartDirectionSucc[i] = GetPositionRootSpace(Bones[i + 1]) - GetPositionRootSpace(current);
+ BonesLength[i] = StartDirectionSucc[i].magnitude;
+ CompleteLength += BonesLength[i];
+ }
+
+ current = current.parent;
+ }
+
+
+
+ }
+
+ // Update is called once per frame
+ void LateUpdate()
+ {
+ ResolveIK();
+ }
+
+ private void ResolveIK()
+ {
+ if (Target == null)
+ return;
+
+ if (BonesLength.Length != ChainLength)
+ Init();
+
+ //Fabric
+
+ // root
+ // (bone0) (bonelen 0) (bone1) (bonelen 1) (bone2)...
+ // x--------------------x--------------------x---...
+
+ //get position
+ for (int i = 0; i < Bones.Length; i++)
+ Positions[i] = GetPositionRootSpace(Bones[i]);
+
+ var targetPosition = GetPositionRootSpace(Target);
+ var targetRotation = GetRotationRootSpace(Target);
+
+ //1st is possible to reach?
+ if ((targetPosition - GetPositionRootSpace(Bones[0])).sqrMagnitude >= CompleteLength * CompleteLength)
+ {
+ //just strech it
+ var direction = (targetPosition - Positions[0]).normalized;
+ //set everything after root
+ for (int i = 1; i < Positions.Length; i++)
+ Positions[i] = Positions[i - 1] + direction * BonesLength[i - 1];
+ }
+ else
+ {
+ for (int i = 0; i < Positions.Length - 1; i++)
+ Positions[i + 1] = Vector3.Lerp(Positions[i + 1], Positions[i] + StartDirectionSucc[i], SnapBackStrength);
+
+ for (int iteration = 0; iteration < Iterations; iteration++)
+ {
+ //https://www.youtube.com/watch?v=UNoX65PRehA
+ //back
+ for (int i = Positions.Length - 1; i > 0; i--)
+ {
+ if (i == Positions.Length - 1)
+ Positions[i] = targetPosition; //set it to target
+ else
+ Positions[i] = Positions[i + 1] + (Positions[i] - Positions[i + 1]).normalized * BonesLength[i]; //set in line on distance
+ }
+
+ //forward
+ for (int i = 1; i < Positions.Length; i++)
+ Positions[i] = Positions[i - 1] + (Positions[i] - Positions[i - 1]).normalized * BonesLength[i - 1];
+
+ //close enough?
+ if ((Positions[Positions.Length - 1] - targetPosition).sqrMagnitude < Delta * Delta)
+ break;
+ }
+ }
+
+ //move towards pole
+ if (Pole != null)
+ {
+ var polePosition = GetPositionRootSpace(Pole);
+ for (int i = 1; i < Positions.Length - 1; i++)
+ {
+ var plane = new Plane(Positions[i + 1] - Positions[i - 1], Positions[i - 1]);
+ var projectedPole = plane.ClosestPointOnPlane(polePosition);
+ var projectedBone = plane.ClosestPointOnPlane(Positions[i]);
+ var angle = Vector3.SignedAngle(projectedBone - Positions[i - 1], projectedPole - Positions[i - 1], plane.normal);
+ Positions[i] = Quaternion.AngleAxis(angle, plane.normal) * (Positions[i] - Positions[i - 1]) + Positions[i - 1];
+ }
+ }
+
+ //set position & rotation
+ for (int i = 0; i < Positions.Length; i++)
+ {
+ if (i == Positions.Length - 1)
+ SetRotationRootSpace(Bones[i], Quaternion.Inverse(targetRotation) * StartRotationTarget * Quaternion.Inverse(StartRotationBone[i]));
+ else
+ SetRotationRootSpace(Bones[i], Quaternion.FromToRotation(StartDirectionSucc[i], Positions[i + 1] - Positions[i]) * Quaternion.Inverse(StartRotationBone[i]));
+ SetPositionRootSpace(Bones[i], Positions[i]);
+ }
+ }
+
+ private Vector3 GetPositionRootSpace(Transform current)
+ {
+ if (Root == null)
+ return current.position;
+ else
+ return Quaternion.Inverse(Root.rotation) * (current.position - Root.position);
+ }
+
+ private void SetPositionRootSpace(Transform current, Vector3 position)
+ {
+ if (Root == null)
+ current.position = position;
+ else
+ current.position = Root.rotation * position + Root.position;
+ }
+
+ private Quaternion GetRotationRootSpace(Transform current)
+ {
+ //inverse(after) * before => rot: before -> after
+ if (Root == null)
+ return current.rotation;
+ else
+ return Quaternion.Inverse(current.rotation) * Root.rotation;
+ }
+
+ private void SetRotationRootSpace(Transform current, Quaternion rotation)
+ {
+ if (Root == null)
+ current.rotation = rotation;
+ else
+ current.rotation = Root.rotation * rotation;
+ }
+
+ void OnDrawGizmos()
+ {
+#if UNITY_EDITOR
+ var current = this.transform;
+ for (int i = 0; i < ChainLength && current != null && current.parent != null; i++)
+ {
+ var scale = Vector3.Distance(current.position, current.parent.position) * 0.1f;
+ Handles.matrix = Matrix4x4.TRS(current.position, Quaternion.FromToRotation(Vector3.up, current.parent.position - current.position), new Vector3(scale, Vector3.Distance(current.parent.position, current.position), scale));
+ Handles.color = Color.green;
+ Handles.DrawWireCube(Vector3.up * 0.5f, Vector3.one);
+ current = current.parent;
+ }
+ }
+#endif
+
+ }
+} \ No newline at end of file
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKFabric.cs.meta b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKFabric.cs.meta
new file mode 100644
index 0000000..05db1b4
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKFabric.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 03ca45bb53dc94f478358a1b6475653d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 200
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKLook.cs b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKLook.cs
new file mode 100644
index 0000000..54ed1ed
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKLook.cs
@@ -0,0 +1,40 @@
+using UnityEngine;
+
+namespace DitzelGames.FastIK
+{
+ public class FastIKLook : MonoBehaviour
+ {
+ /// <summary>
+ /// Look at target
+ /// </summary>
+ public Transform Target;
+
+ /// <summary>
+ /// Initial direction
+ /// </summary>
+ protected Vector3 StartDirection;
+
+ /// <summary>
+ /// Initial Rotation
+ /// </summary>
+ protected Quaternion StartRotation;
+
+ void Awake()
+ {
+ if (Target == null)
+ return;
+
+ StartDirection = Target.position - transform.position;
+ StartRotation = transform.rotation;
+ }
+
+ void Update()
+ {
+ if (Target == null)
+ return;
+
+
+ transform.rotation = Quaternion.FromToRotation(StartDirection, Target.position - transform.position) * StartRotation;
+ }
+ }
+}
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKLook.cs.meta b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKLook.cs.meta
new file mode 100644
index 0000000..fa801cd
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/FastIK/FastIKLook.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5db2cc9d15d8e1c4e81fbc747c163d99
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample.meta b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample.meta
new file mode 100644
index 0000000..2fef29e
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f9ac29da80c8cfe4084775ebe4166f24
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleProcedualAnimation.cs b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleProcedualAnimation.cs
new file mode 100644
index 0000000..01e38ff
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleProcedualAnimation.cs
@@ -0,0 +1,45 @@
+using UnityEngine;
+
+namespace DitzelGames.FastIK
+{
+ class SampleProcedualAnimation : MonoBehaviour
+ {
+ public Transform[] FootTarget;
+ public Transform LookTarget;
+ public Transform HandTarget;
+ public Transform HandPole;
+ public Transform Step;
+ public Transform Attraction;
+
+ public void LateUpdate()
+ {
+ //move step & attraction
+ Step.Translate(Vector3.forward * Time.deltaTime * 0.7f);
+ if (Step.position.z > 1f)
+ Step.position = Step.position + Vector3.forward * -2f;
+ Attraction.Translate(Vector3.forward * Time.deltaTime * 0.5f);
+ if (Attraction.position.z > 1f)
+ Attraction.position = Attraction.position + Vector3.forward * -2f;
+
+ //footsteps
+ for(int i = 0; i < FootTarget.Length; i++)
+ {
+ var foot = FootTarget[i];
+ var ray = new Ray(foot.transform.position + Vector3.up * 0.5f, Vector3.down);
+ var hitInfo = new RaycastHit();
+ if(Physics.SphereCast(ray, 0.05f, out hitInfo, 0.50f))
+ foot.position = hitInfo.point + Vector3.up * 0.05f;
+ }
+
+ //hand and look
+ var normDist = Mathf.Clamp((Vector3.Distance(LookTarget.position, Attraction.position) - 0.3f) / 1f, 0, 1);
+ HandTarget.rotation = Quaternion.Lerp(Quaternion.Euler(90, 0, 0), HandTarget.rotation, normDist);
+ HandTarget.position = Vector3.Lerp(Attraction.position, HandTarget.position, normDist);
+ HandPole.position = Vector3.Lerp(HandTarget.position + Vector3.down * 2, HandTarget.position + Vector3.forward * 2f, normDist);
+ LookTarget.position = Vector3.Lerp(Attraction.position, LookTarget.position, normDist);
+
+
+ }
+
+ }
+}
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleProcedualAnimation.cs.meta b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleProcedualAnimation.cs.meta
new file mode 100644
index 0000000..7f3ffb6
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleProcedualAnimation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1c9cd2c593f693345ad26b97d5a0d43f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 100
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleRotator.cs b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleRotator.cs
new file mode 100644
index 0000000..62f201d
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleRotator.cs
@@ -0,0 +1,14 @@
+using UnityEngine;
+
+namespace DitzelGames.FastIK
+{
+ public class SampleRotator : MonoBehaviour
+ {
+
+ void Update()
+ {
+ //just rotate the object
+ transform.Rotate(0, Time.deltaTime * 90, 0);
+ }
+ }
+}
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleRotator.cs.meta b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleRotator.cs.meta
new file mode 100644
index 0000000..5fd4b94
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleRotator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e9a7a99d0dda4cf438c3fd3db6627c08
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleSinMover.cs b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleSinMover.cs
new file mode 100644
index 0000000..0607082
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleSinMover.cs
@@ -0,0 +1,21 @@
+using UnityEngine;
+
+namespace DitzelGames.FastIK
+{
+ public class SampleSinMover : MonoBehaviour
+ {
+ public Vector3 Dir;
+ public Vector3 Start;
+
+ private void Awake()
+ {
+ Start = transform.position;
+ }
+
+ void Update()
+ {
+ //just move the object from a to b and back
+ transform.position = Start + Dir * Mathf.Sin(Time.timeSinceLevelLoad);
+ }
+ }
+}
diff --git a/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleSinMover.cs.meta b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleSinMover.cs.meta
new file mode 100644
index 0000000..9095f54
--- /dev/null
+++ b/JamHelper/Assets/JamUtils/FastIK/Scripts/Sample/SampleSinMover.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bf9a667200f2ae8459b397bc03e59350
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: