Universal Tween Engine / LibGDX:模型在序列之间丢失变换和旋转

Universal Tween Engine / LibGDX: models losing transform and rotation between tweens in sequence

我正在开发 3d 游戏并尝试正确设置角色移动。交互很简单,屏幕上只有一个模型,用户点击屏幕上的一个点,模型旋转面对点击的点(现在模型是一个有眼睛的小幽灵,所以眼睛转向点击的点点),一旦面向该点,模型就会移动到该点。

我用自己编写的一些代码进行了此操作,但动画并不流畅,模型经常 overshoot/undershoot 到达目的地,然后向后或向前猛拉到位。之前我只在 2d 动画中使用过 Universal Tween 引擎,但决定试一试。它解决了抖动问题,旋转和变换都可以单独工作,但我无法让它们按顺序一起工作。

如果我只启用旋转模型的代码,它就可以正常工作(好吧,几乎可以,有些东西会变得很奇怪 w/ 在某些角度确定顺时针或逆时针旋转,但这是以后的另一个问题):我单击一个位置,模型旋转以面对它并保持新的旋转直到下一次单击,然后它转向面对该位置。与仅启用翻译相同:我单击一个点,模型移动到它并保留它的新翻译,直到我再次单击,然后它移动到该位置,等等。

同时启用平移和旋转时,我遇到了问题。模型将首先旋转以面向单击点,然后设置回其初始旋转,然后移动到单击点。在随后的点击中,模型将首先回到其初始平移,然后旋转以面对点击点(实际上是点击点相对于重新初始化位置的位置),然后移动到点击点。

我试过重新排列代码,使用回调,将新的平移和旋转缓存到游戏模型的成员 class,然后在开始补间之前使用 set() 和它们的值,但没有任何效果成功了。

这是我的 TweenAccessor 的相关代码:

public class GameModelTweenAccessor implements TweenAccessor<DynamicModel> {    
    public int getValues(DynamicModel target, int tweenType, float[] returnValues) {
        trans = target.model.transform.getTranslation(trans);
        switch (tweenType) {
            ...
            case POSITION_XYZ:
                returnValues[0] = trans.x;
                returnValues[1] = trans.y;
                returnValues[2] = trans.z;
                return 3;
            case ROTATION:
                axisVec = new Vector3();
                angle = target.model.transform.getRotation(new Quaternion()).getAxisAngle(axisVec) * axisVec.nor().y;
                returnValues[0] = angle;
                return 1;
            ...
        }

    }

    public void setValues(DynamicModel target, int tweenType, float[] newValues) {
        trans = target.model.transform.getTranslation(trans);
        switch (tweenType) {
            ...
            case POSITION_XYZ:
                target.model.transform.setToTranslation(newValues[0], newValues[1], newValues[2]);
                break;
            case ROTATION:
                target.model.transform.setToRotation(Vector3.Y, newValues[0]);
                break;
            ...
        }
    }
}

这是启动时间线和补间的代码(在 this file 中):

Timeline.createSequence()
    .push(Tween.to(screen.ghost, GameModelTweenAccessor.ROTATION, Math.abs(angle - newRotation) / 200)
        .target(newRotation)
        .ease(TweenEquations.easeNone))
    .push(Tween.to(screen.ghost, GameModelTweenAccessor.POSITION_XYZ, duration).
        target(intersection.x, intersection.y, intersection.z)
        .ease(TweenEquations.easeNone))
    .start(screen.ghostManager);

任何人都可以指出我的解决方案吗?

编辑: 似乎每个补间完成后设置的转换在另一个补间完成后重置为 0。这些是 TweenAccessor:

getValuessetValues 函数的那些值的日志
Get Rot: 0.0

Get Trans: x: 0.0          y: 0.0          z: 0.0

Get Rot: 0.0

Get Trans: x: 0.0          y: 0.0          z: 0.0

Get Rot: 0.0

Set Rot: 9.598349
Set Rot: 9.814415
Set Rot: 10.052449
...
Set Rot: 39.99417
Set Rot: 43.397423
Set Rot: 46.62333

Get Trans: x: 0.0          y: 0.0          z: 0.0

Set Trans: x: 0.0012489144 y: 0.0          z: 0.001180494
Set Trans: x: 0.024489587  y: 0.0          z: 0.023147952
Set Trans: x: 0.04921494   y: 0.0          z: 0.04651875
...
Set Trans: x: 6.4197707    y: 0.0          z: 6.06807
Set Trans: x: 6.444479     y: 0.0          z: 6.091425
Set Trans: x: 6.453598     y: 0.0          z: 6.1000443

