插值

插值是图形编程中一个非常基本的操作. 作为一名图形开发人员, 熟悉它有助于扩展你的视野.

基本思想是从 A 转换到 B。t 值是介于两者之间的状态。

举个例子, 如果 t 是0, 那么他的状态是A. 如果 t 是1,那么它的 状态是B. 任何介于两者之间的状态都是 插值.

Between two real (floating-point) numbers, an interpolation can be described as:

  1. interpolation = A * (1 - t) + B * t

通常简化为:

  1. interpolation = A + (B - A) * t

The name of this type of interpolation, which transforms a value into another at constant speed is “linear”. So, when you hear about Linear Interpolation, you know they are referring to this formula.

还有其他类型的插值, 这里将不做讨论. 建议之后阅读 Bezier 页面.

向量插值

Vector types (Vector2 and Vector3) can also be interpolated, they come with handy functions to do it Vector2.lerp() and Vector3.lerp().

对于三次插值,还有 Vector2.cubic_interpolate()Vector3.cubic_interpolate() ,它们执行 Bezier 式插值。

Here is example pseudo-code for going from point A to B using interpolation:

GDScriptC#

  1. var t = 0.0
  2. func _physics_process(delta):
  3. t += delta * 0.4
  4. $Sprite2D.position = $A.position.lerp($B.position, t)
  1. private float _t = 0.0f;
  2. public override void _PhysicsProcess(double delta)
  3. {
  4. _t += (float)delta * 0.4f;
  5. Marker2D a = GetNode<Marker2D>("A");
  6. Marker2D b = GetNode<Marker2D>("B");
  7. Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
  8. sprite.Position = a.Position.Lerp(b.Position, _t);
  9. }

它将产生以下运动:

../../_images/interpolation_vector.gif

变换插值

It is also possible to interpolate whole transforms (make sure they have either uniform scale or, at least, the same non-uniform scale). For this, the function Transform3D.interpolate_with() can be used.

下面是将猴子从位置1转换为位置2的例子:

../../_images/interpolation_positions.png

使用以下伪代码:

GDScriptC#

  1. var t = 0.0
  2. func _physics_process(delta):
  3. t += delta
  4. $Monkey.transform = $Position1.transform.interpolate_with($Position2.transform, t)
  1. private float _t = 0.0f;
  2. public override void _PhysicsProcess(double delta)
  3. {
  4. _t += (float)delta;
  5. Marker3D p1 = GetNode<Marker3D>("Position1");
  6. Marker3D p2 = GetNode<Marker3D>("Position2");
  7. CSGMesh3D monkey = GetNode<CSGMesh3D>("Monkey");
  8. monkey.Transform = p1.Transform.InterpolateWith(p2.Transform, _t);
  9. }

又会产生下面的动作:

../../_images/interpolation_monkey.gif

平滑运动

插值可用于平滑运动, 旋转等. 下面是使用平滑运动跟随鼠标的圆圈的例子:

GDScriptC#

  1. const FOLLOW_SPEED = 4.0
  2. func _physics_process(delta):
  3. var mouse_pos = get_local_mouse_position()
  4. $Sprite2D.position = $Sprite2D.position.lerp(mouse_pos, delta * FOLLOW_SPEED)
  1. private const float FollowSpeed = 4.0f;
  2. public override void _PhysicsProcess(double delta)
  3. {
  4. Vector2 mousePos = GetLocalMousePosition();
  5. Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
  6. sprite.Position = sprite.Position.Lerp(mousePos, (float)delta * FollowSpeed);
  7. }

如下:

../../_images/interpolation_follow.gif

这对平滑相机运动很有用, 队友在跟随你(确保他们保持在一定范围内), 以及许多其他常见的游戏模式.