为何我的Fractal Noise出现网格轮廓线?附代码求助
分形噪声平铺异常问题修复

背景说明
getFractalPointHeight() 函数用于根据Perlin噪声图像的坐标,结合amplitude(振幅)和frequency(频率)参数返回分形噪声的高度值。其中通过getPointHeight()函数从尺寸为nodesxn - 1 * nodesyn - 1的Perlin噪声网格中获取基础高度值。
问题描述
函数中用四个while循环处理坐标超出Perlin噪声边界的情况,但实际运行后噪声无法正确平铺,出现明显的网格轮廓线(如上图所示)。
原代码
float getFractalPointHeight(float x,float y,int octaves,float amplitude,float frequency){ float elevation = amplitude; for(int i = 0;i<octaves;i++){ float sx = x * frequency; float sy = y * frequency; while(sx < 0){ sx = sx + (nodesxn - 1); } while(sy < 0){ sy = sy + (nodesyn - 1); } while(sx > nodesxn - 1){ sx = sx - (nodesxn - 1); } while(sy > nodesyn - 1){ sy = sy - (nodesyn - 1); } elevation += getPointHeight(sx,sy) * amplitude; frequency *= 2; amplitude *= 0.5; } elevation = fmin(2,fmax(elevation,0)); return elevation; }
问题原因与修复方案
问题根源
用while循环做坐标回卷的方式存在两个核心问题:
- 当频率为2的整数倍时,高八度的噪声网格会成为基础网格的子集,回卷逻辑容易导致边界处的噪声值不连续;
while循环的逐次加减无法处理浮点数的精确映射,边界坐标计算偏差直接导致网格线出现。
修复代码
用浮点数取模运算替代while循环,直接实现坐标的无缝平铺,确保边界处的连续性:
float getFractalPointHeight(float x,float y,int octaves,float amplitude,float frequency){ float elevation = amplitude; float gridWidth = nodesxn - 1; float gridHeight = nodesyn - 1; for(int i = 0;i<octaves;i++){ float sx = fmod(x * frequency, gridWidth); float sy = fmod(y * frequency, gridHeight); // 修正负数取模的结果,确保坐标落在[0, 网格尺寸)区间内 if(sx < 0) sx += gridWidth; if(sy < 0) sy += gridHeight; elevation += getPointHeight(sx,sy) * amplitude; frequency *= 2; amplitude *= 0.5; } elevation = fmin(2,fmax(elevation,0)); return elevation; }
额外注意事项
如果getPointHeight()依赖的基础Perlin噪声本身不具备无缝平铺特性(即网格左右、上下边缘的噪声值与梯度不连续),仅靠坐标回卷无法彻底解决问题。此时需要生成无缝平铺的Perlin噪声纹理,确保网格边缘的噪声属性完全一致,多层八度叠加后才不会出现接缝。
内容的提问来源于stack exchange,提问作者Gabriel
相关产品推荐
相关产品推荐

