我的代码改编自"Improved" Perlin noise
const js_string = 'while(1);{"menu":{"id":"file","value":"File","popup":{"menuitem":[{"value":"New","onclick":"CreateNewDoc()"},{"value":"Open","onclick":"OpenDoc()"},{"value":"Close","onclick":"CloseDoc()"}]}}}';
//while(9); has 9 characters so remove it and parse it to json object
console.log(JSON.parse(js_string.slice(9)));
我想要一个方向的周期性噪声,所以我将该方向包裹在一个额外维度的圆上,这样称呼它
double improved_noise (double x, double y, double z)
{
// Calculate the "unit cube" that the point asked will be located in
// The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that
// plus 1. Next we calculate the location (from 0.0 to 1.0) in that
// cube. We also fade the location to smooth the result.
int xi = (int)x & 255;
int yi = (int)y & 255;
int zi = (int)z & 255;
double xf = x - (int) x;
double yf = y - (int) y;
double zf = z - (int) z;
double u = fade (xf);
double v = fade (yf);
double w = fade (zf);
int aaa, aba, aab, abb, baa, bba, bab, bbb;
auto & p = permutation;
aaa = p[p[p[ xi ] + yi ] + zi ];
aba = p[p[p[ xi ] + inc(yi)] + zi ];
aab = p[p[p[ xi ] + yi ] + inc(zi)];
abb = p[p[p[ xi ] + inc(yi)] + inc(zi)];
baa = p[p[p[inc(xi)] + yi ] + zi ];
bba = p[p[p[inc(xi)] + inc(yi)] + zi ];
bab = p[p[p[inc(xi)] + yi ] + inc(zi)];
bbb = p[p[p[inc(xi)] + inc(yi)] + inc(zi)];
double x1, x2, y1, y2;
// The gradient function calculates the dot product between a
// pseudorandom gradient vector and the vector from the input
// coordinate to the 8 surrounding points in its unit cube.
// This is all then lerped together as a sort of weighted average
// based on the faded (u,v,w) values we made earlier.
x1 = lerp (
grad (aaa, xf , yf , zf),
grad (baa, xf-1, yf , zf),
u);
x2 = lerp (
grad (aba, xf , yf-1, zf),
grad (bba, xf-1, yf-1, zf),
u);
y1 = lerp (x1, x2, v);
x1 = lerp (
grad (aab, xf , yf , zf-1),
grad (bab, xf-1, yf , zf-1),
u);
x2 = lerp (
grad (abb, xf , yf-1, zf-1),
grad (bbb, xf-1, yf-1, zf-1),
u);
y2 = lerp (x1, x2, v);
return (lerp (y1, y2, w) + 1) / 2;
}
我得到了奇怪的结果(大和/或否定)。一些实验表明,当 improved_noise (sin(x*2*M_PI), cos(x*2*M_PI), y))
的参数为负数时会发生这种情况。
为什么此函数不能很好地处理负值,并且可以轻松地进行调整,以使整数行成为有效参数?
答案 0 :(得分:3)
improved_noise
不能处理负输入。
其中的一条评论说:
The left bound is ( |_x_|,|_y_|,|_z_| )…
|…|
表示建议使用绝对值。但是,代码将计算:
int xi = (int)x & 255;
在常见的C实现中(使用二进制补码),这有效地计算了x
模数256的整数部分的残差。例如,如果x为-3.25,则其整数部分为-3,并且这会将xi
设置为253(即-3 + 256)。
这有两个问题。首先,253不是-3的绝对值,因此此代码与注释不匹配。其次,它采用包含该点的单位立方体的“右”边界(值较大的边界),而注释以及正值的行为表明,其意图是设置xi
,{ {1}}和yi
到“左”边界(值较小的边界)。
从那里继续,代码设置zi
。对于非负值,这将生成double xf = x - (int) x;
的小数部分。例如,如果x
为3.25,则x
为.25。但是,如果使用负值和先前的xf
操作,则会误入歧途。对于& 255
= -3.25,它计算得出-3.25-253 = -256.25。但是该代码可能仅打算在0到1的小数部分内在一个单位立方体内进行插值。无论使用什么函数执行插值,都可能不支持-256.25。
从本质上讲,此代码从未设计为支持负值,而要对其进行修复,则需要从应该如何操作的第一原则进行重新设计。
x
无论int X = (int)Math.floor(x) & 255
…
x -= Math.floor(x);
是否为负,前者正确使用floor
来找到“左”边界。然后将x
应用于此。假设为两个补码,这将在定期平铺中提供正确的坐标。 (假设两个补码不是纯粹可移植的,应该记录或避免。)
然后,它通过减去& 255
的{{1}}而不是减去floor
的结果来正确地找到分数。例如,对于x
= −3.25,这将产生整数坐标−4和分数.75。
将& 255
修改为类似功能可能会有所帮助。您可以尝试:
x
您同时用C ++和C标记了这个问题。在C ++中,最好使用improved_noise
而不是int xi = (int) floor(x) & 255;
int yi = (int) floor(y) & 255;
int zi = (int) floor(z) & 255;
double xf = x - floor(x);
double yf = y - floor(y);
double zf = z - floor(z);
,并且C ++和C之间可能存在其他差异。