第三人称结构
第三人称在AutoHandVRIK脚本初始化完毕后,会出把两只手提到玩家对象根部对象上,并且在原始的模型手的位置创建了新的对象(leftHandFollowTarget,rightHandFollowTarget),副VRIK大概用途就是IK中间过渡。大概如图下面的样子。
female01大概是我的人物,Hidden IK Copy就是副VRIK。
因为工作需要关闭和打开IK,所以这里要处理IK和手部有时要随动画摆动。
可以这样来处理
关闭角色IK
需要把手部的当前追踪follow改为AutoHandVRIK脚本leftHandFollowTarget和rightHandFollowTarget(也就是原始模型手原来的Transform位置),并且把主VRIK和副VRIK的Weight通过渐变函数改为0,这里改副VRIK的原因是启用IK的时候希望副手的位置也在当前原始点。
打开角色IK
把手部的follow换回原始的副VRIK的手部位置(这个是AutoHandVRIK在初始化时候处理的,所以我们按照他的思路来)。然后再把VRIK的Weight渐变为1就可以了。因为主VRIK的手是副VRIK的手,所以我们可以直接把正手直接改为1,渐变为1可能出现扯皮问题。
大致脚本如下:
namespace Autohand {
[DefaultExecutionOrder(-5), RequireComponent(typeof(VRIK))]
public class AutoHandVRIK : MonoBehaviour
{
//...这里省略原始代码..
//最后添加保存原来手的目标
private Transform handLeftTarget; //左手原来的目标
private Transform handRightTarget;
void SetupIKCopy() {
{
//...这里省略原始代码..
//最后添加保存原来手的目标
handRightTarget = rightHand.follow;
handLeftTarget = leftHand.follow;
}
public bool IKIsEnable = true;
float nowLerp;
float lerpspeed = 1f;
[ContextMenu("EnableIK")]
public void EnableIK()
{
IKIsEnable = true;
//打开的时候,要跟着头显手位置
nowLerp = visibleIK.solver.GetIKPositionWeight();
leftHand.SetHandTarget(handLeftTarget);
rightHand.SetHandTarget(handRightTarget);
if (checkIKSwitch != null)
{
StopCoroutine(checkIKSwitch);
checkIKSwitch = null;
}
checkIKSwitch = StartCoroutine(IKChange(true));
}
[ContextMenu("DisableIK")]
public void DisableIK()
{
//关闭IK,需要吧isCopy的比重放到拉到最低
IKIsEnable = false;
//关闭的时候要跟着手。
nowLerp = visibleIK.solver.GetIKPositionWeight();
leftHand.SetHandTarget(leftHandFollowTarget);
rightHand.SetHandTarget(rightHandFollowTarget);
if (checkIKSwitch != null)
{
StopCoroutine(checkIKSwitch);
checkIKSwitch = null;
}
checkIKSwitch = StartCoroutine(IKChange(false));
}
Coroutine checkIKSwitch;
IEnumerator IKChange(bool switchopen)
{
yield return 0;
while (true)
{
yield return 0;
if (switchopen)
{
//如果是打开IK,那么需要插值到1.最终要跟随手部设置的
nowLerp = Mathf.Lerp(nowLerp, 1.5f, Time.deltaTime * lerpspeed);
visibleIK.solver.SetIKPositionWeight(1f);
invisibleIK.solver.SetIKPositionWeight(nowLerp);
if (nowLerp > 1f)
{
break;
}
}
else
{
//如果关闭IK,显示动作,那么手跟踪原始位置
nowLerp = Mathf.Lerp(nowLerp, -0.5f, Time.deltaTime * lerpspeed);
visibleIK.solver.SetIKPositionWeight(nowLerp);
invisibleIK.solver.SetIKPositionWeight(nowLerp);
if (nowLerp < 0f)
{
break;
}
}
}
}
这样就可以直接切换了。