/* * Draws the scene view helpers for IKSolverHeuristic * */ public static void AddScene(IKSolverHeuristic solver, Color color, bool modifiable) { // Protect from null reference errors if (Application.isPlaying && !solver.initiated) return; if (!Application.isPlaying && !solver.IsValid()) return; Handles.color = color; GUI.color = color; // Display the bones for (int i = 0; i < solver.bones.Length; i++) { IKSolver.Bone bone = solver.bones[i]; if (i < solver.bones.Length - 1) Handles.DrawLine(bone.transform.position, solver.bones[i + 1].transform.position); Inspector.SphereCap(0, solver.bones[i].transform.position, Quaternion.identity, GetHandleSize(solver.bones[i].transform.position)); } // Selecting joint and manipulating IKPosition if (Application.isPlaying && solver.IKPositionWeight > 0) { if (modifiable) { Inspector.CubeCap(0, solver.IKPosition, solver.GetRoot().rotation, GetHandleSize(solver.IKPosition)); // Manipulating position if (solver.target == null) solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity); } // Draw a transparent line from last bone to IKPosition Handles.color = new Color(color.r, color.g, color.b, color.a * solver.IKPositionWeight); Handles.DrawLine(solver.bones[solver.bones.Length - 1].transform.position, solver.IKPosition); } Handles.color = Color.white; GUI.color = Color.white; }
/* * Rotating bone to get transform aim closer to target * */ private void RotateToTarget(Vector3 targetPosition, IKSolver.Bone bone, float weight) { // Swing if (weight >= 0f) { Quaternion rotationOffset = Quaternion.FromToRotation(transformAxis, targetPosition - transform.position); bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, rotationOffset, weight) * bone.transform.rotation; } // Pole if (poleWeight > 0f) { Vector3 poleDirection = polePosition - transform.position; // Ortho-normalize to transform axis to make this a twisting only operation Vector3 poleDirOrtho = poleDirection; Vector3 normal = transformAxis; Vector3.OrthoNormalize(ref normal, ref poleDirOrtho); Quaternion toPole = Quaternion.FromToRotation(transformPoleAxis, poleDirOrtho); bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, toPole, weight * poleWeight) * bone.transform.rotation; } if (useRotationLimits && bone.rotationLimit != null) { bone.rotationLimit.Apply(); } }
/// <summary> /// Solve the bone chain virtually using solverPositions only. SolverRotations will not be changed. /// </summary> public static void SolveVirtualPositions(IKSolver.Bone bone1, IKSolver.Bone bone2, IKSolver.Bone bone3, Vector3 targetPosition, Vector3 bendNormal, float weight) { // Direction of the limb in solver targetPosition = Vector3.Lerp(bone3.solverPosition, targetPosition, weight); Vector3 dir = targetPosition - bone1.solverPosition; // Distance between the first and the last node solver positions float sqrMag = dir.sqrMagnitude; if (sqrMag == 0f) { return; } float length = Mathf.Sqrt(sqrMag); float sqrMag1 = (bone2.solverPosition - bone1.solverPosition).sqrMagnitude; float sqrMag2 = (bone3.solverPosition - bone2.solverPosition).sqrMagnitude; // Get the general world space bending direction Vector3 bendDir = Vector3.Cross(dir, bendNormal); // Get the direction to the trigonometrically solved position of the second node Vector3 toBendPoint = GetDirectionToBendPoint(dir, length, bendDir, sqrMag1, sqrMag2); //bone2.solverPosition = bone1.solverPosition + toBendPoint; bone2.solverPosition = bone1.solverPosition + toBendPoint.normalized * Mathf.Sqrt(sqrMag1); bone3.solverPosition = sqrMag < sqrMag1 + sqrMag2? targetPosition: bone2.solverPosition + (targetPosition - bone2.solverPosition).normalized * Mathf.Sqrt(sqrMag2); }
/// <summary> /// Draws the scene view helpers for IKSolverAim /// </summary> public static void AddScene(IKSolverAim solver, Color color, bool modifiable) { // Protect from null reference errors if (!solver.IsValid(false)) { return; } if (solver.transform == null) { return; } if (Application.isPlaying && !solver.initiated) { return; } Handles.color = color; GUI.color = color; // Display the bones for (int i = 0; i < solver.bones.Length; i++) { IKSolver.Bone bone = solver.bones[i]; if (i < solver.bones.Length - 1) { Handles.DrawLine(bone.transform.position, solver.bones[i + 1].transform.position); } Handles.SphereCap(0, solver.bones[i].transform.position, Quaternion.identity, jointSize); } if (solver.axis != Vector3.zero) { Handles.ConeCap(0, solver.transform.position, Quaternion.LookRotation(solver.transform.rotation * solver.axis), jointSize * 2f); } // Selecting joint and manipulating IKPosition if (Application.isPlaying && solver.IKPositionWeight > 0) { if (modifiable) { Handles.SphereCap(0, solver.IKPosition, Quaternion.identity, selectedSize); // Manipulating position solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity); } // Draw a transparent line from transform to IKPosition Handles.color = new Color(color.r, color.g, color.b, color.a * solver.IKPositionWeight); Handles.DrawLine(solver.bones[solver.bones.Length - 1].transform.position, solver.transform.position); Handles.DrawLine(solver.transform.position, solver.IKPosition); } Handles.color = Color.white; GUI.color = Color.white; }
/// <summary> /// Rebuild the bone hierarcy and reinitiate the solver. /// </summary> /// <returns> /// Returns true if the new chain is valid. /// </returns> public bool SetChain(Transform[] hierarchy, Transform root) { if (bones == null || bones.Length != hierarchy.Length) bones = new Bone[hierarchy.Length]; for (int i = 0; i < hierarchy.Length; i++) { if (bones[i] == null) bones[i] = new IKSolver.Bone(); bones[i].transform = hierarchy[i]; } Initiate(root); return initiated; }
/* * Rotating bone to get transform aim closer to target * */ private void RotateToTarget(Vector3 targetPosition, IKSolver.Bone bone, float weight) { Quaternion rotationOffset = Quaternion.FromToRotation(transformAxis, targetPosition - transform.position); bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, rotationOffset, weight) * bone.transform.rotation; if (useRotationLimits && bone.rotationLimit != null) { bone.rotationLimit.Apply(); } }
/* * Rotating bone to get transform aim closer to target * */ private void RotateToTarget(Vector3 targetPosition, IKSolver.Bone bone, float weight) { // Swing if (XY) { if (weight >= 0f) { Vector3 dir = transformAxis; Vector3 targetDir = targetPosition - transform.position; float angleDir = Mathf.Atan2(dir.x, dir.y) * Mathf.Rad2Deg; float angleTarget = Mathf.Atan2(targetDir.x, targetDir.y) * Mathf.Rad2Deg; bone.transform.rotation = Quaternion.AngleAxis(Mathf.DeltaAngle(angleDir, angleTarget), Vector3.back) * bone.transform.rotation; } } else { if (weight >= 0f) { Quaternion rotationOffset = Quaternion.FromToRotation(transformAxis, targetPosition - transform.position); if (weight >= 1f) { bone.transform.rotation = rotationOffset * bone.transform.rotation; } else { bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, rotationOffset, weight) * bone.transform.rotation; } } // Pole if (poleWeight > 0f) { Vector3 poleDirection = polePosition - transform.position; // Ortho-normalize to transform axis to make this a twisting only operation Vector3 poleDirOrtho = poleDirection; Vector3 normal = transformAxis; Vector3.OrthoNormalize(ref normal, ref poleDirOrtho); Quaternion toPole = Quaternion.FromToRotation(transformPoleAxis, poleDirOrtho); bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, toPole, weight * poleWeight) * bone.transform.rotation; } } if (useRotationLimits && bone.rotationLimit != null) { bone.rotationLimit.Apply(); } }
/// <summary> /// Rebuild the bone hierarcy and reinitiate the solver. /// </summary> /// <returns> /// Returns true if the new chain is valid. /// </returns> public bool SetChain(Transform[] hierarchy, Transform root) { if (bones == null || bones.Length != hierarchy.Length) { bones = new Bone[hierarchy.Length]; } for (int i = 0; i < hierarchy.Length; i++) { if (bones[i] == null) { bones[i] = new IKSolver.Bone(); } bones[i].transform = hierarchy[i]; } Initiate(root); return(initiated); }
private void RotateToTarget(Vector3 targetPosition, IKSolver.Bone bone, float weight) { if (this.XY) { if (weight >= 0f) { Vector3 transformAxis = this.transformAxis; Vector3 vector = targetPosition - this.transform.position; float current = Mathf.Atan2(transformAxis.x, transformAxis.y) * 57.29578f; float target = Mathf.Atan2(vector.x, vector.y) * 57.29578f; bone.transform.rotation = Quaternion.AngleAxis(Mathf.DeltaAngle(current, target), Vector3.back) * bone.transform.rotation; } } else { if (weight >= 0f) { Quaternion quaternion = Quaternion.FromToRotation(this.transformAxis, targetPosition - this.transform.position); if (weight >= 1f) { bone.transform.rotation = quaternion * bone.transform.rotation; } else { bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, quaternion, weight) * bone.transform.rotation; } } if (this.poleWeight > 0f) { Vector3 vector2 = this.polePosition - this.transform.position; Vector3 toDirection = vector2; Vector3 transformAxis2 = this.transformAxis; Vector3.OrthoNormalize(ref transformAxis2, ref toDirection); Quaternion b = Quaternion.FromToRotation(this.transformPoleAxis, toDirection); bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, b, weight * this.poleWeight) * bone.transform.rotation; } } if (this.useRotationLimits && bone.rotationLimit != null) { bone.rotationLimit.Apply(); } }
private void RotateToTarget(Vector3 targetPosition, IKSolver.Bone bone, float weight) { if (weight >= 0f) { Quaternion b = Quaternion.FromToRotation(this.transformAxis, targetPosition - this.transform.position); bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, b, weight) * bone.transform.rotation; } if (this.poleWeight > 0f) { Vector3 vector = this.polePosition - this.transform.position; Vector3 toDirection = vector; Vector3 transformAxis = this.transformAxis; Vector3.OrthoNormalize(ref transformAxis, ref toDirection); Quaternion b2 = Quaternion.FromToRotation(this.transformPoleAxis, toDirection); bone.transform.rotation = Quaternion.Lerp(Quaternion.identity, b2, weight * this.poleWeight) * bone.transform.rotation; } if (this.useRotationLimits && bone.rotationLimit != null) { bone.rotationLimit.Apply(); } }
public override bool IsValid(bool log) { if (this.bones.Length == 0) { if (log) { base.LogWarning("IK chain has no bones. Can not initiate solver."); } return(false); } if (this.bones.Length < this.minBones) { if (log) { base.LogWarning("IK chain has less than " + this.minBones + " bones. Can not initiate solver."); } return(false); } IKSolver.Bone[] array = this.bones; for (int i = 0; i < array.Length; i++) { IKSolver.Bone bone = array[i]; if (bone.transform == null) { if (log) { base.LogWarning("Bone transform is null in IK chain. Can not initiate solver."); } return(false); } } if (!this.allowCommonParent && !IKSolver.HierarchyIsValid(this.bones)) { if (log) { base.LogWarning("IK requires for it's bones to be parented to each other. Invalid bone hierarchy detected."); } return(false); } Transform transform = IKSolver.ContainsDuplicateBone(this.bones); if (transform != null) { if (log) { base.LogWarning(transform.name + " is represented multiple times in a single IK chain. Can nott initiate solver."); } return(false); } if (!this.boneLengthCanBeZero) { for (int j = 0; j < this.bones.Length - 1; j++) { float magnitude = (this.bones[j].transform.position - this.bones[j + 1].transform.position).magnitude; if (magnitude == 0f) { if (log) { base.LogWarning("Bone " + j + " length is zero. Can nott initiate solver."); } return(false); } } } return(true); }