插值函数

本文最后更新于:2025年4月17日 晚上

线性插值函数

lerp(y1,y2,weight)=y1+(y2−y1)×weightlerp(y_1, y_2, weight) = y_1 + (y_2 - y_1) \times weight

其中 weightweight 是一个在 [0, 1] 区间的实数,倒不是因为取更大的值后这个函数就无定义了,而是因为取了更大的值,这个函数就失去了我们构造它的理由,另外,CG 会限制 weightweight 的值在 [0, 1] 的范围内,超过这个范围会被留在边界 0 或者边界 1。

这里 y1y_1 被称为起点,而 y2y_2 被称为终点,lerp 函数就是取值 y1y_1 到 y2y_2 中间的一个值。取值由 weightweight 来控制,当 weightweight 为 0.5 时,取值刚好在起点和终点之间。为了更加方便理解,可以把公式写成这种形式:

lerp(y1,y2,weight)=(1−weight)×y1+weight×y2lerp(y_1, y_2, weight) = (1 - weight) \times y_1 + weight \times y_2

简单来说,lerp 函数是在 y1y_1 和 y2y_2 之间过渡。y1y_1 和 y2y_2 可以是一个值,也可以是一个函数。比如,我们可以在正弦函数和线性函数之间做过渡,我们先看一下正弦函数:

正弦函数曲线

再看一下最简单的线性函数 y=xy = x

线性函数曲线

在它俩之间过渡,我们只需要使用 lerp(sin⁡x,x,0.5)lerp(\sin x, x, 0.5) 即可。当然可以调整 weightweight 参数观察不同的结果。

weight 为 0.5

weight 为 0.8

weight 为 0.2

当 y1y_1 和 y2y_2 分别为两个点时,结果就是两点间的位置。

线性插值

贝塞尔曲线

当有 AA、BB、CC 三个点且有 DD 为从 AA 到 CC 上权重为 tt 的插值,EE 为从 CC 到 BB 上权重为 tt 的插值,点 FF 为从 DD 到 EE 上权重为 tt 的插值,则点 FF 是以 AA 为起点、BB 为终点、CC 为控制点的二阶贝塞尔曲线上的一点。

贝塞尔二阶曲线上的点

贝塞尔二阶曲线上的点

同理,当有 AA、BB、CC、DD 四个点,EE 为从 AA 到 CC 上权重为 tt 的插值,FF 为从 CC 到 DD 上权重为 tt 的插值,GG 为从 DD 到 BB 上权重为 tt 的插值,且 HH 为从 EE 到 FF 上权重为 tt 的插值,II 为从 FF 到 GG 上权重为 tt 的插值,JJ 为从 HH 到 II 上权重为 tt 的插值,则点 JJ 是以 AA 为起点、BB 为终点、CC 和 DD 为控制点的三阶贝塞尔曲线上的一点。

贝塞尔三阶曲线上的点

贝塞尔三阶曲线上的点

二阶贝塞尔曲线公式推导

由 f(p0,p1,t)=(p1−p0)×t+p0f(p_0, p_1, t) = (p_1 - p_0) \times t + p_0 可得:

D=(C−A)t+AE=(B−C)t+CF=(E−D)t+D=(((B−C)t+C)−((C−A)t+A)t+((C−A)t+A))=(At+Bt−2Ct+C−A)t+Ct−At+A=(t−1)2A+t2B+2t(1−t)CB(t)=(1−t)2A+t2B+2t(1−t)C,t∈[0,1]\begin{aligned} D &= (C - A)t + A\\ E &= (B - C)t + C\\ F &= (E - D)t + D\\ &= (((B - C)t + C) - ((C - A)t + A)t + ((C - A)t + A))\\ &= (At + Bt -2Ct + C - A)t + Ct - At + A\\ &= (t - 1)^2A + t^2B + 2t(1 - t)C\\ \\ B(t) &= (1 - t)^2A + t^2B + 2t(1 - t)C, t \in [0, 1] \end{aligned}

三阶贝塞尔曲线公式推导

由 f(p0,p1,t)=(p1−p0)×t+p0f(p_0, p_1, t) = (p_1 - p_0) \times t + p_0 可得:

E=(C−A)t+AF=(D−C)t+CG=(B−D)t+D\begin{aligned} E &= (C - A)t + A\\ F &= (D - C)t + C\\ G &= (B - D)t + D\\ \end{aligned}

