Unity C#中Perlin Noise函数为何始终出现对称性问题?
Perlin Noise 对称性问题排查与解决
问题现象
使用Perlin Noise生成地形时,始终出现异常对称性,尝试偏移调整等方法后仍无法消除。
问题代码
int verticesx = (cubeAmountX) + 1; int verticesy = (cubeAmountY) + 1; for(float x = ((chunkX) * (cubeAmountX/3)); x < verticesx + ((chunkX) * (cubeAmountX/3)); x++){ for(float y = ((chunkY) * (cubeAmountY/3)); y < verticesy + ((chunkY)* (cubeAmountY/3)); y++){ float perlinNoiseResult = Mathf.PerlinNoise((x + 0.1f) / 100 * scale + 132765, (y + 0.2f) / 100 * scale + 38789); perlinNoiseResult *= (Mathf.PerlinNoise((x + 0.3f) / 100 * scale * (x + 0.4f) / 100 * scale + 132765, (y + 0.5f) / 100 * scale * (y + 0.6f) / 100 * scale + 38789)) / 5 + 1; float biomeDecider = (Mathf.PerlinNoise(Mathf.Sqrt(Mathf.Abs(x + 0.7f) / 100 * scale) + 132765, Mathf.Sqrt(Mathf.Abs(y + 0.8f) / 100 * scale) + 38789)); biomeDecider = 1/(1+Mathf.Pow(2,(-16*(biomeDecider - 0.5f)))); perlinNoiseResult *= biomeDecider + 0.1f; vertices.Add(new Vector3(x * lengthBetweenVertices, perlinNoiseResult * maxheight - 10, y * lengthBetweenVertices)); uv.Add(new Vector2(x/verticesx,y/verticesy)); for(int ix = 0;ix < detail * lengthBetweenVertices;ix++){ for(int iy = 0; iy < detail * lengthBetweenVertices;iy++){ Color color = CalculateColor(Mathf.PerlinNoise((x + ix/detail/lengthBetweenVertices)/ 100 * scale, (y + iy/detail/lengthBetweenVertices) / 100 * scale) * biomeDecider * maxheight - 10, maxheight); texture.SetPixel((int)x * (int)detail * (int)lengthBetweenVertices + ix,(int)y * (int)detail * (int)lengthBetweenVertices + iy,color); } } } }
问题根源
- 二次项乘法引入对称:第二个
Mathf.PerlinNoise的x参数使用了(x+0.3f)/100*scale * (x+0.4f)/100*scale,这是x的二次函数,存在对称轴,会导致噪声在对称轴两侧呈现对称分布。 - 绝对值运算强制对称:
biomeDecider中使用了Mathf.Abs(x + 0.7f),这会让x + 0.7f和-(x + 0.7f)得到相同的输入值,直接引入关于x = -0.7f的镜像对称,最终传递到地形高度计算中。
修正方案
- 把第二个噪声的参数从二次乘法改成线性偏移,保持输入的连续性与非对称性:
// 原代码 Mathf.PerlinNoise((x + 0.3f) / 100 * scale * (x + 0.4f) / 100 * scale + 132765, ...) // 修正后 Mathf.PerlinNoise((x + 0.3f) / 100 * scale + 0.4f + 132765, (y + 0.5f) / 100 * scale + 0.6f + 38789) - 移除
biomeDecider中的Mathf.Abs,改用线性输入:// 原代码 Mathf.PerlinNoise(Mathf.Sqrt(Mathf.Abs(x + 0.7f) / 100 * scale) + 132765, ...) // 修正后 Mathf.PerlinNoise((x + 0.7f) / 100 * scale + 132765, (y + 0.8f) / 100 * scale + 38789) - 确保所有Perlin Noise的输入参数都是线性变换,避免使用平方、绝对值这类会产生对称的运算,保持噪声的自然随机性。
内容的提问来源于stack exchange,提问作者Jeffie The Turtle
相关产品推荐
相关产品推荐

