unity-game-engine - 使用洪水方法创建 2D 圆

标签 unity-game-engine geometry contour terrain

我正在尝试生成如下所示的地形轮廓线: enter image description here

我的最终目标是根据一些用户定义的点生成等高线(例如:这座山的海拔为 100m,坡度为 X)。

目前,我生成高度图的算法是一种径向洪水填充,其中每个点设置其当前高度,然后将其 8 个邻居(包括对角线)排入队列,将其高度设置为当前高度 - 的值斜坡。 heightmap 是一个二维 double 组,表示 map 上每个 x/y 点的高度。 sqrt_2 是 2 的平方根的值,我们乘以对角邻居的斜率值来表示它们距当前点的真实距离。每个点还向外传播其斜率(高度向默认高度移动的速率。EnqueueIfValidPoint 只是将一个点添加到 point_to_assign 队列中。想法是从我们知道高度的某些点开始,并缓慢倾斜/梯度朝向默认高度(在本例中为 0)。points_to_assign 是常规 FIFO 队列。

此代码是在 Unity 中用 C# 编写的,但该语言不会改变其背后的逻辑。

// Continue the flood fill until we're out of points to assign
while (points_to_assign.Count > 0)
{

    PointToAssign p = points_to_assign.Dequeue();

    // Check if we have already assigned a height to this point
    if (heightmap[p.x_pos, p.y_pos] == unassigned_height)
    {
        assigned_points++;
        // Assign a height to this point
        heightmap[p.x_pos, p.y_pos] = p.height;


        // Height to assign neighbours to, moved towards default floor value
        double slope = p.slope;//GetRandomSlope(p.x_pos, p.y_pos, p.slope);

        double orthogonal_heights = 0;
        if (p.height >= 0)
            orthogonal_heights = Math.Max(0, p.height - (slope));
        else
            orthogonal_heights = Math.Min(0, p.height + (slope));
        // Enqueue neighbours of this point to assign a new height to
        // Below
        EnqueueIfValidPoint(points_to_assign, heightmap, p.x_pos - 1, p.y_pos, orthogonal_heights, p.slope);
        // Above
        EnqueueIfValidPoint(points_to_assign, heightmap, p.x_pos + 1, p.y_pos, orthogonal_heights, p.slope);
        // Left
        EnqueueIfValidPoint(points_to_assign, heightmap, p.x_pos, p.y_pos - 1, orthogonal_heights, p.slope);
        // Right
        EnqueueIfValidPoint(points_to_assign, heightmap, p.x_pos, p.y_pos + 1, orthogonal_heights, p.slope);

        double diagonal_heights = 0;
        if (p.height >= 0)
            diagonal_heights = Math.Max(0, p.height - (slope * sqrt_2));
        else
            diagonal_heights = Math.Min(0, p.height + (slope * sqrt_2));
        // Below and left
        EnqueueIfValidPoint(points_to_assign, heightmap, p.x_pos - 1, p.y_pos - 1, diagonal_heights, p.slope);
        // Below and right
        EnqueueIfValidPoint(points_to_assign, heightmap, p.x_pos + 1, p.y_pos - 1, diagonal_heights, p.slope);
        // Above and left
        EnqueueIfValidPoint(points_to_assign, heightmap, p.x_pos - 1, p.y_pos + 1, diagonal_heights, p.slope);
        // Above and right
        EnqueueIfValidPoint(points_to_assign, heightmap, p.x_pos + 1, p.y_pos + 1, diagonal_heights, p.slope);
    }
}

然后将高度值传递给指定颜色的颜色函数,例如:如果高度在 0 到 1 之间,则指定为白色,如果高度在 1 到 2 之间,则指定为浅绿色,等等。

不幸的是,这段代码并不能完全生成圆形,而是生成一个八边形。我想这个问题与编码对角邻居值有关 enter image description here

有人知道如何使用我的洪水填充策略生成一个圆形而不是八边形吗?

最佳答案

问题是,当您混合两种步骤类型(对角线和正交)时,您会得到错误的距离。例如,正交步骤 + 对角线步骤会产生 sqrt(5) ~ 2.24 的实际距离。但你的算法给你1 + sqrt(2) ~ 2.41。这就是圆圈被切断的原因。

您需要做的是计算距种子点的实际距离。只需将种子点与队列中的项目一起存储(或者如果只有一个,则使用这个)并根据距离计算高度。一些事情:

heightmap[p.x_pos, p.y_pos] = distance(p.seedPoint, p) * p.slope + p.seedPoint.height;

您还可以在外部存储种子点及其斜率,然后在队列中引用它以节省一些内存。

还可以通过累加 x 差值和 y 差值来增量计算欧氏距离,然后仅计算 sqrt(x-difference^2 + y-difference^2)。但这可能不值得付出努力。

关于unity-game-engine - 使用洪水方法创建 2D 圆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50902966/

相关文章:

c# - Vector3.Lerp Unity3D 期间目标发生变化

unity-game-engine - 让汽车爬上斜坡

c# - Mongodb:如何检查一个点是否包含在多边形中?

algorithm - 如何将三角形的二维网格转换为四边形?

c++ - findcontours opencv中的段错误

r - 是否可以在 R 中创建没有连续数据的 3d 等高线图?

c# - Unity3D 声明变量或使用 GetComponent

ios - Onesignal Unity IOS 构建符号未找到错误

ios - 使用约束从用户点击计算点坐标

python - OpenCV Python : Closed Contour Approximation For A Speech Bubble Shape