# 【插值】
# 普通插值
- 求a与b之间位置t的值。
- t为0时候输出值为a。
- t为1时候输出值为b。
public static float Lerp( float a, float b, float t ) => ( 1f - t ) * a + t * b;
图片插值演示:
# 反向插值
- 已知value,求a与b之间的t值。
- value等于a值时,t为0。
- value等于b值时,t为1。
public static float InverseLerp( float a, float b, float value ) => ( value - a ) / ( b - a );
以下是一个反向插值使用例子,已知人和音源距离,求人能听见的音量。
参数A:多远处音频值为0
参数B:多远处音频值为1
参数C:人和音源的距离
结果值:人听到音量的大小(0~1)
注意:这个例子里,因为音量不能超出1也不能小于0,所以InverseLerp对结果值进行了Camp0~1
另外一个使用 inverseLerp 的例子,比如有很多不同长度的分段subsections,也知道根据分段总长度内的一个值val,求出val是哪个分段以及对应分段内的t(0~1)。
/**
* 获取子分段里的0~1之间的t值
* @param subsections 段长度的数组
* @param val 0~subsections的总长度
* @returns index: 所在段的索引 subT:所在段内的t值(0~1)
*/
public getSubsectionT(subsections: number[], val: number): { index: number; subT: number } {
let index = -1;
let subT = 0;
let tempStart: number = 0;
for (let i = 0; i < subsections.length; i++) {
const subsection = subsections[i];
const tempEnd = tempStart + subsection;
subT = Math.inverseLerp(tempStart, tempEnd, val);
if (subT >= 0 && subT <= 1) {
index = i;
break;
}
tempStart = tempEnd;
}
return { index: index, subT: subT };
}
# 平滑反向插值
如果想反向插值的坡度有平滑,可以使用smoothstep。
float smoothstep(float a,float b, float x)
{
float t = saturate((x-a)/(b-a)); // saturate的作用是 clamp0~1
return t*t*(3.0-(2.0*t));
}
# 映射
- 比如把 -1 到 1 的值映射成 0 到 1 的值。
- Photoshop里的色阶就使用了映射。
public static float Remap( float iMin, float iMax, float oMin, float oMax, float value ) => Lerp( oMin, oMax, InverseLerp( iMin, iMax, value ) );
# 连续帧插值平滑
// a: 当前值
// b: 目标值
// decay: 推荐 1~25 从慢到快
// dt: 时间差,单位:秒
// 指数衰减
expDecay(a,b,decay,dt)
{
return b+(a-b)*exp(-decay*dt);
}
decay = 16;
update()
{
a = expDecay(a,b,decay,Time.deltaTime);
}