Get Rot: 0.0

Get Trans: x: 6.453598     y: 0.0          z: 6.1000443

Get Rot: 0.0

Get Trans: x: 6.453598     y: 0.0          z: 6.1000443

Get Rot: 0.0

Set Rot: 3.4318955
Set Rot: 6.795984
Set Rot: 10.0074415
...
Set Rot: 156.79567
Set Rot: 159.99591
Set Rot: 162.38742

Get Trans: x: 0.0          y: 0.0          z: 0.0

Set Trans: x: 0.03550978   y: 3.836017E-8  z: 0.021066409
Set Trans: x: 0.15527377   y: 1.6773768E-7 z: 0.092117175
...
Set Trans: x: 6.848614     y: 7.3983565E-6 z: 4.062985
Set Trans: x: 6.961268     y: 7.5200533E-6 z: 4.129818
Set Trans: x: 7.0624847    y: 7.6293945E-6 z: 4.189865

Get Rot: 0.0

Get Trans: x: 7.0624847    y: 7.6293945E-6 z: 4.189865

Get Rot: 0.0

Get Trans: x: 7.0624847    y: 7.6293945E-6 z: 4.189865

Get Rot: 0.0

Set Rot: -3.2620814
Set Rot: -6.8205137
Set Rot: -9.834579
...
Set Rot: -76.57533
Set Rot: -79.91388
Set Rot: -80.610855

Get Trans: x: 0.0          y: 0.0          z: 0.0

Set Trans: x: 0.01940876   y: 0.0          z: 0.033669088
Set Trans: x: 0.04174851   y: 0.0          z: 0.07242267
Set Trans: x: 0.06332677   y: 0.0          z: 0.109855264
...
Set Trans: x: 2.7853239    y: 0.0          z: 4.8318033
Set Trans: x: 2.808029     y: 0.0          z: 4.8711905
Set Trans: x: 2.827034     y: 0.0          z: 4.9041595

getValues 在补间开始之前,每种类型的补间(平移和旋转)被调用两次。此时,翻译的值仍然是上次翻译补间结束时设置的值。不过,旋转的值已设置回 0(我猜测是下一堆调用 setValues 进行旋转的结果)。

然后多次调用

setValues进行轮换,直到达到目标轮换。这是(除了重置旋转之外)如我所料和希望的那样工作。尽管在 getRotation 调用之后,翻译设置回 0,0,0,但不是通过调用 setValues(没有它的日志)。然后通过几次 setValues 调用将翻译动画化到目标。

在此之后,循环会在再次单击时重新开始,并且 getValues 会再次调用两次以进行旋转和平移。翻译具有在最后一次 Timeline 中最后一次调用 setValues 时设置的值,但仅在旋转(返回 0)通过其补间之前设置。

getValues 的 4 次调用可能有点问题。我不确定我的设置中的什么会导致 Timeline 会在其补间开始之前获取翻译的值,如果它们应该在被推入 Timeline 时按顺序运行的话。我也不确定为什么每个补间调用两次 getValues,但补间引擎在补间过程中调用它两次并非不可行。

我很确定我使用的 LibGDX 中的 translation/rotation 函数很好,它们 'stick' 用于模型,我也使用相同的方法进行翻译使用我的非 Tween-Engine 版本。旋转类似,但功能不一样。

不过,第二次翻译期间 Y 值的变化值得研究。

因此该解决方案与通用补间引擎或其实现方式无关。只是我对LibGDX中的矩阵变换函数的理解很差。对 setToRotation 的调用会重置变换矩阵,然后仅应用旋转,从而将先前的平移归零。 setToTranslation同理,造成旋转丢失

为了翻译,我用了setTranslation代替,旋转也没有丢失。我认为没有可比的旋转功能(使用 rotate 会导致各种问题),所以我得到一个新的 Vector3 并在其中存储模型的位置,然后应用 setToRotation,然后将翻译设置为新向量。这是来自 TweenAccessor:

的更新代码
public void setValues(DynamicModel target, int tweenType, float[] newValues) {
    trans = target.model.transform.getTranslation(trans);
    switch (tweenType) {
        ...
        case POSITION_XYZ:
            target.model.transform.setTranslation(newValues[0], newValues[1], newValues[2]);
            break;
        case ROTATION:
            // store the position
            Vector3 position = target.model.transform.getTranslation(new Vector3());
            // then set the rotation and reset the translation
            target.model.transform.setToRotation(Vector3.Y, newValues[0]).setTranslation(position);
            break;
        default:
            assert false;
            break;
    }
}