现在我们的角色已经能像我们期待的那样,能随着我们的控制而走动了,但是现在和实际的效果还有一定的差距。
其中一个差距在于,起始和终止的时动作的质量。如果我们仅让角色移动一点儿,那么角色的步伐会看起来一顿一顿的,或者是在滑动,发生这种情况的原因在于,在行走、停止的状态转移过程中,没有任何限制,我们仅仅是在对应指令下执行相应的操作。所以这一教程中,我们将要做一点设置,使得卡顿的步伐能够和动画制作者的动画匹配。
另外一个差距在于每次角色停止的时候,总是左腿在前的。这也就意味着有很大可能性出现这样的局面:当人物正在迈右脚向前的时候,使其停止,这时角色会在短时间内变成左脚在前,看起来非常突兀。
现在我们要做的就是,不应当总是播放左腿在前的停止动画,我们将会介绍一些动画镜像工具来做出正确的变换效果,也就是说,角色开始或者停止的时候,他迈的腿总是正确的那个,这样就能提高它的行为图的质量。
我们已经有两个脚本,一个在idle状态,另外一个在idle to run的状态。它们的作用是控制一些弹性量的值。在idle状态下,用户移动手柄,当变化达到了一定阈值的时候,我们计算动画的方向,然后立即使得角色开始运动,这时我们从idle状态变化到idle to run状态。
这时候我们在idle to run的状态下,我们做类似的逻辑判断,区别在于这次我们是松开手柄然后角色停止;这些行为的响应速度很快,但是动画质量并不那么好,因为变换的过程过早地被打断了,所以现在你所得到的结果显得比较笨重。我们所希望的是角色能够完成完整在某一方向上完整的一步动作,而不是立刻就停止了。所以我们需要这两个过程遵循一定的规则。
我们关注的第一件事情是定时,为了做到这一点,我们选择Idle to Run事件 ,在高级菜单栏中勾选Do Not Interrupt,使之不要被打断,能够完整地播放。
此外,对于Idle to Run to Run事件,我们勾选Abut at End of From State,来强制idle to run再返回idle时播放完整。
这时候我们演示一下动画,会发现虽然我们勾选了动画播放结束,但是在连贯上依然有些问题,旋转并没有进行到100%。这意味着我们还需要设置一些别的东西。我们点击stop事件(idle to run与idle之间),然后设置Flags为FLAG_IGNORE_TO_WORLD_AND_FROM_MODEL_ROTATION,来排除from/to状态旋转的干扰。我们之所以没有完成完整的旋转动画,是因为from和to两个状态进行了混合运算,由于我们是和没有任何动作的idle状态进行混合计算的,所以我们就丢失了一些旋转的信息。而之所以没有选择FLAG_IGNORE_TO_WORLD_AND_FROM_MODEL,是因为我们仍然希望保留位动作上的插值。
接下来我们要介绍的是动画的镜像。为了做到这一点,我们首先要添加一个变量:
参数设置如上。
之后,我们在每一帧都去计算这个参数的值,这样它就能精确地指出角色当前的姿态了。现在我们在havok的脚本中加入判断的代码:
-- called every time the locomotion state is updated
function onLocomotionUpdate()
-- update the gamepad state
g_gamepadState:update()
-- update the camera state
g_cameraState:update3rdPerson()
-- Compute which foot is forward and store it in a behavior variable
local leftLegIndex = hkbGetBoneIndex("LeftLegCalf")
local rightLegIndex = hkbGetBoneIndex("RightLegCalf")
local leftLegModelSpace = hkbGetOldBoneModelSpace(leftLegIndex)
local rightLegModelSpace = hkbGetOldBoneModelSpace(rightLegIndex)
local leftForward = leftLegModelSpace:getTranslation():dot3(FORWARD_AXIS)
local rightForward = rightLegModelSpace:getTranslation():dot3(FORWARD_AXIS)
if rightForward > leftForward then
hkbSetVariable("IsRightFootForward", 1)
else
hkbSetVariable("IsRightFootForward", 0)
end
end
以上代码计算出了左右脚当前在forward方向上的坐标,并根据大小来判断谁在前方,以动态地更新rightForward这个值。
我们在这一脚本上加上一个选择器:
并将其重命名为Idle Mirror。他所需要做的选择是:左脚在前或者是右脚在前。
进入Idle Mirror,我们双击Generators:
点击添加新建一个选项:
点击1处的... ,创建一个新的Clip, 选择Idle_0.hkt
双击新的数值进入编辑,将变量重命名为Idle Mirror,并勾选Mirror Animation
这时候我们再来调整选择器,使得IsRightFootForward变量来控制选择器:
同样地,对于run turn 180,我们创建一个选择器,重命名为Run Turn 180 Mirror。
为新增的子选择器,勾选single play以及continue事件,并勾选Mirror Animation。和之前一样,我们让IsRightFootForward来控制这一状态。
不同的是,需要注意一点,我们要把Selected Index Can Change After Activate的选择取消,这样它就不会在每帧都去计算了。
类似地,我们对run这么做:
剩余的操作和前面类似。唯一需要注意的是,我们之前为了匹配上准确的脚的方位,延迟了Start Time,但是在这里我们已经不需要了,因为我们已经判断了当前的正确方向。