概述
这个功能有多种方案实现,总体可以分为两类:
1.改变腰的旋转;
2.改变手臂和头的旋转;
其中一类方案:
只要转动腰一个骨骼,比较简单;
腰以上的部分保持稳定,所以适合在第一人称使用。
使用这种方案的游戏:
尘白禁区
二类方案:
转动3个骨骼,比较复杂(因为改变仰角时双臂的旋转是一个极不规则的旋转,写代码使用正向动力学控制基本不可能,要么用IK,要么动画混合);
使用这种方案的游戏:
原神
因为枪相对头和第一人称相机的位置不固定,第一人称看到的枪的位置和远近也不固定,仰视时枪可能和头、第一人称相机穿模。
其实第一人称射击也存在这两种方案,如果手臂和相机存在父子关系,则相当于一类方案,表现为枪的远近不随仰角变化;如果手臂和相机是平级关系,相当于二类方案,表现为枪的远近随仰角变化。
animator.SetBoneLocalRotation()转动腰(最简单的方案)
需要把相应层打开IK Pass,在OnAnimatorIK()里执行animator.SetBoneLocalRotation(),可以直接改变某个骨骼的旋转。这似乎是官方推荐的方法:
Quaternion.AngleAxis()输入的轴是物体的局部坐标系的,所以要获得Spine坐标系下人物x轴的向量。Quaternion.AngleAxis()返回一个旋转变化,把它乘给spine.localRotation。这里angleX是仰角,是个会变大变小的值,怎么能做变化量?
public Animator animator;
HumanBodyBones boneToLookUpDown=HumanBodyBones.Spine;
Transform spine;
[Range(-90,90)]
public float angleX=0;
void Start(){
animator = GetComponent<Animator>();
spine=animator.GetBoneTransform(boneToLookUpDown);
}
void OnAnimatorIK(){
Quaternion spineRot=Quaternion.AngleAxis(angleX,spine.InverseTransformDirection(transform.right));
animator.SetBoneLocalRotation(boneToLookUpDown,spine.localRotation*spineRot);
}
这里animator.SetBoneLocalRotation()之前我打印了一下spine.localEulerAngles,结果是:
animator.SetBoneLocalRotation()之前spine的旋转一直不变,会被动画系统掰回原来的旋转,所以animator.SetBoneLocalRotation(xxx,spine.localRotation*deltaRot);里面虽然有spine的当前旋转,但这个旋转一直是人物姿势被改变前的旋转,这句其实是设置spine的局部绝对旋转。
如果不运行,只在编辑模式看一下效果,可以把人物的旋转归零,选Global,Rotate Tool,直接旋转Spine骨骼。
效果
动画一维混合树实现(双臂和腰都可以转动)
在3d动画软件里做出人物仰视俯视的动画,然后用一维混合树。
持枪状态在body层是一个移动的二维混合树,arm层是控制仰角的一维混合树。
第一人称效果(枪相对头的位置变化了,所以看到枪的位置不一样):
Unity使用一维混合树改变人物仰角_单机游戏热门视频 (bilibili.com)
使用IK(转动双臂和头。调整很繁琐)
轴-枪-IK-双手
节点的决定关系是:
人物改变仰角的时候枪是绕右肩旋转的,所以在瞄准姿势在人物根节点下右肩的位置放一个节点作为转轴Axis。
把枪挂载到Axis下,在枪下面建左手右手的IKGoal节点。枪应该使Axis在枪托尾部的位置。IKGoal的位置和旋转需要运行后手调。
Axis前方很远的地方建一个target,作为头看向的目标。
配置双手IK:
public Transform rightHandIK,leftHandIK;
void HandsIK(){
animator.SetIKPosition(AvatarIKGoal.RightHand,rightHandIK.position);
animator.SetIKPositionWeight(AvatarIKGoal.RightHand,1);
animator.SetIKRotation(AvatarIKGoal.RightHand,rightHandIK.rotation);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand,1);
animator.SetIKPosition(AvatarIKGoal.LeftHand,leftHandIK.position);
animator.SetIKPositionWeight(AvatarIKGoal.LeftHand,1);
animator.SetIKRotation(AvatarIKGoal.LeftHand,leftHandIK.rotation);
animator.SetIKRotationWeight(AvatarIKGoal.LeftHand,1);
}
配置头看向:
public Transform target;
void HeadLookIK(){
animator.SetLookAtPosition(target.position);
animator.SetLookAtWeight(1);
}
需要手调的变量有:
1.Axis的位置;
2.枪的位置;
3.双手IK的位置和旋转;
效果
第一人称效果:仰视的时候枪穿到了相机的Near clip plane后面,没有显示全。
看上去好像不错。这个方案的问题:
1.仰视的时候枪和头、第一人称相机穿模了。所以这个适用于第三人称,第一人称适合方案1.
2.持枪跑步、换弹、收枪、取枪的动画需要给枪的节点K帧;
轴-IK-双手-枪
这种架构左手和枪没有约束关系,可能出现左手脱离护木的问题。
使用IK方案的问题:
1.换弹动画需要关闭IK,然后无法改变仰角,如果做第一人称,换弹时可能看不到双手的动画