【学Rust写CAD】14线性插值函数(加入color.rs)

lerp 函数源码

rust 复制代码
/// 颜色线性插值
    /// t 取值范围 0..256,0 表示完全使用当前颜色(self),256 表示完全使用目标颜色(end)
    #[inline]
    pub fn lerp(self, end: Color, t: u32) -> Color {
        let mask = 0xff00ff;
        // 提取目标颜色的蓝色和红色分量
        let brb = end.0 & 0xff00ff;
        // 提取目标颜色的alpha和绿色分量
        let bag = (end.0 >> 8) & 0xff00ff;

        // 提取当前颜色的蓝色和红色分量
        let arb = self.0 & 0xff00ff;
        // 提取当前颜色的alpha和绿色分量
        let aag = (self.0 >> 8) & 0xff00ff;

        // 计算分量差值
        let drb = brb.wrapping_sub(arb);
        let dag = bag.wrapping_sub(aag);

        // 应用插值系数
        let drb = drb.wrapping_mul(t) >> 8;
        let dag = dag.wrapping_mul(t) >> 8;

        // 计算最终分量值
        let rb = arb + drb;
        let ag = aag + dag;
        
        // 组合并返回结果颜色
        Color((rb & mask) | ((ag << 8) & !mask))
    }

颜色线性插值(Lerp)解释

这段代码实现了两个颜色之间的线性插值(linear interpolation),通常称为lerp。这是一种在两个值之间进行平滑过渡的技术,在这里用于颜色过渡。

工作原理
  1. 输入参数:
  • self: 起始颜色

  • end: 目标颜色

  • t: 插值系数,范围0-256(0=完全使用起始颜色,256=完全使用目标颜色)

  1. 颜色分量分离:
  • 将颜色值拆分为蓝色/红色分量和alpha/绿色分量

使用掩码0xff00ff来提取这些分量(因为颜色通常以ARGB格式存储)

  1. 差值计算:

计算目标颜色和起始颜色在各分量上的差值

  • 使用wrapping_sub处理可能的溢出
  1. 应用插值系数:
  • 将差值乘以插值系数t,然后右移8位(相当于除以256)

  • 这实现了按比例混合两个颜色

  1. 组合结果:
  • 将插值后的分量重新组合成最终颜色

  • 使用掩码确保各分量在正确的位置

为什么这样实现

这种实现方式有几个优点:

  • 使用位操作而不是浮点运算,效率更高

  • 同时处理两个颜色分量(蓝色/红色和alpha/绿色),减少操作次数

  • 使用包装算术(wrapping)避免溢出检查,提高性能

示例

如果起始颜色是红色(0xFF0000),目标颜色是蓝色(0x0000FF),当t=128时:

结果会是紫色(0x800080),正好在红色和蓝色中间

这种技术广泛应用于图形渲染、动画过渡和颜色渐变等场景。

测试代码

测试代码包括多种边界情况和典型场景的测试:

rust 复制代码
#[cfg(test)]
mod tests {
    use super::Color;

    #[test]
    fn test_lerp() {
        // 测试相同颜色插值
        let white = Color(0xFFFFFFFF);
        for i in 0..=256 {
            assert_eq!(white.lerp(white, i).0, 0xFFFFFFFF, "相同颜色插值失败,i={}", i);
        }

        // 测试从黑到白插值
        let black = Color(0xFF000000);
        let white = Color(0xFFFFFFFF);
        assert_eq!(black.lerp(white, 0).0, 0xFF000000, "t=0应返回起始颜色");
        assert_eq!(black.lerp(white, 256).0, 0xFFFFFFFF, "t=256应返回目标颜色");
        assert_eq!(black.lerp(white, 128).0, 0xFF7F7F7F, "中间值不正确");

        // 测试红色到蓝色插值
        let red = Color(0xFFFF0000);
        let blue = Color(0xFF0000FF);
        assert_eq!(red.lerp(blue, 0).0, 0xFFFF0000);
        assert_eq!(red.lerp(blue, 256).0, 0xFF0000FF);
        assert_eq!(red.lerp(blue, 128).0, 0xFF7F007F);

        // 测试透明度变化
        let opaque = Color(0xFF123456);
        let transparent = Color(0x00123456);
        assert_eq!(opaque.lerp(transparent, 128).0, 0x7F123456);

        // 测试边界情况
        let color1 = Color(0x12345678);
        let color2 = Color(0x87654321);
        assert_eq!(color1.lerp(color2, 0).0, color1.0);
        assert_eq!(color1.lerp(color2, 256).0, color2.0);

        // 测试所有分量同时变化
        let start = Color(0x00000000);
        let end = Color(0x01020304);
        assert_eq!(start.lerp(end, 64).0, 0x00404040); // 1/4 of end color
    }

    #[test]
    fn test_lerp_edge_cases() {
        // 测试t值超出范围的情况(虽然参数是u32,但实际只使用低9位)
        let c1 = Color(0x00000000);
        let c2 = Color(0xFFFFFFFF);
        assert_eq!(c1.lerp(c2, 257).0, c1.lerp(c2, 1).0); // 257 & 0xFF = 1
        assert_eq!(c1.lerp(c2, 512).0, c1.lerp(c2, 0).0); // 512 & 0xFF = 0

        // 测试颜色值溢出情况
        let low = Color(0x00000000);
        let high = Color(0xFFFFFFFF);
        assert_eq!(low.lerp(high, 255).0, 0xFFFEFEFE);
    }
}
测试说明
  1. 基本测试:
  • 相同颜色插值结果应该不变

  • 从黑到白插值的边界和中间值

  • 从红到蓝插值的典型场景

  1. 透明度测试:
  • 测试alpha通道的插值是否正确

3.边界测试:

  • 确保t=0和t=256时返回正确的颜色

  • 测试t值超出范围时的行为(虽然参数是u32,但实现只使用低9位)

  1. 分量测试:
  • 测试所有颜色分量同时变化的情况

  • 测试颜色值溢出的处理

  1. 特殊场景:
  • 测试包装算术(wrapping)的正确性

这些测试覆盖了正常使用场景和边界情况,可以验证lerp方法的正确性。

相关推荐
Source.Liu14 分钟前
【学Rust写CAD】15 定点数实现(fixed.rs)
rust·cad
weixin_502539854 小时前
rust学习笔记21-闭包
笔记·学习·rust
橘右溪4 小时前
Windows 下 Rust 快速安装指南
rust
fundroid4 小时前
Rust 为什么不适合开发 GUI
开发语言·后端·rust
w4ngzhen13 小时前
理解Rust引用及其生命周期标识(下)
rust
残轩16 小时前
是时候考虑用uv管理你的python项目及依赖了
python·rust
Source.Liu16 小时前
【学Rust写CAD】18 定点数2D仿射变换矩阵结构体(MatrixFixedPoint结构别名)
矩阵·rust·cad
橘右溪17 小时前
前端快速系统学习Rust的路径
rust
江南月19 小时前
Rust+WebAssembly 高性能图像处理引擎开发实战
前端·rust
Tee xm19 小时前
清晰易懂的Rust安装与配置教程
linux·windows·macos·rust