Hey. I'm working on setting up a re-usable character rig with IKs. I'm currently trying to use SimpleCCD, a (brand new, it seems, thus no documentation) script from Unity (showcased here, found the link here). I did also try Sprites and Bones, but switched back to SimpleCCD since I didn't find a way to restrict the angles of the IK, which leads to my current problem. The angle limits seem to be limited themselves, the way it's currently set up. The arm I'm limiting gets thrown to an opposite angle beyond a certain point, well within the range I've set up. Granted it would not bug on me, it still would be limited, in the sense that you can't seem to move where the 0 angle is calculated from. That creates a sort of obligatory dead-zone for animation. It's hard to explain, so I'll try to show: Here's the scripts - one of them is for the editor only. https://dl.dropboxusercontent.com/u/58757568/SimpleCCD.cs https://dl.dropboxusercontent.com/u/58757568/SimpleCCDEditor.cs Or to view them here: Spoiler: SimpleCCD.cs Code (CSharp): using UnityEngine; using System.Collections.Generic; [ExecuteInEditMode] public class SimpleCCD : MonoBehaviour { public int iterations = 5; [Range(0.01f, 1)] public float damping = 1; public Transform target; public Transform endTransform; public Node[] angleLimits = new Node[0]; Dictionary<Transform, Node> nodeCache; [System.Serializable] public class Node { public Transform Transform; public float min; public float max; } void OnValidate() { // min & max has to be between 0 ... 360 foreach (var node in angleLimits) { node.min = Mathf.Clamp (node.min, 0, 360); node.max = Mathf.Clamp (node.max, 0, 360); } } void Start() { // Cache optimization nodeCache = new Dictionary<Transform, Node>(angleLimits.Length); foreach (var node in angleLimits) if (!nodeCache.ContainsKey(node.Transform)) nodeCache.Add(node.Transform, node); } void LateUpdate() { if (!Application.isPlaying) Start(); if (target == null || endTransform == null) return; int i = 0; while (i < iterations) { CalculateIK (); i++; } endTransform.rotation = target.rotation; } void CalculateIK() { Transform node = endTransform.parent; while (true) { RotateTowardsTarget (node); if (node == transform) break; node = node.parent; } } void RotateTowardsTarget(Transform transform) { Vector2 toTarget = target.position - transform.position; Vector2 toEnd = endTransform.position - transform.position; // Calculate how much we should rotate to get to the target float angle = SignedAngle(toEnd, toTarget); // Flip sign if character is turned around angle *= Mathf.Sign(transform.root.localScale.x); // "Slows" down the IK solving angle *= damping; // Wanted angle for rotation angle = -(angle - transform.eulerAngles.z); // Take care of angle limits if (nodeCache.ContainsKey(transform)) { // Clamp angle in local space var node = nodeCache[transform]; float parentRotation = transform.parent ? transform.parent.eulerAngles.z : 0; angle -= parentRotation; angle = ClampAngle(angle, node.min, node.max); angle += parentRotation; } transform.rotation = Quaternion.Euler(0, 0, angle); } public static float SignedAngle (Vector3 a, Vector3 b) { float angle = Vector3.Angle (a, b); float sign = Mathf.Sign (Vector3.Dot (Vector3.back, Vector3.Cross (a, b))); return angle * sign; } float ClampAngle (float angle, float min, float max) { angle = Mathf.Abs((angle % 360) + 360) % 360; return Mathf.Clamp(angle, min, max); } } Spoiler: SimpleCCDEditor.cs Code (CSharp): using UnityEngine; using UnityEditor; [InitializeOnLoad] public class SimpleCCDEditor { static SimpleCCDEditor () { SceneView.onSceneGUIDelegate += OnScene; } // Scales scene view gizmo, feel free to change ;) const float gizmoSize = 0.5f; static void OnScene(SceneView sceneview) { var targets = GameObject.FindObjectsOfType<SimpleCCD>(); foreach (var target in targets) { foreach (var node in target.angleLimits) { if (node.Transform == null) continue; Transform transform = node.Transform; Vector3 position = transform.position; float handleSize = HandleUtility.GetHandleSize(position); float discSize = handleSize * gizmoSize; float parentRotation = transform.parent ? transform.parent.eulerAngles.z : 0; Vector3 min = Quaternion.Euler(0, 0, node.min + parentRotation)*Vector3.down; Vector3 max = Quaternion.Euler(0, 0, node.max + parentRotation)*Vector3.down; Handles.color = new Color(0, 1, 0, 0.1f); Handles.DrawWireDisc(position, Vector3.back, discSize); Handles.DrawSolidArc(position, Vector3.forward, min, node.max - node.min, discSize); Handles.color = Color.green; Handles.DrawLine(position, position + min * discSize); Handles.DrawLine(position, position + max*discSize); Vector3 toChild = FindChildNode(transform, target.endTransform).position - position; Handles.DrawLine(position, position + toChild); } } } static Transform FindChildNode (Transform parent, Transform endTransform) { if (endTransform.parent != parent) return FindChildNode(parent, endTransform.parent); ; return endTransform; } } Would be super grateful for any help, or any suggestions for other alternatives!
yeah, i know. that is on my find-out-how list. as soon as you give up on simpleccd and give the puppet guy the money AND you find out how to do it I would be happy if you post it here.
Sprites and Bones does to IK limiting, been in there for a while now: https://github.com/playemgames/UnitySpritesAndBones
Upon import: "Some scripts have compilation errors which may prevent obsolete API usages to get updated. Obsolete API updating will continue automatically after these errors get fixed."
So I click this link you posted: https://github.com/playemgames/UnitySpritesAndBones Then I click Clone or Download Then I click Download Zip Then I unzip the folder Then I copy Assets/SpritesAndBones into my project's Assets folder Then I tab over to Unity, which already has my project open, and it says "Some scripts have compilation errors which may prevent obsolete API usages to get updated. Obsolete API updating will continue automatically after these errors get fixed." Did I do it right? If so, Unity 5.3.5f Personal can't convert the latest off Github.