Rust线性插值库lerp的使用,高性能数值过渡与动画补间工具

Rust线性插值库lerp的使用,高性能数值过渡与动画补间工具

Lerp是一个用于线性插值和迭代的Rust库,自动实现大多数浮点兼容类型的线性插值功能。

基本使用

简单线性插值

use lerp::Lerp;

assert_eq!(3.0.lerp(5.0, 0.5), 4.0);

迭代插值

// 引入trait
use lerp::LerpIter;

// 在3.0和5.0之间均匀生成4个值
// 注意默认的开放迭代器不包括两端点
// 这使得链式插值迭代器更简单
let items: Vec<_> = 3.0_f64.lerp_iter(5.0, 4).collect();
assert_eq!(vec![3.0, 3.5, 4.0, 4.5], items);

// 闭合迭代器包含两端点
assert_eq!(vec![3.0, 5.0], 3.0.lerp_iter_closed(5.0, 2).collect::<Vec<_>>());

派生Lerp

该库还提供了derive宏(需要启用derive特性),可以自动生成实现。

[dependencies]
lerp = { version = "0.4", features = ["derive"] }
use lerp::Lerp;

#[derive(Lerp, PartialEq, Debug)]
struct Data {
    a: f64,
    b: f64
}

assert_eq!(
    Data { a: 0.0, b: 1.0 }.lerp(Data { a: 1.0, b: 0.0 }, 0.5),
    Data { a: 0.5, b: 0.5 }
);

完整示例

use lerp::{Lerp, LerpIter};

fn main() {
    // 基本线性插值
    println!("3.0和5.0中间值是: {}", 3.0.lerp(5.0, 0.5));
    
    // 动画补间示例
    let start = 0.0;
    let end = 100.0;
    let steps = 10;
    
    println!("\n从{}到{}的{}步动画值:", start, end, steps);
    for value in start.lerp_iter(end, steps) {
        println!("{:.1}", value);
    }
    
    // 自定义结构体插值
    #[derive(Lerp, Debug)]
    struct Position {
        x: f32,
        y: f32,
    }
    
    let pos1 = Position { x: 0.0, y: 10.0 };
    let pos2 = Position { x: 100.0, y: 50.0 };
    
    println!("\n位置过渡:");
    for t in 0..=10 {
        let t = t as f32 / 10.0;
        let pos = pos1.lerp(pos2, t);
        println!("t={:.1}: {:?}", t, pos);
    }
}

安装

在Cargo.toml中添加:

[dependencies]
lerp = "0.5.0"

或者运行:

cargo add lerp

完整示例demo

基于上述内容,这里提供一个更完整的动画补间示例:

use lerp::{Lerp, LerpIter};
use std::thread;
use std::time::Duration;

#[derive(Lerp, Debug, Clone)]
struct Color {
    r: f32,
    g: f32,
    b: f32,
}

fn main() {
    // 数值过渡示例
    println!("数值过渡示例:");
    for value in 0.0_f32.lerp_iter(1.0, 5) {
        println!("当前值: {:.2}", value);
    }

    // 颜色过渡动画
    let start_color = Color { r: 1.0, g: 0.0, b: 0.0 }; // 红色
    let end_color = Color { r: 0.0, g: 0.0, b: 1.0 };   // 蓝色
    
    println!("\n颜色过渡动画:");
    for t in 0..=10 {
        let t = t as f32 / 10.0;
        let color = start_color.lerp(&end_color, t);
        println!("进度 {:.0}%: {:?}", t * 100.0, color);
        thread::sleep(Duration::from_millis(200));
    }

    // 复杂结构体插值
    #[derive(Lerp, Debug)]
    struct Transform {
        position: (f32, f32),
        scale: f32,
        rotation: f32,
    }
    
    let start = Transform {
        position: (0.0, 0.0),
        scale: 1.0,
        rotation: 0.0,
    };
    
    let end = Transform {
        position: (100.0, 50.0),
        scale: 2.0,
        rotation: 90.0,
    };
    
    println!("\n变换动画:");
    for t in 0..=5 {
        let t = t as f32 / 5.0;
        let transform = start.lerp(&end, t);
        println!("t={:.1}: {:?}", t, transform);
    }
}

这个完整示例展示了:

  1. 基本的数值过渡
  2. 颜色结构的平滑过渡动画
  3. 复杂结构体的插值变换
  4. 使用lerp_iter进行迭代插值
  5. 派生Lerp trait在自定义结构体上的应用

1 回复

Rust线性插值库lerp的使用指南

