平滑不同幅度的噪声(第2部分)

时间:2018-11-27 18:28:10

标签: c# unity3d interpolation noise amplitude

好吧,我继续这个问题,没有答案(Smoothing random noises with different amplitudes),还有另一个问题。

我选择使用形状(Translating/transforming? list of points from its center with an offset/distance)的轮廓/阴影。

此轮廓/阴影大于当前路径。我使用此存储库(https://github.com/n-yoda/unity-vertex-effects)重新创建了阴影。除一个事实外,这非常有效。

要知道所有点的高度(通过此阴影算法(Line 13 of ModifiedShadow.csLine 69 of CircleOutline.cs获得),我得到了当前点到中心的距离,并在到点的最大距离之间进行划分。中心:

float dist = orig.Max(v => (v - Center).magnitude);
foreach Point in poly --> float d = 1f - (Center - p).magnitude / dist;

其中orig是通过阴影算法获得的所有点的完整列表。 D是阴影的高度。

但是问题很明显,我得到了一个完美的圈子:

...

用红色和黑色查看对比度:

...

这不是我想要的:

...

如您所见,这并不是一个完美的渐变。让我们解释发生了什么。

我使用这个库来产生噪音:https://github.com/Auburns/FastNoise_CSharp

注意::如果您想了解如何使用不同幅度的噪声:Smoothing random noises with different amplitudes(请参见第一段代码),请参见{{3} }

see this repo

  • 绿色背景代表噪声,其平均高度为-0.25,幅度为0.3
  • 白色背景颜色表示平均高度为0且幅度为0.1的噪声
  • 红色表示1(对与白色像素相对应的噪声进行总插值)
  • 黑色表示0(对与绿色像素相对应的噪声进行总插值)

这就是为什么我们有以下输出:

...

实际上,我尝试比较每个点到中心的距离,但这会产生奇怪且出乎意料的结果。

实际上,我不知道该怎么做...

1 个答案:

答案 0 :(得分:2)

问题在于lerp百分比(例如,在可视化中从高/低或“红色”到“黑色”)仅是点到中心的距离的函数,该距离除以常数(这会发生是任何点到中心的最大距离)。这就是为什么它看起来是圆形的。

例如,多边形左侧的最中心点可能离中心300像素,而右侧的最中心点可能是5像素。两者都必须为红色,但以0 distance from center = red为基础将不会是红色,而以min distance from center = red为基础将仅在右侧具有红色。

相关的最小和最大距离将根据点的位置而改变

针对每个点的一种替代方法是:找到最接近的白色像素,然后找到最接近的绿色像素(或与绿色/白色相邻的最接近的阴影像素,例如here)。然后,根据这两个点与当前点之间的距离比较方式选择红色。

因此,您可以执行此操作(伪C#):

foreach pixel p in shadow_region {

    // technically, closest shadow pixel which is adjacent to x Pixel: 
    float closestGreen_distance = +inf;
    float closestWhite_distance = +inf;

    // Possibly: find all shadow-adjacent pixels prior to the outer loop 
    // and cache them. Then, you only have to loop through those pixels.
    foreach pixel p2 in shadow {
        float p2Dist = (p-p2).magnitude;

        if (p2 is adjacent to green) {
           if (p2Dist < closestGreen_distance) {
               closestGreen_distance = p2Dist;
           }
        }

        if (p2 is adjacent to white) {
           if (p2Dist < closestWhite_distance) {
               closestWhite_distance = p2Dist;
           }
        }
    }

    float d = 1f - closestWhite_distance / (closestWhite_distance + closestGreen_distance)
}

使用您在评论中发布的代码,看起来可能像这样:

foreach (Point p in value)
{
    float minOuterDistance = outerPoints.Min(p2 => (p - p2).magnitude);
    float minInnerDistance = innerPoints.Min(p2 => (p - p2).magnitude);

    float d = 1f - minInnerDistance / (minInnerDistance + minOuterDistance);

    Color32? colorValue = func?.Invoke(p.x, p.y, d);

    if (colorValue.HasValue)
        target[F.P(p.x, p.y, width, height)] = colorValue.Value;
}

选择上面的部分作为解决方案。下面的部分,作为另一个选项,被证明是不必要的。


如果您不能确定阴影像素是否与白色/绿色相邻,则这是一种替代方法,只需要计算粉色(原始)轮廓中每个顶点的法线即可。

通过转到每个粉红色顶点并遵循其法线向外来创建外部“黄色”顶点。通过转到每个粉红色顶点并遵循其正常向内的方式来创建内部“蓝色”顶点。

然后,当遍历阴影中的每个像素时,遍历黄色顶点以获得“最接近绿色”,并遍历蓝色顶点以获得“最接近白色”。

问题在于,由于您的形状不是完全凸出的,因此这些投影的蓝色和黄色轮廓在某些地方可能会由内向外,因此您需要以某种方式进行处理。我在确定处理该问题的确切方法时遇到了麻烦,但这是我到目前为止所拥有的:

第一步是忽略具有指向当前阴影像素的向外法线的任何蓝色/黄色。

但是,如果当前像素位于黄色/蓝色形状由内向外的点内,则我不确定如何继续。可能有一些事情可以忽略比最接近的粉红色顶点更远的蓝色/黄色顶点。

极其粗糙的伪代码:

list yellow_vertex_list = new list 
list blue_vertex_list = new list 
foreach pink vertex p:
    given float dist;
    vertex yellowvertex = new vertex(p+normal*dist)
    vertex bluevertex = new vertex(p-normal*dist)

    yellow_vertex_list.add(yellowvertex)
    blue_vertex_list.add(bluevertex)

create shadow

for each pixel p in shadow:
    foreach vertex v in blue_vertex_list
        if v.normal points towards v: break;
        if v is the wrong side of inside-out region: break;
        if v is closest so far:
            closest_blue = v
            closest_blue_dist = (v-p).magnitude

    foreach vertex v in yellow_vertex_list
        if v.normal points towards v break;
        if v is the wrong side of inside-out region: break;
        if v is closest so far:
            closest_yellow = v
            closest_yellow_dist = (v-p).magnitude


    float d = 1f - closest_blue_dist / (closest_blue_dist + closest_yellow_dist)