平滑不同振幅的噪声(第 2 部分)
Smoothing noises with different amplitudes (Part 2)
嗯,我继续这个问题,但没有答案 (),我还有一个问题。
我选择使用形状 () 的 contour/shadow。
此 contour/shadow 比当前路径大。我使用此存储库 (https://github.com/n-yoda/unity-vertex-effects) 重新创建了影子。这工作得很好,除了一个事实。
要知道所有点的高度(通过这个阴影算法得到(Line 13 of ModifiedShadow.cs & Line 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
注意:如果你想知道我用什么来获得不同幅度的噪声:(见第一段代码),看看这个在行动, 查看此存储库
- 绿色背景色代表平均高度为-0.25、振幅为0.3的噪声
- 白色背景颜色表示平均高度为 0、振幅为 0.1 的噪声
- 红色表示1(白色像素对应的噪声的总插值)
- 黑色表示0(绿色像素对应的噪声的总插值)
这就是为什么我们有这个输出:
实际上,我已经尝试比较每个点到中心的距离,但这输出了一个奇怪且意外的结果。
其实,我不知道该尝试什么...
问题在于 lerp 百分比(例如,在您的可视化中从 high/low 或 "red" 到 "black")只是点与中心距离的函数,这除以一个常数(恰好是任何点距中心的最大距离)。这就是为什么它看起来是圆形的。
例如,多边形左侧的中心点可能距中心 300 像素,而右侧的中心点可能距中心 5 像素。两者都需要是红色的,但是以 0 distance from center = red
为基础的两者都不会是红色,而以 min distance from center = red
为基础的只会在右侧有红色。
相关的最小和最大距离将根据点的位置而变化
另一种方法是针对每个点:找到最近的白色像素,并找到最近的绿色像素,(或者,与green/white相邻的最近的阴影像素,例如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;
}
选择以上部分作为解决方案。下面的部分,作为另一个选项提到,结果是不必要的。
如果您无法确定阴影像素是否与 white/green 相邻,这里有一个替代方案,它只需要计算粉红色(原始)轮廓中每个顶点的法线。
通过转到每个粉红色顶点并沿着其法线向外创建外部 "yellow" 顶点。通过转到每个粉红色顶点并按照其法线向内创建内部 "blue" 顶点。
然后,当循环遍历阴影中的每个像素时,循环遍历黄色顶点以获得 "closest to green" 并循环遍历蓝色顶点以获得 "closest to white"。
问题在于,由于您的形状不是完全凸出的,因此这些投影的蓝色和黄色轮廓在某些地方可能会由内而外,因此您需要以某种方式进行处理。我无法确定处理该问题的确切方法,但这是我目前所拥有的:
第一步是忽略任何具有指向当前阴影像素的向外法线的 blues/yellows。
但是,如果当前像素位于 yellow/blue 形状由内向外的点内,我不确定如何继续。可能需要忽略 blue/yellow 个比它们应该更接近最近的粉红色顶点的顶点。
极其粗糙的伪代码:
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)
嗯,我继续这个问题,但没有答案 (
我选择使用形状 (
此 contour/shadow 比当前路径大。我使用此存储库 (https://github.com/n-yoda/unity-vertex-effects) 重新创建了影子。这工作得很好,除了一个事实。
要知道所有点的高度(通过这个阴影算法得到(Line 13 of ModifiedShadow.cs & Line 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
注意:如果你想知道我用什么来获得不同幅度的噪声:
- 绿色背景色代表平均高度为-0.25、振幅为0.3的噪声
- 白色背景颜色表示平均高度为 0、振幅为 0.1 的噪声
- 红色表示1(白色像素对应的噪声的总插值)
- 黑色表示0(绿色像素对应的噪声的总插值)
这就是为什么我们有这个输出:
实际上,我已经尝试比较每个点到中心的距离,但这输出了一个奇怪且意外的结果。
其实,我不知道该尝试什么...
问题在于 lerp 百分比(例如,在您的可视化中从 high/low 或 "red" 到 "black")只是点与中心距离的函数,这除以一个常数(恰好是任何点距中心的最大距离)。这就是为什么它看起来是圆形的。
例如,多边形左侧的中心点可能距中心 300 像素,而右侧的中心点可能距中心 5 像素。两者都需要是红色的,但是以 0 distance from center = red
为基础的两者都不会是红色,而以 min distance from center = red
为基础的只会在右侧有红色。
相关的最小和最大距离将根据点的位置而变化
另一种方法是针对每个点:找到最近的白色像素,并找到最近的绿色像素,(或者,与green/white相邻的最近的阴影像素,例如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;
}
选择以上部分作为解决方案。下面的部分,作为另一个选项提到,结果是不必要的。
如果您无法确定阴影像素是否与 white/green 相邻,这里有一个替代方案,它只需要计算粉红色(原始)轮廓中每个顶点的法线。
通过转到每个粉红色顶点并沿着其法线向外创建外部 "yellow" 顶点。通过转到每个粉红色顶点并按照其法线向内创建内部 "blue" 顶点。
然后,当循环遍历阴影中的每个像素时,循环遍历黄色顶点以获得 "closest to green" 并循环遍历蓝色顶点以获得 "closest to white"。
问题在于,由于您的形状不是完全凸出的,因此这些投影的蓝色和黄色轮廓在某些地方可能会由内而外,因此您需要以某种方式进行处理。我无法确定处理该问题的确切方法,但这是我目前所拥有的:
第一步是忽略任何具有指向当前阴影像素的向外法线的 blues/yellows。
但是,如果当前像素位于 yellow/blue 形状由内向外的点内,我不确定如何继续。可能需要忽略 blue/yellow 个比它们应该更接近最近的粉红色顶点的顶点。
极其粗糙的伪代码:
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)