How to Aim Animator.SetIKRotation() to direction WRT hand bone rotation offset?

I’m trying to make a firearm which is parented to the hand aim directly forward to where the character is facing.

I assumed this would be easy with

Animator.SetIKRotation(AvatarIKGoal.RightHand,Quaternion.LookRotation(SubjectObj.transform.forward));

But I’m testing this on 4 different rigs and getting inconsistent results because of the default orientation of hand bones - also screwing it up is the axis of the hand bones.

Currently the weapon is put into the hand like this:

Quaternion WeaponOrientationInHand()
{
   Quaternion foo =Quaternion.LookRotation(
     (Subject.InvertHandForward ? -RightHandBone().right : RightHandBone().right),
     RightHandBone().TransformDirection(Subject.Stats.ThumbDirection));
   return foo;
}

bonetransform.right is X aiming down the arm. Some rigs have it inverted… This part actually works great. The weapon sets in the hand perfectly every time even with totally jacked up bone setups.

Then the weapon it parented to the hand bone and I make IK calls to put the hand bone where I want it, but then I need to rotate the hand so that the gun actually points forward but I can’t seem to figure out the rotation math to do it. I’m stuck here.

I’ve tried various things to get the rotation but bottom line I can’t figure out how to compensate for the base hand rotation offset variance even when I know all of the correct variables. ThumbDirection and X direction should be enough to formulate a signed direction but I need some help figuring out doing this with the rotations respecting that.

Tried posting this on Answers, but for some reason my posts now go to Moderation?

1 Like

Here are some pics to illustrate what is happening.

I’m kind of at a loss why this doesnt work:

Animator.SetIKRotation(AvatarIKGoal.RightHand,Quaternion.LookRotation(SubjectObj.transform.forward));

The LookRotation() should align the Hand forward axis to the player’s forward axis, right?

The Weapons set into the hands correct, the IK just doesn’t seem to set the rotation precisely. Tried some options with layering in the Animator too, didn’t seem to change anything.

Here is a helpful class to test you hand ik target

  1. create a new scene
  2. add you character with script below attached
  3. create a sphere/cude and drop it to rightHandIKGoal variable

instead of using this Quaternion.LookRotation(SubjectObj.transform.forward) you can just change the position/rotation of the rightHandIKGoal, I think it’s much easier and intuitive

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class HandIK : MonoBehaviour {

    public bool enabledIK;
    public Transform rightHandIKGoal = null;
   
    Animator animator;

    // Use this for initialization
    void Start () {

        animator = GetComponent<Animator>();
    }
   
    // Update is called once per frame
    void Update () {

        animator.Update(0.0f);
   
    }

    void OnAnimatorIK(int layerIndex)
    {
        if (enabledIK)
        {
            animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1.0f);
            animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandIKGoal.rotation);

            animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1.0f);
            animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandIKGoal.position);
        }
        else
        {
            animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0.0f);
            animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0.0f);
        }
    }
}

Yes but the problem is that the hand does not align to the given target. There is some sort of offset from the rig that the IK does not take into consideration.

Thats why I’m building a rotation to add to it to make up the difference, but my efforts to do that haven’t been working.

Here’s the current code, which basically produces the same result as the LookRotation() alone.

private void SetRightHandIk()
        {
            Animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
            Animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1);

            Animator.SetIKPosition(AvatarIKGoal.RightHand, DominantWeaponRestPoint() * CharScaleMultiplier);
            Animator.SetIKRotation(AvatarIKGoal.RightHand, desiredRotation);

            _deltaRotation = Quaternion.Inverse(RightHandBone().rotation) * SubjectObj.transform.rotation;
            desiredRotation = RightHandBone().transform.rotation*_deltaRotation;
        }

Here are the results…
2303019--155091--shot_150919_140845.png

Red line are actual, green lines are what it should be.

The zombie is the worst rig, the other 3 are pretty good but all yield different offsets. In any case, the detal calc and multiplication isn’t working to fix the issue.

I don’t really understand what you do here

RightHandBone() is a Transform ?

Yes, its just a shorthand method. The code should be getting the delta rotation between where it should be pointing and where it is pointing, then adding it to the desired rotation to compensate for the offset. It doesnt seem to work.

Transform RightHandBone() { return Animator.GetBoneTransform(HumanBodyBones.RightHand); }

so finaly desiredRotation is SubjectObj.transform.rotation

you don’t need to make inverse and multiply it by it self its an identity, right ?

I think if you use the script I sent earlier, you can control the aim easly.

and to avoid an extra computation, you can create the rightHandIKGoal with a child Transform, and apply all the offset to the child

animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandIKGoal.child(0).rotation);

in that way you can control rightHandIKGoal in the same way for all your character

I need to pragmatically fix the rotation, i can’t manually do it in the inspector for each character because it will never be exact. The entire problem is that SetIKRotation is not setting the rotation correctly, there is some inherit offset from each model’s hand rotation that is screwing it up and must be fixed pragmatically.

1 Like

I can’t really help cause I don’t have such model’s, if you know any free model that I can do a test with send me a link

The zombie is free, and its quite a messy rig.

will give it try and let you know

Thanks, here is what I’m doing for the debug rays.

        void Update()
        {
            Debug.DrawRay(RightHandBone().position, RightHandBone().right * 2, Color.red);
            Debug.DrawRay(RightHandBone().position, SubjectObj.transform.forward, Color.green);
// the zombie's X is actually inverted, so you need -RightHandBone().right
        }

Technically this problem should be evident on any rig, I’ve used 4 different ones with the same Animator Controller and they all exhibit some amount of offset caused by how the model is rigged/setup which Mecanim’s retargeting does not compensate for.

The goal is to get the hand to orient inline with a given direction.

Transform arm = animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
Quaternion lookAt = Quaternion.LookRotation(rightHandIKGoal.position - arm.position);

animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandIKGoal.rotation * lookAt );

That doesnt seem to work.

Ok either I’m going crazy, or there is some magical hand rotation offset buried in the Humanoid rig that you have to have to use to get the hand to point at something properly.

if (DummyTarget) Animator.SetIKRotation(AvatarIKGoal.RightHand, Quaternion.LookRotation(DummyTarget.position - RightHandBone().position));

Produces this:

I’m at wits end. It seems like a bug at this point. The wireframe of the IK target isn’t even in the right spot!

The only way that even sort of works is adding a ‘correction’ vector to the LookRotation(), then tweaking it until it looks straight and applying that to the prefab. It’s not perfect, but it seems like the best that can be done at this point.

FYI for those interested I filed a bug report on this last night and it was repro’d/accepted this morning. (<12 hrs[!])

You can also get the delta quaternion and iterate closer to the correct direction, I was just doing the math wrong. It still doesn’t seem to get it perfect, but I think that has something to do with the same issue thats causing the offset to begin with. The same exact code in Debug rays does what it is intended to do.

1 Like

@LaneFox So we did investigate this issue and the offset that you see is related to your avatar T-pose. If you want a perfect match you need to align your hand characterization pose on the X axis.

1 Like

@Mecanim-Dev Ahh, I found where you can adjust the bone rotation in the Avatar Configuration screen. Was not aware we could make changes there. Did not test to confirm yet - out of town all this week.

Is there a way to auto-align this or bind the avatar into a known T-pose that will alleviate alignment issues like this one? It’s not ideal to have users manually adjust their avatars by eyeballing the hand alignment, especially so if you need to rely on the hand pointing in a specific direction with consistency.

The best way would be to keyframe your t-pose in your authoring tools (3dsmax, maya, blender, etc…) and then import the file to create your avatar.

1 Like