msm

Hi,

I am trying to programmatically pin my character's arm to a point (ledge grabbing). I have a SkeletonUtilityBone set to Override, and when I want to pin the arm, I enable it and continuously set the world position to the desired point during Update().

This works, but I have an issue where the arm stutters while a parent bone is rotated. The parent bone is rotated to follow the mouse cursor for aiming a gun. The arm IK is a child of this rotated bone so that the arms will rotate with the gun. In my ledge grab scenario though, I want the child arm to stick to a specific point. So Spine is fighting to rotate the arm with the parent, then I pull it back into my desired place, and the result is a stuttering while aiming.

Is there a better approach I can take? Any suggestions?

One thought I am trying out, is to turn off IK (set the Mix to 0) for the arm to be pinned, and then just use the IkConstraint to calculate the bone SRTs and update them myself, like
Vector2 ledgePoint = ... // the world point to pin to
SkeletonUtilityBone armIK = ... // the arm IK bone
IkConstraint c = ... // the arm ik constraint
armIK.bone.x = ledgePoint.x;
armIK.bone.y = ledgePoint.y;
armIK.bone.UpdateWorldTransform();
IkConstraint.Apply(c.Bones.Items[0], c.Bones.Items[1], armIK.bone.WorldX, armIK.bone.WorldY, c.BendDirection, 1f);
but still trying to get that to work

Thanks for the help

-- 16 Mar 2016 10:14 am --

I just read about Transform Constraints, Use case for transform constraint

Is that something I could use to solve my issue?
msm
  • Сообщения: 52

Pharan

There are two things to do to make this VERY VERY SIMPLE. No SkeletonUtility required.
(1) Keep your root bone at the origin point. Don't animate it. Don't rotate it. Don't do anything to it in setup mode. This is important for step 2.
(2) Keep your IK targets as immediate children of the root bone. Because of Step 1, their local positions will be equal to their skeleton-space positions.

And I personally recommend keeping your root bone at the default position and origin point (0,0) for all your skeletons. If you don't, that's an extra step negating the root bone's transform effects. But there are plenty of other animation-/rig-centric reasons to do this like making skeleton.flipX work predictably, being able to define bones and IK targets that won't move with other things.

Just subscribe to SkeletonAnimation or SkeletonAnimator's UpdateLocal.
// UpdateLocal happens after animations are applied but before IK Constraints are applied.
skeletonAnimation.UpdateLocal += HandleSetBonePosition;
Then have your method
Spine.Bone myIkTargetBone;
bool isGrabbing;

void HandleSetBonePosition (ISkeletonAnimation s) {
if (isGrabbing) {
myIkConstraint.Mix = 1f;
Vector2 ledgePointLocalSpace = skeletonAnimation.transform.InverseTransformPoint(ledgePoint); // your ledgePoint
myIkTargetBone.X = ledgePointLocalSpace.x;
myIkTargetBone.Y = ledgePointLocalSpace.y;
}
// set myIkConstraint.Mix 0? Or handle that elsewhere?
}
The part where the parent kinda shakes because of the child or whatever. I'm not sure if the cause is an order-of-operations thing. Depending on where you put it, it could be completely working, or completely not working. But it could also be the other SkeletonUtilityBones following or overriding and fighting with each other.
Аватара пользователя
Pharan
  • Сообщения: 5366

msm

Thanks for the suggestion.

I was trying to avoid reworking any animations. I am actually building off of the Gunman asset pack, and those animations are built with the parent being the pivot bone for aiming. And my ledge grabbing is actually a one-arm grab, since I wanted to retain the ability for aiming and shooting with the other arm while hanging.

I actually came to the same conclusion, that I would need to just add another copy of the arm bones at the root with a separate IK constraint, and just hide the original arm and show the grabber arm when needed.

Thanks for the help
msm
  • Сообщения: 52

Pharan

If you need to use SkeletonUtilityBone, it's a matter of switching the right ones between Follow and Override mode. If they're mixed within a chain, they'll definitely fight over where one is supposed to go and whatever. That's another reason to keep your IK targets on separate parts of the hierarchy anyway.

In any case, when you're using SkeletonUtilityBone, there should be no reason for you to manually call IkConstraint.Apply or set bone positions manually. The SkeletonUtilityBone Override will do that for you.

Also, yes. IkConstraint.Mix value is designed to be changed at runtime by code or by animations so you should change that around to whatever value you need.
Аватара пользователя
Pharan
  • Сообщения: 5366

msm

Hey,

yeah, the only reason I was trying the manual approach was I had the same thought that it might be an order-of-operations thing, if I had the Mix set 1, if the IK constraint was being applied and fighting with where I wanted the arm to go. So I tried keeping the constraint disabled, and just then manually updating the position myself... but I had the same stuttering problem.

So I think it is just the issue that the bone is a child of a parent that is rotating. Like you suggested, I am going to try using a separate bone at the root outside of the bone being pivoted. I read in another thread about hiding/showing bones, and it looks like I will just need to write an extension to SkeletonRenderer? That is my current plan.
msm
  • Сообщения: 52


Вернуться в Unity