我最近在使用噪音功能,即perlin噪音和单纯噪音。我对噪声算法没有任何疑问,因为我已经启动并运行了,但我对ken perlin使用的哈希方法有一些疑问:
因此,在这些噪声函数中,每个坐标都需要一个(伪)随机值。在Ken Perlins实现中,他使用查找表来获取这些值:
static const U8 perlin_hash_values[] = {
151,160,137, 91, 90, 15,131, 13,201, 95, 96, 53,194,233, 7,225,
140, 36,103, 30, 69,142, 8, 99, 37,240, 21, 10, 23,190, 6,148,
247,120,234, 75, 0, 26,197, 62, 94,252,219,203,117, 35, 11, 32,
57,177, 33, 88,237,149, 56, 87,174, 20,125,136,171,168, 68,175,
74,165, 71,134,139, 48, 27,166, 77,146,158,231, 83,111,229,122,
60,211,133,230,220,105, 92, 41, 55, 46,245, 40,244,102,143, 54,
65, 25, 63,161, 1,216, 80, 73,209, 76,132,187,208, 89, 18,169,
200,196,135,130,116,188,159, 86,164,100,109,198,173,186, 3, 64,
52,217,226,250,124,123, 5,202, 38,147,118,126,255, 82, 85,212,
207,206, 59,227, 47, 16, 58, 17,182,189, 28, 42,223,183,170,213,
119,248,152, 2, 44,154,163, 70,221,153,101,155,167, 43,172, 9,
129, 22, 39,253, 19, 98,108,110, 79,113,224,232,178,185,112,104,
218,246, 97,228,251, 34,242,193,238,210,144, 12,191,179,162,241,
81, 51,145,235,249, 14,239,107, 49,192,214, 31,181,199,106,157,
184, 84,204,176,115,121, 50, 45,127, 4,150,254,138,236,205, 93,
222,114, 67, 29, 24, 72,243,141,128,195, 78, 66,215, 61,156,180,
151,160,137, 91, 90, 15,131, 13,201, 95, 96, 53,194,233, 7,225,
140, 36,103, 30, 69,142, 8, 99, 37,240, 21, 10, 23,190, 6,148,
247,120,234, 75, 0, 26,197, 62, 94,252,219,203,117, 35, 11, 32,
57,177, 33, 88,237,149, 56, 87,174, 20,125,136,171,168, 68,175,
74,165, 71,134,139, 48, 27,166, 77,146,158,231, 83,111,229,122,
60,211,133,230,220,105, 92, 41, 55, 46,245, 40,244,102,143, 54,
65, 25, 63,161, 1,216, 80, 73,209, 76,132,187,208, 89, 18,169,
200,196,135,130,116,188,159, 86,164,100,109,198,173,186, 3, 64,
52,217,226,250,124,123, 5,202, 38,147,118,126,255, 82, 85,212,
207,206, 59,227, 47, 16, 58, 17,182,189, 28, 42,223,183,170,213,
119,248,152, 2, 44,154,163, 70,221,153,101,155,167, 43,172, 9,
129, 22, 39,253, 19, 98,108,110, 79,113,224,232,178,185,112,104,
218,246, 97,228,251, 34,242,193,238,210,144, 12,191,179,162,241,
81, 51,145,235,249, 14,239,107, 49,192,214, 31,181,199,106,157,
184, 84,204,176,115,121, 50, 45,127, 4,150,254,138,236,205, 93,
222,114, 67, 29, 24, 72,243,141,128,195, 78, 66,215, 61,156,180};
坐标映射到如下值:
return perlin_hash_values[perlin_hash_values[y & 255] + x & 255];
我遇到了一些问题:它吃了内存,并且重复得非常快,并且没有播种(至少参考实现。我猜你可以使用3D Perlin噪音,并将z值用作种子)和我想知道一个人是否可以更快。 (可能不是因为数组很可能在缓存中而且很难击败2个内存读取和3个指令)。我这样做主要是为了娱乐和学习一些东西。
用算法替换此方法有什么好方法?理想的属性可能是它很快,不会产生视觉伪像,也不会像这个数组一样快。
我首先考虑使用标准哈希函数,但我发现了两个不需要的属性:哈希函数通常采用任意长输入,这里不需要。他们还试图避免碰撞(不同输入的输出相同),这也不是必需的。至少如果我认为视觉伪像和碰撞之间可能没有强烈的相关性,那是正确的。这两个因素使标准哈希函数看起来不太复杂。所需要的只是从N维到1维的映射,看起来是随机的。
采用xorshift *伪随机数发生器:我将内部64位状态设置为x和y连接的值。
F32 xor_shift_star_adaption(S32 x, S32 y, U32 seed) {
union concat_S32
{
S32 s[2];
U64 u;
};
concat_S32 temp;
temp.s[0] = x;
temp.s[1] = y;
xorshift_star_64 xor;
xor.state = temp.u;
return xor.get_random_number();
}
It produces a LOT of artifacts我没有足够的声誉来发布图片:/。我怀疑伪随机数生成器不适合这项任务,因为我听说他们通常需要一些时间来“热身”。内部状态自我提升,时间越长,随机数的质量越高。通过这种方法,我可以防止prng“升温”。另一方面:状态可以被认为是数字的线性序列。如果我用这个线性序列中很长的数字初始化prng,我应该立即得到“高质量”数字吗?
使用这个超级简单的衬垫有人建议(现在不再是一个衬垫):
F32 internet_oneliner(S32 x, S32 y, U32 seed){
F32 xf = x;
F32 yf = y;
F32 dot = xf * 12.9898 + yf * 78.233;
F32 sin = sinf(dot) * 43758.5453;
F32 fract = sin - floorf(sin);
return fract;
}
它performs pretty well,但其中有一些昂贵的操作。
使用Murmur 3哈希函数,它似乎是(?)我能找到的最好的“普通”哈希函数。 (我不会在这里发布代码,它的大)。它也表现得非常好,但也需要很长时间才能完成工作。
尝试用素数来做一些xors和bithifting的东西,因为我认为那个prngs是如何工作的:D。你可以想象,它看起来很可怕(更接近抽象艺术而不是随机噪音)。如果没有对它们的一些了解,创建一个prng似乎是不可能的。
那么,您对下一步尝试有什么建议吗?我认为一般来说我更喜欢散列函数而不是prng,因为它更符合我想在这里实现的目标。
(我很抱歉没有链接和图片,声誉系统真的让我在这里搞砸了)
答案 0 :(得分:0)
两种可能的解决方案:
a)使用2D随机表。如果它适合L1缓存,它会很快。
b)使用整数哈希:http://burtleburtle.net/bob/hash/integer.html
例如,这个:
uint32_t hash( uint32_t a)
a = (a ^ 61) ^ (a >> 16);
a = a + (a << 3);
a = a ^ (a >> 4);
a = a * 0x27d4eb2d;
a = a ^ (a >> 15);
return a;
}
使用(hash((y <&lt; 8)+ x)&amp; 0xff)。
甚至,因为它是一个完整的32位散列,并且您只需要8位输出,您可以找到更快的变体。也许只是从这个哈希函数中删除一些操作:)(你可以尝试不仅仅是最低的8位,而是最高的8位,也许它有更好的属性)