1D线性值噪声非均匀分布,求均匀分布的连续噪声函数
实现均匀分布的连续噪声用于概率场景
我实现了一个简单的1D Value Noise函数:
public float ValueNoise1D(float x) { int l = Mathf.FloorToInt(x); int r = l + 1; float vl = hashToFloat(hash(l)); float vr = hashToFloat(hash(r)); float lerp = Mathf.InverseLerp(l, r, x); return Mathf.Lerp(vl, vr, lerp); } //Based on Murmur3 int hash(int key) { uint k = (uint)key; k += 0x7ed55d16; k ^= k >> 16; k *= 0x85ebca6b; k ^= k >> 13; k *= 0xc2b2ae35; k ^= k >> 16; return (int)(k & 0x7fffffff); } float hashToFloat(int hash) { return hash / (float)0x80000000; }
经测试,该函数的概率密度函数(PDF)呈三角分布——因为它是对两个均匀分布的随机值做线性插值,导致输出更集中在中间值,无法直接用于概率计算场景(比如模拟降雨:需要连续的干湿周期,但要求噪声输出在[0,1]区间均匀分布,即0-0.1与0.4-0.5区间的输出概率相等)。
解决方案1:用逆累积分布函数(CDF)重映射到均匀分布
你的Value Noise输出是三角分布,对应的CDF和逆CDF可推导如下:
- 三角分布的PDF:
f(t) = 2(1 - |t - 0.5|),t∈[0,1] - 对应的CDF:
- 当
t ≤ 0.5时,CDF(t) = 2t² - 当
t > 0.5时,CDF(t) = 1 - 2(1-t)²
- 当
- 逆CDF(将三角分布转换为均匀分布):
- 对于均匀输入
u ∈ [0, 0.5],输出t = sqrt(u/2) - 对于均匀输入
u ∈ (0.5, 1],输出t = 1 - sqrt((1-u)/2)
- 对于均匀输入
将逆CDF应用到你的Value Noise输出上,即可得到均匀分布的连续噪声:
float RemapTriangularToUniform(float triangularNoise) { if (triangularNoise <= 0.5f) { return Mathf.Sqrt(triangularNoise / 2f); } else { return 1f - Mathf.Sqrt((1f - triangularNoise) / 2f); } } // 使用方式 float uniformNoise = RemapTriangularToUniform(ValueNoise1D(x));
解决方案2:直接基于非均匀噪声调整概率阈值
如果不想修改噪声生成逻辑,可以根据噪声的CDF调整判断阈值。比如要实现30%的降雨概率:
- 找到三角分布CDF等于0.3对应的t值:解方程
2t² = 0.3,得t ≈ 0.387 - 当
ValueNoise1D(x) < 0.387时,判定为降雨,此时整体降雨概率正好是30%
这种方法不需要转换分布,只需要根据目标概率反推对应的噪声阈值即可。
解决方案3:原生均匀分布连续噪声构造
如果希望从根源生成均匀分布的连续噪声,可以采用连续单调变换+均匀随机点的方式:
- 在整数点生成均匀分布的随机值
- 使用单调递增/递减的连续函数连接这些点(比如用
y = x³这类单调函数代替线性插值),但需要确保整体变换后保持均匀分布——不过这种方法的复杂度高于逆CDF重映射,实际场景中方案1是最优选择。
内容的提问来源于stack exchange,提问作者The Justice King
相关产品推荐
相关产品推荐

