夹紧角度连续结果

时间:2017-01-05 14:45:49

标签: c++ 3d geometry unreal-engine4

我正在编写自己的反向运动学,目前正致力于联合约束。它很好,但我想从结果动画中删除所有不连续性,约束是最大的问题。

例如,让我们说你正在看着绕着你的头旋转的球。它向右旋转,你看起来正确,直到你的脖子扭曲限制。球仍在移动,当它经过你的背部时,你的头部会突然被相反的限制,向左看。这就是我们通过典型的夹紧方式得到的结果,它给了我框架到框架的不连续性。

我需要的是你的头在几帧内从右到左。我的第一个想法是用我的X轴(肩部之间)反映源方向,如果反射方向满足约束限制 - 返回它。如果它不符合限制 - 剪切反射方向而不是源方向。

这应该给我一个美好而持续的运动,它不是一个火箭科学,但有许多细节需要照顾。我的限制可能类似于min < max,但也可能是max < min,它们可能会通过切换角度值(例如360->0180->-180)。此外,当我允许的范围大于180度时,逻辑应该略有不同。

不同案件的数量增长非常快,所以我想知道我是否能在某处找到它?

顺便说一句:如果它出现任何差异,我会使用虚幻引擎。

修改

对不起,如果我用我的头脑示例误导了你 - 这只是想象我的需求的类比。我不打算使用此代码来定位最终动画中的头骨(或任何其他骨头)。我计划将其用作解决IK的基本操作。它将在每个IK链中的每个迭代中用于每个骨骼,多次使用。所以它需要尽可能快。如果需要,所有更高级别的概念,如运动规划,动态等,都将添加到另一层。

现在我只想要一个像:

这样的功能
float clampAngle( float angle, float min, float max )

将返回连续值以更改输入。

我目前处理不同的问题,但是当我回到这个问题时,我会发布我的代码。

2 个答案:

答案 0 :(得分:1)

如果你认为这是一个模拟,它会更加清晰。您的评论中不需要任何计划,因为下一帧仅使用当前帧上可用的信息计算。

如前两段所述,为颈部设置一个关节。当球到来时,它将在一帧中从左向右翻转。

然后设置第二个相同的关节并写出一个角度弹簧,随着时间的推移将其旋转到第一个关节。通过调整弹簧系数 - 强度,阻尼等 - 您可以控制磁头旋转的方式。

如何写角弹簧?

这可能不是最好的方法,但代码非常简短,所以这里......

让我们调用2个关节主人和一个奴隶。您需要在从属关节上存储旋转phi和角速度omega

phiomegamanual update - 一个3d矢量,其大小是围绕由矢量定义的轴旋转的弧度数。它使模拟旋转变得非常容易。无论您的关节旋转是作为欧拉角或矩阵还是四元数存储,您都可能有一些联合UE API的类来帮助提取轴/角度向量。

当主关节改变时,将其旋转转换为轴角。让我们称之为phi_m

在起始帧上,从属旋转phi应设置为与master相同的值。 phi = phi_m。它没有角速度,因此omega设置为零向量(0,0,0)

然后你前进一帧。帧长dt可能是1/60秒或其他。

在模拟你的同时,首先计算出phi_m的新值。然后主从和(矢量phi_m - phi)之间的差异表示作用在从动关节上的扭矩。 axis-angle vectors。假设质量为1.0,则使用F = ma,角加速度alpha等于扭矩。这意味着在该帧上从属关节的角速度变化为alpha*dt。现在我们可以计算出新的角速度:omega = omega + (alpha*dt)。类似地,新旋转是旧旋转加上随时间旋转的变化(角速度)。 phi = phi + (omega * dt)

将所有内容放在一起并添加弹簧strengthdamping的系数,模拟步骤可以是这样的:

damping = 0.01 // between 0 and 1
strength = 0.2 // ..experiment
dt = currentTime-lastTimeEvaluated

phi_m = eulerToAxisAngle(master.rotate)
if (currentTime <= startTime || dt < 0) {
  slave.phi = phi_m
  slave.omega = (0,0,0)  
} else {
  alpha = (phi_m - slave.phi)*strength
  slave.omega = (slave.omega * (1.0 - damping)) + (alpha*dt)
  slave.phi = slave.phi + slave.omega*dt
}
slave.rotate = axisAngleToEuler(slave.phi)
lastTimeEvaluated = currentTime

请注意,阻尼只会消除一点存储的速度。如果阻尼非常低,则关节会过冲并振荡到位 - boing !!

答案 1 :(得分:0)

一种方法:

  • 定义不能满足约束的区域(头部后面的锥形)
  • 测量目标所在区域的距离(目标与锥心之间的角度除以半锥角)
  • 使用此标量值将受约束的物体平滑地混合回某个预定义的中立位置(即当目标移动到头部后方时,将头部平稳地转回到中心/静止位置)