归一化从[0.5 - 1]到[0 - 1]

时间:2009-09-24 12:27:43

标签: c++ math hlsl normalize

我有点被困在这里,我想这是一个脑筋急转弯。如果我的数字在0.5到1之间,我怎样才能将其标准化为0到1?

感谢您提供任何帮助,也许我因为过去24小时工作而感到有点慢O_O

6 个答案:

答案 0 :(得分:65)

其他人为你提供了公式,但没有为你提供工作。这是你如何解决这样的问题。你可能会发现这比知道答案更有价值。

要将[0.5, 1]映射到[0, 1],我们会搜索x -> ax + b形式的线性地图。我们将要求将端点映射到端点,并保留该顺序。

方法一:端点映射到端点并保留该顺序的要求意味着0.5映射到0并且1映射到1

a * (0.5) + b = 0 (1)
a * 1 + b = 1     (2)

这是一个线性方程的同时系统,可以通过将方程(1)乘以-2并将方程(1)加到等式(2)来求解。完成此操作后,我们获取b = -1并将其替换为等式(2),我们获得a = 2。因此,地图x -> 2x - 1将起到作用。

方法二:通过两个点(x1, y1)(x2, y2)的线的斜率为

(y2 - y1) / (x2 - x1).

在这里,我们将使用点(0.5, 0)(1, 1)来满足端点映射到端点并且映射是保持顺序的要求。因此斜率是

m = (1 - 0) / (1 - 0.5) = 1 / 0.5 = 2.

我们认为(1, 1)是线上的一个点,因此我们得到一条线的等式的斜率形式

y - 1 = 2 * (x - 1) = 2x - 2

这样

y = 2x - 1.

我们再次看到x -> 2x - 1是一个可以解决问题的地图。

答案 1 :(得分:31)

减去0.5(给你一个0到0.5的新范围),然后乘以2.

double normalize( double x )
{
    // I'll leave range validation up to you
    return (x - 0.5) * 2;
}

答案 2 :(得分:24)

添加另一个通用答案。

如果要将线性范围[A..B]映射到[C..D],可以应用以下步骤:

移动范围使下限为0.(从两个边界中减去A:

[A..B] -> [0..B-A]

缩放范围,使其为[0..1]。 (除以上限):

[0..B-A] -> [0..1]

缩放范围,使其具有新范围的长度,即D-C。 (乘以D-C):

[0..1] ->  [0..D-C]

移动范围使下限为C.(将C添加到边界):

[0..D-C] -> [C..D]

将其与单个公式相结合,我们得到:

       (D-C)*(X-A)
X' =   -----------  + C
          (B-A)

在你的情况下,你得到A = 0.5,B = 1,C = 0,D = 1:

       (X-0.5)
X' =   ------- = 2X-1
        (0.5)

注意,如果必须将大量X转换为X',则可以将公式更改为:

       (D-C)         C*B - A*D
X' =   ----- * X  +  ---------  
       (B-A)           (B-A)

看一下非线性范围也很有趣。您可以采取相同的步骤,但需要额外的步骤将线性范围转换为非线性范围。

答案 3 :(得分:15)

  

×2 - 1

应该做的伎俩

答案 4 :(得分:14)

Lazyweb回答:要将值x[minimum..maximum]转换为[floor..ceil]

一般情况:

normalized_x = ((ceil - floor) * (x - minimum))/(maximum - minimum) + floor

标准化为[0..255]:

normalized_x = (255 * (x - minimum))/(maximum - minimum)

标准化为[0..1]:

normalized_x = (x - minimum)/(maximum - minimum)

答案 5 :(得分:0)

您可以在数学中始终使用钳制或饱和来确保您的最终值在0-1之间。有些人在最后饱和,但我也看到它在计算过程中完成了。