我一直在生成噪声纹理以用作地形生成的高度图。在此应用程序中,最初有一个 256x256 噪声纹理,用于创建用户可以自由漫游的一 block 土地。当用户在游戏中到达某个边界时,应用程序会生成一个新纹理,从而生成另一个地形 block 。
在代码中,生成了一个 64x64 随机值的表格,纹理中的值是使用 smoothstep 函数在不同“频率”和“波长”下在这些点之间插值的结果,然后组合形成最终的噪声纹理;最后,纹理中的值除以其最大值以有效地对其进行归一化。当玩家在边界处并创建新纹理时,创建的随机数表会重新使用前一个纹理的适当边缘的值(例如,如果新纹理是针对位于前一个纹理的+X侧,前一个纹理每行中的最后一个值用作下一个随机数每行中的第一个值。)
我的问题是:即使在相邻纹理的边缘使用相同的值,它们也远不是无缝的——地形上的一些相邻点不匹配很多米。我的猜测是,用于对随机数字表进行采样的变化频率可能对纹理的所有区域都有重大影响。那么一个人如何在程序上产生分形噪声,即。根据需要,它看起来是否与相邻值连续?
下面是一段代码,它返回一个给定点 P 的随机数表上的点之间的内插值:
float MainApp::assessVal(glm::vec2 P){
//Integer component of P
int xi = (int)P.x;
int yi = (int)P.y;
//Decimal component ofP
float xr = P.x - xi;
float yr = P.y - yi;
//Find the grid square P lies inside of
int x0 = xi % randX;
int x1 = (xi + 1) % randX;
int y0 = yi % randY;
int y1 = (yi + 1) % randY;
//Get random values for the 4 nodes
float r00 = randNodes->randNodes[y0][x0];
float r10 = randNodes->randNodes[y0][x1];
float r01 = randNodes->randNodes[y1][x0];
float r11 = randNodes->randNodes[y1][x1];
//Smoother interpolation so
//texture appears less blocky
float sx = smoothstep(xr);
float sy = smoothstep(yr);
//Find the weighted value of the 4
//random values. This will be the
//final value in the noise texture
float sx0 = mix(r00, r10, sx);
float sx1 = mix(r01, r11, sx);
return mix(sx0, sx1, sy);
}
其中 randNodes 是一个包含随机值的二维数组。
下面是获取上述函数返回的所有值并构造纹理数据的代码:
int layers = 5;
float wavelength = 1, frequency = 1;
for (int k = 0; k < layers; k++) {
for (int i = 0; i < stepsY; i++) {
for(int j = 0; j < stepsX; j++){
//Compute value for (stepsX * stepsY) interpolation points
//across the grid of random numbers
glm::vec2 P = glm::vec2((float)j/stepsX * randX, (float)i/stepsY * randY);
buf[i * stepsY + j] += assessVal(P * wavelength) * frequency;
}
}
//repeat (layers) times with different signals
wavelength *= 0.5;
frequency *= 2;
}
for(int i = 0; i < buf.size(); i++){
//divide all data by the largest value.
//this normalises the data to avoid saturation
buf[i] /= largestVal;
}
最后,这是由这些函数生成的两个纹理的示例,它们应该是无缝的,但实际上不是:
现在并排放置的 2 张图片显然不匹配。
最佳答案
您的代码仅将值包装在您从中读取的噪声纹理域中,而不是在正在生成的纹理域中。
要使大小为 stepX
的纹理 T 可重复(为简单起见,让我们考虑一维情况),您必须有
T(0) == T(stepX)
或者在您的情况下(替换 j = 0
和 j = stepX
):
assessVal(0) == assessVal(randX * wavelength)
当 k >= 1
时,这在您的代码中显然不正确,因为
(randX / pow(2, k)) % randX != 0
一种解决方案是在提高频率的同时降低 randX
和 randY
。
但我的典型方法是从一个 2x2
随机纹理开始,用 GL_REPEAT
将它放大到 4x4
,每增加一点- 像素噪声,继续放大到 8x8
等。直到我达到所需的大小。
关于c++ - 程序生成无缝分形噪声纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40715519/