UpperArm Weight doesn't work

Hi,

I've set my hands weight and upper arms weight to 1 while aiming a gun and the hands work great, but the upper arm is frozen in place. I want to stop the hands weight (set it to 0) and only move the upper arm up and down based on where i'm looking. No matter what I do, the upper arm stays frozen. I don't have any animations of my gun on the upper body later, but I noticed they are mainly for equipping or melee on the other guns, so I didn't use them.

My ideal setup is hands weight = 0 (i've posted them inside my animation), upper arms ik = 1 (rotate based on player look at - up/down). Imagine pistol held with right hand, the default pose is the arm is straight, but when I look up or down I want the whole arm to rotate in the look direction.

What am I doing wrong?

Controller version 3.2.2.
 
Last edited:
The upper arm weight sets the AvatarIKHint for the hand in order to influence the elbow. This is a restriction of Unity's IK system in that it doesn't allow you to specifically set every limb. For this you will either need to switch out the animations or use something like FinalIK which gives more control.
 
For anyone who has the same problem, I made this script that moves the right arm to the look direction and also the left hand to hold the gun, because I need it for my shooting weapon, but feel free to set the weight of left hand to 0 if you just have a pistol that the character holds in the right hand.

C#:
public class TwoHandAimIKStateBehavior : StateBehavior
    {
        [SerializeField, Required] private Animator _animator;
        [SerializeField, Required] private CharacterIK _characterIk;
        [SerializeField] private Transform _leftHandGripTarget;

        [Header("IK Weights")]
        [SerializeField, Range(0f, 1f)] private float _rightHandWeight = 0.85f;
        [SerializeField, Range(0f, 1f)] private float _leftHandWeight = 1f;

    
        [Header("Pitch Limits")]
        [SerializeField] private float _maxUpAngle = 60f;
        [SerializeField] private float _maxDownAngle = 65f;

    
        [Header("Offsets")]
        [SerializeField] private Vector3 _rightHandOffset;

        private Transform _rightShoulder;
    
        // TODO: State Behavior properties to be implemented...

        private void Start()
        {
            _rightShoulder = _animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
        }

        private void OnAnimatorIK(int layerIndex)
        {
            if (!IsValid()) return;

            Vector3 lookPosition = GetLookPosition();

            Vector3 finalDirection;
            Vector3 rightHandTarget = CalculateRightHandTarget(lookPosition, out finalDirection);

            ApplyRightHandIK(rightHandTarget, finalDirection);
            ApplyLeftHandIK();
        }


        private bool IsValid()
        {
            return _animator && _characterIk && _leftHandGripTarget && _rightShoulder;
        }

        private Vector3 GetLookPosition()
        {
            return _characterIk.GetDefaultLookAtPosition();
        }

        private Vector3 CalculateRightHandTarget(Vector3 lookPosition, out Vector3 finalDirection)
        {
            Vector3 direction = lookPosition - _rightShoulder.position;

            Vector3 localDir = transform.InverseTransformDirection(direction.normalized);

            float pitch = Mathf.Asin(localDir.y) * Mathf.Rad2Deg;
            pitch = -pitch;
            pitch = Mathf.Clamp(pitch, -_maxUpAngle, _maxDownAngle);

            Quaternion pitchRotation = Quaternion.AngleAxis(pitch, transform.right);
            finalDirection = pitchRotation * transform.forward;

            Vector3 targetPos = _rightShoulder.position + finalDirection * direction.magnitude;

            // Offset in aim space
            Quaternion aimRotation = Quaternion.LookRotation(finalDirection, transform.up);
            targetPos += aimRotation * _rightHandOffset;

            return targetPos;
        }

        private void ApplyRightHandIK(Vector3 targetPosition, Vector3 direction)
        {
            _animator.SetIKPositionWeight(AvatarIKGoal.RightHand, _rightHandWeight);
            _animator.SetIKRotationWeight(AvatarIKGoal.RightHand, _rightHandWeight);

            _animator.SetIKPosition(AvatarIKGoal.RightHand, targetPosition);
            _animator.SetIKRotation(AvatarIKGoal.RightHand, Quaternion.LookRotation(direction));
        }

        
        private void ApplyLeftHandIK()
        {
            _animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, _leftHandWeight);
            _animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, _leftHandWeight);

            _animator.SetIKPosition(AvatarIKGoal.LeftHand, _leftHandGripTarget.position);
            _animator.SetIKRotation(AvatarIKGoal.LeftHand, _leftHandGripTarget.rotation);
        }


    }
 
Back
Top