介绍

lerp是Rust中一个简单高效的线性插值库,用于在两个值之间进行平滑过渡计算。它特别适合用于动画、游戏开发、数据可视化和任何需要数值过渡的场景。

线性插值(Linear Interpolation)的基本公式是:

result = start + (end - start) * t

其中t通常在[0.0, 1.0]范围内变化。

安装

在Cargo.toml中添加依赖:

[dependencies]
lerp = "0.4.0"

基本用法

1. 数值插值

use lerp::Lerp;

fn main() {
    let start = 0.0f32;
    let end = 10.0f32;
    
    // 在中间点插值
    let middle = start.lerp(end, 0.5);
    println!("中间值: {}", middle); // 输出: 5.0
    
    // 25%位置插值
    let quarter = start.lerp(end, 0.25);
    println!("25%位置的值: {}", quarter); // 输出: 2.5
}

2. 颜色插值

use lerp::Lerp;

fn main() {
    let red = (1.0, 0.0, 0.0); // RGB
    let blue = (0.0, 0.0, 1.0);
    
    // 从红色渐变到蓝色
    let purple = red.lerp(blue, 0.5);
    println!("紫色: {:?}", purple); // 输出: (0.5, 0.0, 0.5)
}

3. 向量插值

use lerp::Lerp;
use glam::Vec3; // 需要添加glam依赖

fn main() {
    let start_pos = Vec3::new(0.0, 0.0, 0.0);
    let end_pos = Vec3::new(10.0, 5.0, 0.0);
    
    // 在30%位置插值
    let current_pos = start_pos.lerp(end_pos, 0.3);
    println!("当前位置: {:?}", current_pos); // 输出: Vec3(3.0, 1.5, 0.0)
}

高级特性

1. 范围映射

use lerp::{Lerp, remap};

fn main() {
    // 将0.5从[0.0, 1.0]范围映射到[100.0, 200.0]范围
    let value = remap(0.5, 极狐0.0..=1.0, 100.0..=200.0);
    println!("映射后的值: {}", value); // 输出: 150.0
}

2. 缓动函数

use lerp::{Lerp, ease_in_out_quad};

fn main() {
    let start = 0.0;
    let end = 100.0;
    let t = 0.7; // 原始进度
    
    // 应用二次缓动函数
    let eased_t = ease_in_out_quad(t);
    let value = start.ler极狐p(end, eased_t);
    
    println!("缓动后的值: {}", value);
}

3. 自定义类型插值

可以为自定义类型实现Lerp trait:

use lerp::Lerp;

struct Point {
    x: f32,
    y: f32,
}

impl Lerp<f32> for Point {
    fn lerp(self, other: Self, t: f32) -> Self {
        Point {
            x: self.x.lerp(other.x, t),
            y: self.y.lerp(other.y, t),
        }
    }
}

fn main() {
    let p1 = Point { x: 0.0, y: 0.0 };
    let p2 = Point { x: 10.0, y: 20.0 };
    
    let p_mid = p1.lerp(p2, 0.5);
    println!("中点: ({}, {})", p_mid.x, p_mid.y); // 输出: (5.0, 10.0)
}

性能提示

  1. lerp库经过高度优化,对浮点运算特别友好
  2. 对于大量插值计算,考虑使用SIMD优化
  3. 在游戏循环中,可以预计算(end - start)来避免重复计算

实际应用示例:平滑动画

use lerp::Lerp;
use std::time::{Instant, Duration};

struct Animation {
    start_value: f32,
    end_value: f32,
    duration: Duration,
    start_time: Instant,
}

impl Animation {
    fn new(start: f32, end: f32, duration: Duration) -> Self {
        Self {
            start_value: start,
            end_value: end,
            duration,
            start_time: Instant::now(),
        }
    }
    
    fn current_value(&self) -> f32 {
        let elapsed = self.start_time.elapsed();
        let t = (elapsed.as_secs_f32() / self.duration.as_secs_f32()).min(1.0);
        self.start_value.lerp(self.end_value, t)
    }
}

fn main() {
    let anim = Animation::new(0.0, 100.0, Duration::from_secs(2));
    
    loop {
        let value = anim.current_value();
        println!("当前值: {}", value);
        
        if value >= 100.0 {
            break;
        }
        
        std::thread::sleep(Duration::from_millis(16)); // ~60fps
    }
}

lerp库是Rust生态中处理线性插值的高效工具,通过简单的API提供了强大的功能,特别适合游戏开发、UI动画和科学计算等场景。

回到顶部