如何在关键帧之间进行平滑插值?

How do I get a smooth interpolation between keyframes?

我正在尝试为我的 three.js 项目制作一个动画系统。我有一个 json 文件来获取信息。我能够播放动画。但是,在他们需要在某个地方的那一刻,他们移动到那个位置,而不是随着时间的推移慢慢移动到那个位置。 json 文件告诉程序特定对象需要在某个位置。例如:

Json 文件:

{
"right": {
    "position": {
        "0.0": [0, 0, 0],
        "0.25": [0, 1, 0],
        "0.5": [1, 1, 0]
    }
}

Json 文件告诉你位置,在什么时候,然后是位置。

代码:

for (const [key, value] of Object.entries(json.position.right)) 
  if(seconds === json.position.right[key]) {
    obj.position.x = json.right.position[key][0];
    obj.position.y = json.right.position[key][1];
    obj.position.z = json.right.position[key][2];
  }
}

在代码中,我循环遍历 json 文件的右立方体位置(它告诉位置何时发生变化)。如果秒匹配,它会移动到那个位置。

我怎样才能在对象的关键帧之间移动?

示例如下:https://mixed-polyester-a.glitch.me/

这是全部代码:https://glitch.com/edit/#!/mixed-polyester-a

我使用 Blockbench 将模型导出为 .OBJ 文件,将材质导出为 .MTL 文件,将动画导出为 .JSON 文件。

抱歉,如果这听起来令人困惑,我真的不知道如何解释。任何帮助将不胜感激。

Three.js 有 a method called MathUtils.lerp() 取起始位置、结束位置和 [0, 1] 之间的插值。您可以使用它在每一帧上将对象的当前位置补间到其目标位置,如下例所示:

const container = document.getElementById("container");
const ball = document.getElementById("ball");

// Set current positions
let ballPosX = 0;
let ballPosY = 0;

// Set target positions
let ballTargetX = 0;
let ballTargetY = 0;

// Update target positions on click
function onClick(event) {
  ballTargetX = event.layerX;
  ballTargetY = event.layerY;
  //console.log(event);
}

function update() {
  // Interpolate current position towards targets
  ballPosX = THREE.MathUtils.lerp(ballPosX, ballTargetX, 0.1);
  ballPosY = THREE.MathUtils.lerp(ballPosY, ballTargetY, 0.1);
  
  // Apply current position to our object
  ball.style.left = ballPosX + "px";
  ball.style.top = ballPosY + "px";
  requestAnimationFrame(update);
}

container.addEventListener("click", onClick);
update();
#container {
  width: 300px;
  height: 300px;
  background: #ddd;
}

#ball {
  width: 10px;
  height: 10px;
  position: absolute;
  top: 0;
  left: 0;
  background: #f90;
  border-radius: 10px;
  margin-top: -5px;
  margin-left: -5px;
}
<div id="container">
  <div id="ball"></div>
</div>

<script src="https://threejs.org/build/three.js"></script>

更新:

为了创建带有关键帧的线性时间轴,我使用 gsap.to() 和关键帧参数将所有位置提供给时间轴。 See here and look up "keyframes" 了解更多详情。您可以在下面的代码演示中看到它的运行情况,不过您需要遍历 JSON 以自行将该数据提供给 GSAP。祝你好运!

// Set position vector
const ballPos = {x: 0, y: 0};
const positions = {
    "0.0": [0, 0],
    "0.25": [0, 100],
    "0.5": [100, 100],
    "0.75": [100, 0],
    "1.0": [0, 0],
}
const timeline = gsap.to(ballPos, {keyframes: [
  {x: positions["0.0"][0], y: positions["0.0"][1], duration: 0.0},
  {x: positions["0.25"][0], y: positions["0.25"][1], duration: 0.25},
  {x: positions["0.5"][0], y: positions["0.5"][1], duration: 0.25},
  {x: positions["0.75"][0], y: positions["0.75"][1], duration: 0.25},
  {x: positions["1.0"][0], y: positions["1.0"][1], duration: 0.25},
]});

const container = document.getElementById("container");
const ball = document.getElementById("ball");


let timelineTime = 0;
function update() {
  timelineTime += 0.001;
  timelineTime %= 1;
  timeline.seek(timelineTime);

  // Apply current position to our object
  ball.style.left = ballPos.x + "px";
  ball.style.top = ballPos.y + "px";
  requestAnimationFrame(update);
}

update();
#container {
  width: 300px;
  height: 300px;
  background: #ddd;
}

#ball {
  width: 10px;
  height: 10px;
  position: absolute;
  top: 0;
  left: 0;
  background: #f90;
  border-radius: 10px;
  margin-top: -5px;
  margin-left: -5px;
}
<div id="container">
  <div id="ball"></div>
</div>

<script src="https://threejs.org/build/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.1/gsap.min.js"></script>