我今天花了几个小时来研究如何进行随机地形生成,在阅读了等离子体分形(中点位移和钻石平方算法)后,我决定尝试实施一个。我的结果实际上并不可怕,但我有这些可怕的方形/线条/网格类型的文物,我似乎无法摆脱它!
当渲染为灰度图像时,我的高度图看起来像: height map http://sphotos-d.ak.fbcdn.net/hphotos-ak-ash3/535816_10151739010123327_225111175_n.jpg
显然,涉及到相当多的代码,但我会尝试发布仅相关的代码。我没有发布将它变成纹理的代码,但不要担心我已经尝试用平滑渐变填充我的高度数组并且纹理很好:)
首先,我将地图的四个角设置为0到1之间的随机值,然后启动递归置换算法:
public void GenerateTerrainLayer()
{
//set the four corners of the map to have random values
TerrainData[0, 0] = (float)RandomGenerator.NextDouble();
TerrainData[GenSize, 0] = (float)RandomGenerator.NextDouble();
TerrainData[0, GenSize] = (float)RandomGenerator.NextDouble();
TerrainData[GenSize, GenSize] = (float)RandomGenerator.NextDouble();
//begin midpoint displacement algorithm...
MidPointDisplace(new Vector2_I(0, 0), new Vector2_I(GenSize, 0), new Vector2_I(0, GenSize), new Vector2_I(GenSize, GenSize));
}
TerrainData只是一个浮点数*的2D数组。 Vector2_I只是我自己的整数向量类。最后四个函数是MidPointDisplace,它是递归函数,CalculateTerrainPointData平均2个数据值并添加一些噪声,CalculateTerrainPointData2平均4个数据值并添加一些噪声并具有稍高的比例值(它仅用于中心点),最后我的噪音函数,atm只是一些随机噪音而不是像perlin等真正的噪音。它们看起来像这样:
private void MidPointDisplace(Vector2_I topleft, Vector2_I topright, Vector2_I bottomleft, Vector2_I bottomright)
{
//check size of square working on.. if its shorter than a certain amount stop the algo, we've done enough
if (topright.X - topleft.X < DisplacementMaxLOD)
{
return;
}
//calculate the positions of all the middle points for the square that has been passed to the function
Vector2_I MidLeft, MidRight, MidTop, MidBottom, Center;
MidLeft.X = topleft.X;
MidLeft.Y = topleft.Y + ((bottomleft.Y - topleft.Y) / 2);
MidRight.X = topright.X;
MidRight.Y = topright.Y + ((bottomright.Y - topright.Y) / 2);
MidTop.X = topleft.X + ((topright.X - topleft.X) / 2);
MidTop.Y = topleft.Y;
MidBottom.X = bottomleft.X + ((bottomright.X - bottomleft.X) / 2);
MidBottom.Y = bottomleft.Y;
Center.X = MidTop.X;
Center.Y = MidLeft.Y;
//collect the existing data from the corners of the area passed to algo
float TopLeftDat, TopRightDat, BottomLeftDat, BottomRightDat;
TopLeftDat = GetTerrainData(topleft.X, topleft.Y);
TopRightDat = GetTerrainData(topright.X, topright.Y);
BottomLeftDat = GetTerrainData(bottomleft.X, bottomleft.Y);
BottomRightDat = GetTerrainData(bottomright.X, bottomright.Y);
//and the center
//adverage data and insert for midpoints..
SetTerrainData(MidLeft.X, MidLeft.Y, CalculateTerrainPointData(TopLeftDat, BottomLeftDat, MidLeft.X, MidLeft.Y));
SetTerrainData(MidRight.X, MidRight.Y, CalculateTerrainPointData(TopRightDat, BottomRightDat, MidRight.X, MidRight.Y));
SetTerrainData(MidTop.X, MidTop.Y, CalculateTerrainPointData(TopLeftDat, TopRightDat, MidTop.X, MidTop.Y));
SetTerrainData(MidBottom.X, MidBottom.Y, CalculateTerrainPointData(BottomLeftDat, BottomRightDat, MidBottom.X, MidBottom.Y));
SetTerrainData(Center.X, Center.Y, CalculateTerrainPointData2(TopLeftDat, TopRightDat, BottomLeftDat, BottomRightDat, Center.X, Center.Y));
debug_displacement_iterations++;
//and recursively fire off new calls to the function to do the smaller squares
Rectangle NewTopLeft = new Rectangle(topleft.X, topleft.Y, Center.X - topleft.X, Center.Y - topleft.Y);
Rectangle NewTopRight = new Rectangle(Center.X, topright.Y, topright.X - Center.X, Center.Y - topright.Y);
Rectangle NewBottomLeft = new Rectangle(bottomleft.X, Center.Y, Center.X - bottomleft.X, bottomleft.Y - Center.Y);
Rectangle NewBottomRight = new Rectangle(Center.X , Center.Y, bottomright.X - Center.X, bottomright.Y - Center.Y);
MidPointDisplace(new Vector2_I(NewTopLeft.Left, NewTopLeft.Top), new Vector2_I(NewTopLeft.Right, NewTopLeft.Top), new Vector2_I(NewTopLeft.Left, NewTopLeft.Bottom), new Vector2_I(NewTopLeft.Right, NewTopLeft.Bottom));
MidPointDisplace(new Vector2_I(NewTopRight.Left, NewTopRight.Top), new Vector2_I(NewTopRight.Right, NewTopRight.Top), new Vector2_I(NewTopRight.Left, NewTopRight.Bottom), new Vector2_I(NewTopRight.Right, NewTopRight.Bottom));
MidPointDisplace(new Vector2_I(NewBottomLeft.Left, NewBottomLeft.Top), new Vector2_I(NewBottomLeft.Right, NewBottomLeft.Top), new Vector2_I(NewBottomLeft.Left, NewBottomLeft.Bottom), new Vector2_I(NewBottomLeft.Right, NewBottomLeft.Bottom));
MidPointDisplace(new Vector2_I(NewBottomRight.Left, NewBottomRight.Top), new Vector2_I(NewBottomRight.Right, NewBottomRight.Top), new Vector2_I(NewBottomRight.Left, NewBottomRight.Bottom), new Vector2_I(NewBottomRight.Right, NewBottomRight.Bottom));
}
//helper function to return a data value adveraged from two inputs, noise value added for randomness and result clamped to ensure a good value
private float CalculateTerrainPointData(float DataA, float DataB, int NoiseX, int NoiseY)
{
return MathHelper.Clamp(((DataA + DataB) / 2.0f) + NoiseFunction(NoiseX, NoiseY), 0.0f, 1.0f) * 1.0f;
}
//helper function to return a data value adveraged from four inputs, noise value added for randomness and result clamped to ensure a good value
private float CalculateTerrainPointData2(float DataA, float DataB, float DataC, float DataD, int NoiseX, int NoiseY)
{
return MathHelper.Clamp(((DataA + DataB + DataC + DataD) / 4.0f) + NoiseFunction(NoiseX, NoiseY), 0.0f, 1.0f) * 1.5f;
}
private float NoiseFunction(int x, int y)
{
return (float)(RandomGenerator.NextDouble() - 0.5) * 0.5f;
}
好的,谢谢花时间去看 - 希望有人知道这个网格状模式出现在哪里:)
*编辑 - 意外写入整数,更正为花车
答案 0 :(得分:2)
我在您的代码中发现了3个问题。 (其中2个是相关的)
你不要缩减每一步的随机性。每一步都必须减少随机性。否则你会得到白色( - )噪音。你选择一个因子(0.5-0.7对我来说工作得很好)并在每次递归中将减少乘以alpha,然后按照该因子缩放生成的随机数。
你交换了钻石和方形步骤。首先是钻石,然后是正方形。反过来是不可能的(见下)。
您的方形步骤仅使用一个方向上的点。这个可能导致你正在谈论的矩形结构。方块必须将值平均到四个边。这意味着平方步长取决于钻石步骤产生的点。而且不仅是您当前正在查看的矩形的菱形步骤,还有它旁边的矩形。对于地图之外的值,您可以换行,使用固定值或仅平均3个值。
答案 1 :(得分:1)
我在CalculateTerrainPointData
实施中发现了一个问题:您没有在每次迭代时缩小NoiseFunction
的结果。
请参阅Midpoint Displacement算法的this description:
- 从单个水平线段开始。
- 重复足够多次:
- 重复场景中的每个线段:
- 找到线段的中点。
- 以Y为单位移动Y中点。
- 缩小随机数的范围。
在代码中执行此操作而不会进行太多更改的快速方法是向scale
添加一些MidPointDisplace
参数(默认设置为1.0f)和CalculateTerrainPointData
;在CalculateTerrainPointData
中使用它来乘以NoiseFunction
的结果;并通过每次递归调用MidPointDisplace(..., 0.5f * scale)
来减少它。
不确定这是否是图片看起来错误或存在其他问题的唯一原因。
答案 2 :(得分:0)
根据维基百科的summary of midpoint displacement,只有中心点的平均值会增加噪音 - 尝试只通过CalculateTerrainPointData2
&amp;添加噪音。消除CalculateTerrainPointData
中的噪音。