我有一个返回有界噪声的函数。例如,假设输入范围为 [-1, 1]。使用我的方法,我可以返回有界/范围内的噪声(取决于我们当前所在的生物群系)。
/// <summary>
/// Converts the range.
/// </summary>
/// <param name="originalStart">The original start.</param>
/// <param name="originalEnd">The original end.</param>
/// <param name="newStart">The new start.</param>
/// <param name="newEnd">The new end.</param>
/// <param name="value">The value.</param>
/// <returns></returns>
public static float ConvertRange(
float originalStart, float originalEnd, // original range
float newStart, float newEnd, // desired range
float value) // value to convert
{
float scale = (newEnd - newStart) / (originalEnd - originalStart);
return (newStart + ((value - originalStart) * scale));
}
/// <summary>
/// Gets the bounded noise.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="meanHeight">Height of the mean.</param>
/// <param name="amplitude">The amplitude.</param>
/// <returns></returns>
// [InRange(-.5f, .5f)] && [InRange(0, 1)]
public static float GetBoundedNoise(float value, float meanHeight, float amplitude)
{
return Mathf.Clamp01(ConvertRange(0, 1, -amplitude, amplitude, ConvertRange(-1, 1, 0, 1, value)) + (meanHeight + .5f));
}
检查此以了解什么是平均高度和幅度:https ://i.gyazo.com/9dc9cbe949f82d7342d7778e904563de.mp4
注意:噪声值由 FastNoise 库给出。(你可以在Github上看到它)
问题是每个区域边界上的高度不匹配:
正常区域:
噪声区域:
黑色像素等于 y=0,白色像素等于 y=1。(可以忽略黄色像素)
但正如您所见,不同的生物群落具有不同的幅度和平均高度(水、草、草、干草、沥青)。
我尝试过高斯卷积,但有一个问题:CPU 迭代次数过多(最好在 GPU 中执行)。
为什么?好吧,我对每个区域边界像素应用高斯卷积(我有一个优化的方法来得到它)。想象一下,我们得到 810k 点。并为每个像素应用一个卷积,有 81 次迭代(以获得该部分的高度平均值)。但这仅适用于一个像素,现在我们必须为另外 81 个像素 (9x9) 或 25 个像素 (5x5) 或其他任何东西取平均值。
(在最好的情况下)有 1,640,250,000 次迭代要做(在每个区域边界周围获得一个非常小的平滑网格)。
您可以查看我的旧代码:
// Smothing segments
//var kernel = Kernels.GAUSSIAN_KERNEL_9;
//int kernelSize = kernel.GetLength(0);
//if (pol != null && !pol.Segments.IsNullOrEmpty())
// foreach (Segment segment in pol.Segments)
// {
// int d = segment.Distance;
// for (int i = 0; i <= d; ++i)
// {
// Point p = (Vector2)segment.start + segment.Normal * d;
// //if (d % kernelSize == 0) // I tried to get less itwrations by checking if the current d modulus from kernelSize was 0. But no luck.
// Filters<Color32>.ConvolutionAtPoint(mapWidth, mapHeight, p.x, p.y, target, kernel, 1, pol.Center.x, pol.Center.y, true);
// }
// }
//else
//{
// if (pol == null)
// ++nullPols;
// else if (pol != null && pol.Segments.IsNullOrEmpty())
// ++nullSegments;
//}
++ 是调试计数器,忽略它们。
点卷积执行以下操作:
private static void ConvolutionAtPointFunc(int width, int height, T[] source, params object[] parameters)
{
float[][] kernel = (float[][])parameters[0];
int kernelSize = kernel.Length;
int iteration = (int)parameters[1];
int _x = (int)parameters[2];
int _y = (int)parameters[3];
int xOffset = (int)parameters[4];
int yOffset = (int)parameters[5];
bool withGrid = (bool)parameters[6];
for (int ite = 0; ite < iteration; ++ite)
{
Color c = new Color(0f, 0f, 0f, 0f);
for (int y = 0; y < kernelSize; ++y)
{
int ky = y - kernelSize / 2;
for (int x = 0; x < kernelSize; ++x)
{
int kx = x - kernelSize / 2;
try
{
if (!withGrid)
{
c += ((Color)(dynamic)source[F.P(_x + kx + xOffset, _y + ky + yOffset, width, height)]) * kernel[x][y];
++FiltersDebug.convolutionIterations;
}
else
{
for (int i = 0; i < 81; ++i)
{
int __x = i % 9,
__y = i / 9;
c += ((Color)(dynamic)source[F.P(_x + __x + kx + xOffset, _y + __y + ky + yOffset, width, height)]) * kernel[x][y];
++FiltersDebug.convolutionIterations;
}
source[F.P(_x + kx + xOffset, _y + ky + yOffset, width, height)] = (dynamic)c;
}
}
catch
{
++FiltersDebug.outOfBoundsExceptionsIn;
}
}
}
if (!withGrid)
try
{
source[F.P(_x + xOffset, _y + yOffset, width, height)] = (dynamic)c;
}
catch
{
++FiltersDebug.outOfBoundsExceptions;
}
}
}
如您所见,非常未优化。代码来自:http ://wiki.unity3d.com/index.php/TextureFilter
我无法想象有任何其他方法可以做到这一点。我能想到的最好的方法是画一条垂直线(垂直于当前段(我有一个工具来获取多边形的边缘(段由起点和终点形成,其中段起点 = 当前边缘和段结束 = 前一个边缘)))(线中每个点的平均噪声)。但也有一个问题:
具有钝投影的段之间存在间隙(用黄色标记)。以及在具有锐利投影的片段上的重叠噪声梯度。
我意识到的另一种方法是从所有需要它的区域边界获取渐变轮廓。
像这样的东西:
我还看到了 Cuberite 的实现(http://cuberite.xoft.cz/docs/Generator.html#heightgen):
但我不明白这部分,如果我能从中提取一些东西:
如果我们取以查询列为中心的 9x9 生物群落区域,为其中的每个生物群落生成高度,将它们相加并除以 81(总和的生物群落数量),我们将有效地得出一个 9 长的运行平均值地形,所有的边界都会突然变得平坦。下图显示了应用平均过程后上一段的情况。
注意:我已经创建了一个扭曲的 voronoi 函数来获取地形点的当前生物群落(按照本指南,但我不完全了解该怎么做,因为我不了解这种方法,也看不到任何相关代码到本文)。
但我不知道从哪里开始,也不知道如何用优化算法解决问题。另外,我不知道该研究什么。所以我有一个问题,因此,欢迎任何帮助。