价值重映射

31

Processing有一个我经常使用的很棒的功能:

map(value, low1, high1, low2, high2)

http://processing.org/reference/map_.html

该函数将期望范围为low1high1value重新映射到目标范围low2high2

我想理解它背后的数学原理,以便在其他语言中使用它。有没有人能帮我倒推一下?我知道这是一个已重新缩放和重新偏移的lerp...今天早上感觉有点脑残。

5个回答

56

根据您的描述,它应该做到这一点,对吗?

low2 + (value - low1) * (high2 - low2) / (high1 - low1)

找出你在第一个范围内的距离,按范围大小比例缩放该距离,这就是你应该在第二个范围内的位置。


8

Processing是开源的。你可以在这里查看map()函数。

static public final float map(float value,
                                float start1, float stop1,
                                float start2, float stop2) {
    float outgoing =
      start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
    String badness = null;
    if (outgoing != outgoing) {
      badness = "NaN (not a number)";

    } else if (outgoing == Float.NEGATIVE_INFINITY ||
               outgoing == Float.POSITIVE_INFINITY) {
      badness = "infinity";
    }
    if (badness != null) {
      final String msg =
        String.format("map(%s, %s, %s, %s, %s) called, which returns %s",
                      nf(value), nf(start1), nf(stop1),
                      nf(start2), nf(stop2), badness);
      PGraphics.showWarning(msg);
    }
    return outgoing;
  }

具体来说,您正在寻找这行代码:

float outgoing =
      start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));

2
我想补充一点,有时找到 low1 和 high1 之间的因子并将其与曲线调制后再将其作为 LERP 的 t 值是很有用的。
所以,t =(value-low1)/(high1-low1),以获得值在 low1 到 high1 线段中的相对位置。
然后,您可以使用一些曲线过滤器,例如 gamma、bias、gain 等来调制 t。同时,如果您需要限制超出设置的最低值和最高值的值,则可以将 t 夹紧在 0 和 1 之间。
然后,使用 t 在 low2 和 high2 之间进行 LERP,如:finalvalue = low2 *(1-t)+ high2 * t

1

如果有人想知道是否有一种没有浮点数的版本,可以尽可能保持精度,我做了这个:

int remap(int value, int input_min, int input_max, int output_min, int output_max)
{
    const long long factor = 1000000000;

    long long output_spread = output_max - output_min;
    long long input_spread = input_max - input_min;

    long long l_value = value;

    long long zero_value = value - input_min;
    zero_value *= factor;
    long long percentage = zero_value / input_spread;

    long long zero_output = percentage * output_spread / factor;

    long long result = output_min + zero_output;

    return (int)result;
}

对我来说似乎有效,没有进行全面测试(例如,最大值小于最小值未经过测试)。

背后的想法是通过使用更大的类型来扩大原始值,以便除法产生更大的数字 - 这将导致更高的精度。


0
在我的情况下,我使用了一个表达式(var*amount)- shift, 其中 var 是值, amount 是 blendshapes 的数量, shift 是基于 blendshape 索引的值(向右移动1位,如果值为1,则得到0,因此下一个 blendshape 开始)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接