Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Interpolazione
L'interpolazione è un'operazione comune nella programmazione grafica, utilizzata per fondere o passare tra due valori. L'interpolazione si può utilizzare anche per rendere più fluido un movimento, una rotazione, ecc. È utile familiarizzarsi con questa operazione per ampliare i propri orizzonti come sviluppatore di giochi.
L'idea di base è che si desidera passare da A a B. Il valore t rappresenta gli stati intermedi.
Ad esempio, se t è 0, allora lo stato è A. Se t è 1, allora lo stato è B. Qualsiasi valore intermedio è un'interpolazione.
Tra due numeri reali (in virgola mobile), un'interpolazione può essere descritta come:
interpolation = A * (1 - t) + B * t
E spesso semplificata in:
interpolation = A + (B - A) * t
Il nome di questo tipo di interpolazione, che trasforma un valore in un altro a una velocità costante, è "lineare". Quindi, quando si sente parlare di interpolazione lineare, ci si riferisce a questa formula.
Esistono altri tipi di interpolazioni, che non saranno trattati qui. Si consiglia di leggere successivamente la pagina Bezier.
Interpolazione vettoriale
Anche i tipi di vettori (Vector2 e Vector3) possono essere interpolati; e sono dotati di funzioni utili per farlo Vector2.lerp() e Vector3.lerp().
Per l'interpolazione cubica, ci sono anche Vector2.cubic_interpolate() e Vector3.cubic_interpolate(), che eseguono un'interpolazione di stile Bezier.
Ecco un esempio di pseudo-codice per passare dal punto A al punto B tramite l'interpolazione:
var t = 0.0
func _physics_process(delta):
t += delta * 0.4
$Sprite2D.position = $A.position.lerp($B.position, t)
private float _t = 0.0f;
public override void _PhysicsProcess(double delta)
{
_t += (float)delta * 0.4f;
Marker2D a = GetNode<Marker2D>("A");
Marker2D b = GetNode<Marker2D>("B");
Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
sprite.Position = a.Position.Lerp(b.Position, _t);
}
Ciò produrrà il seguente movimento:
Interpolazione di trasformazioni
È anche possibile interpolare intere trasformazioni (assicurandosi che abbiano una scala uniforme o, almeno, la stessa scala non uniforme). Per fare ciò, si può utilizzare la funzione Transform3D.interpolate_with().
Ecco un esempio di trasformazione di una scimmia da Position1 a Position2:
Utilizzando il seguente pseudo-codice:
var t = 0.0
func _physics_process(delta):
t += delta
$Monkey.transform = $Position1.transform.interpolate_with($Position2.transform, t)
private float _t = 0.0f;
public override void _PhysicsProcess(double delta)
{
_t += (float)delta;
Marker3D p1 = GetNode<Marker3D>("Position1");
Marker3D p2 = GetNode<Marker3D>("Position2");
CSGMesh3D monkey = GetNode<CSGMesh3D>("Monkey");
monkey.Transform = p1.Transform.InterpolateWith(p2.Transform, _t);
}
E di nuovo, produrrà il seguente movimento:
Smoothing motion
L'interpolazione si può utilizzare per seguire fluidamente un valore di destinazione in movimento, come una posizione o una rotazione. A ogni frame, lerp() sposta il valore attuale verso il valore di destinazione di una percentuale fissa della differenza rimanente tra i due valori. Il valore attuale si sposterà fluidamente verso la destinazione, rallentando man mano che si avvicina. Ecco un esempio di un cerchio che segue il mouse attraverso un'interpolazione fluida:
const FOLLOW_SPEED = 4.0
func _physics_process(delta):
var mouse_pos = get_local_mouse_position()
$Sprite2D.position = $Sprite2D.position.lerp(mouse_pos, delta * FOLLOW_SPEED)
private const float FollowSpeed = 4.0f;
public override void _PhysicsProcess(double delta)
{
Vector2 mousePos = GetLocalMousePosition();
Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
sprite.Position = sprite.Position.Lerp(mousePos, (float)delta * FollowSpeed);
}
Ecco come appare:
Questo è utile per smussare i movimenti della telecamera, per far sì che gli alleati seguano il giocatore (assicurandosi che restino entro una certa distanza) e per molti altri pattern comuni di gioco.
Nota
Nonostante l'utilizzo di delta, la formula utilizzata sopra dipende dal frame rate, perché il parametro weight di lerp() rappresenta una percentuale della differenza rimanente nei valori, non una quantità assoluta da cambiare. In _physics_process(), questo di solito va bene perché ci si aspetta che la fisica mantenga un frame rate costante, e dunque delta dovrebbe rimanere costante.
Per una versione di interpolazione fluida indipendente dal frame rate che si può utilizzare anche in process(), utilizzare invece la seguente formula:
const FOLLOW_SPEED = 4.0
func _process(delta):
var mouse_pos = get_local_mouse_position()
var weight = 1 - exp(-FOLLOW_SPEED * delta)
$Sprite2D.position = $Sprite2D.position.lerp(mouse_pos, weight)
private const float FollowSpeed = 4.0f;
public override void _Process(double delta)
{
Vector2 mousePos = GetLocalMousePosition();
Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
float weight = 1f - Mathf.Exp(-FollowSpeed * (float)delta);
sprite.Position = sprite.Position.Lerp(mousePos, weight);
}
Derivare questa formula va oltre lo scopo di questa pagina. Per una spiegazione, consultare Improved Lerp Smoothing o guardare Lerp Smoothing is broken.