HH 可以看作以 AA 为起点、DD 为终点、CC 为控制点的二阶贝塞尔曲线上的点,II 可以看作以 CC 为起点、BB 为终点、DD 为控制点的二阶贝塞尔曲线上的点,所以由二阶贝塞尔曲线公式可得:

H=(F−E)t+E=(1−t)2A+t2D+2t(1−t)CI=(G−F)t+F=(1−t)2C+t2B+2t(1−t)DJ=(I−H)t+H=(((1−t)2C+t2B+2t(1−t)D)−((1−t)2A+t2D+2t(1−t)C))t+((1−t)2A+t2D+2t(1−t)C)=(1−t)3A+t3B+3t(1−t)2C+3t2(1−t)DB(t)=(1−t)3A+t3B+3t(1−t)2C+3t2(1−t)D,t∈[0,1]\begin{aligned} H &= (F - E)t + E\\ &= (1 - t)^2A + t^2D + 2t(1 - t)C\\ \\ I &= (G - F)t + F\\ &= (1 - t)^2C + t^2B + 2t(1 - t)D\\ \\ J &= (I - H)t + H\\ &= (((1 - t)^2C + t^2B + 2t(1 - t)D) - ((1 - t)^2A + t^2D + 2t(1 - t)C))t + ((1 - t)^2A + t^2D + 2t(1 - t)C)\\ &= (1 - t)^3A + t^3B + 3t(1 - t)^2C + 3t^2(1 - t)D\\ \\ B(t) &= (1 - t)^3A + t^3B + 3t(1 - t)^2C + 3t^2(1 - t)D, t \in [0, 1] \end{aligned}

或者 JJ 也可以看作以 EE 为起点、GG 为终点、FF 为控制点的二阶贝塞尔曲线上的点,由二阶贝塞尔曲线公式可得:

E=(C−A)t+AF=(D−C)t+CG=(B−D)t+DJ=(1−t)2E+t2G+2t(1−t)F=(1−t)2((C−A)t+A)+t2((B−D)t+D)+2t(1−t)((D−C)t+C)=(1−t)3A+t3B+3t(1−t)2C+3t2(1−t)DB(t)=(1−t)3A+t3B+3t(1−t)2C+3t2(1−t)D,t∈[0,1]\begin{aligned} E &= (C - A)t + A\\ F &= (D - C)t + C\\ G &= (B - D)t + D\\ J &= (1 - t)^2E + t^2G + 2t(1 - t)F\\ &= (1 - t)^2((C - A)t + A) + t^2((B - D)t + D) + 2t(1 - t)((D - C)t + C)\\ &= (1 - t)^3A + t^3B + 3t(1 - t)^2C + 3t^2(1 - t)D\\ \\ B(t) &= (1 - t)^3A + t^3B + 3t(1 - t)^2C + 3t^2(1 - t)D, t \in [0, 1] \end{aligned}

阶梯插值函数

step 函数的逻辑是

1
2
3
4
5
6
step(a, x){
if(x < a)
return 0;
else
return 1;
}

阶梯插值函数

平滑阶梯插值函数

smoothstep 函数可以用来生成 0 到 1 的平滑过渡值,它也叫平滑阶梯函数。smoothstep 函数的定义是

1
2
3
4
5
float smoothstep(float a, float b, float x) 
{
x = clamp((x - a) / (b- a), 0.0, 1.0);
return x * x * (3 - 2 * x);
}

简单来说就是:

  • 在 a < b 的情况下,当 x < a 时,返回 0,当 x > b 时,返回 1,否则在 0 和 1 之间平滑过渡:

平滑阶梯插值函数

  • 在 a > b 的情况下,当 x < b 时,返回 1,当 x > a 时,返回 0,否则在 0 和 1 之间平滑过渡:

平滑阶梯插值函数

两个 smoothstep 进行减法运算可以得到一些波形图,例如 smoothstep(1, 2, x) - smoothstep(2, 3, x):

smoothstep(1, 2, x) - smoothstep(2, 3, x)

想要增加波峰的持续宽度,可以构造 smoothstep(1, 2, x) - smoothstep(3, 4, x):

smoothstep(1, 2, x) - smoothstep(3, 4, x)


插值函数
http://example.com/posts/插值函数/
作者
祭零小白
发布于
2022年2月20日
许可协议