Unity - 如何创建圆形渐变?

Unity - How to create circular gradient?

我需要一点帮助,我正在尝试使用 Unity 创建一个岛生成器。

但是我不知道如何使圆形脱落 map.But 相反,我设法创建了一个更像是盒形岛的岛。

这就是我正在做的事情:

  1. 我正在使用 Perlin 噪声生成高度图
  2. 我将生成 FallOff 贴图并从 Perlin 噪声中减去它
  3. 岛已生成,但不是圆形 岛状 hasbox 形状

我想创建这个

这是我的 Perlin 噪声函数

public float[,] GenerateNoise(int mapSize,int octaves, string seed, float noiseScale, float persistence, float lacunarity, Vector2 offset)
    {
        if (noiseScale <= 0)
        {
            noiseScale = 0.0001f;
        }
        
        float halfWidth = mapSize / 2f;
        float halfHeight = mapSize / 2f;
        
        float[,] noiseMap = new float[mapSize + 1, mapSize + 1];
        System.Random rand = new System.Random(seed.GetHashCode());

        //Octaves offset
        Vector2[] octavesOffset = new Vector2[octaves];
        for (int i = 0; i < octaves; i++)
        {
            float offset_X = rand.Next(-100000, 100000) + offset.x;
            float offset_Y = rand.Next(-100000, 100000) + offset.y;
            octavesOffset[i] = new Vector2(offset_X / mapSize, offset_Y / mapSize);
        }

        for (int x = 0; x < mapSize; x++)
        {
            for (int y = 0; y < mapSize; y++)
            {
                float amplitude = 1;
                float frequency = 1;
                float noiseHeight = 0;
                float superpositionCompensation = 0;


                for (int i = 0; i < octaves; i++)
                {
                    float sampleX = (x - halfWidth) / noiseScale * frequency + octavesOffset[i].x;
                    float sampleY = (y - halfHeight) / noiseScale * frequency + octavesOffset[i].y;

                    float perlinValue = Mathf.PerlinNoise(sampleX, sampleY);
                    noiseHeight += perlinValue * amplitude;
                    noiseHeight -= superpositionCompensation;

                    amplitude *= persistence;
                    frequency *= lacunarity;
                    superpositionCompensation = amplitude / 2;

                }

                noiseMap[x, y] = Mathf.Clamp01(noiseHeight);

            }
        }

        return noiseMap;
    }

这是我的 FallOff 贴图函数

public float[,] GenerateFallOffMap(int mapSize)
{
    float[,] fallOffMap = new float[mapSize , mapSize];

    for (int x = 0; x < mapSize; x++)
    {
        for (int y = 0; y < mapSize; y++)
        {
            int index = x * mapSize + y;
            float fallOff_A = x / (float)mapSize * 2 - 1;
            float fallOff_B = y / (float)mapSize * 2 - 1;

            float value = Mathf.Max(Mathf.Abs(fallOff_A), Mathf.Abs(fallOff_B));
            fallOffMap[x,y] = Evaluate(value);
        }
    }

    return fallOffMap;
}

static float Evaluate(float value)
{
    float a = 3;
    float b = 2.2f;

    return Mathf.Pow(value, a) / (Mathf.Pow(value, a) + Mathf.Pow(b - b * value, a));
}

以距网格中心的距离为参数计算衰减值

/// value - The calculated value to process
/// radius - The distance from center to calculate falloff distance
/// x - The x-coordinate of the value position
/// y - The y-coordinate of the value position
/// cx - The x-coordinate of the center position
/// cy - The y-coordinate of the center position
public float RadialFallOff(float value, float radius, int x, int y, float cx, float cy) 
{
  float dx = cx - x;
  float dy = cy - y;
  float distSqr = dx * dx + dy * dy;
  float radSqr = radius * radius;

  if (distSqr > radSqr) return 0f;
  return value;
}

这将导致 radius 处的硬中断。如果您想沿边缘进行更柔和的过渡,可以使用 innerRadiusouterRadius 来产生羽化效果:

/// value - The calculated value to process
/// innerRadius - The distance from center to start feathering
/// outerRadius - The distance from center to fully fall off
/// x - The x-coordinate of the value position
/// y - The y-coordinate of the value position
/// cx - The x-coordinate of the center position
/// cy - The y-coordinate of the center position
public float FeatheredRadialFallOff(float value, float innerRadius, float outerRadius, int x, int y, float cx, float cy) 
{
  float dx = cx - x;
  float dy = cy - y;
  float distSqr = dx * dx + dy * dy;
  float iRadSqr = innerRadius * innerRadius;
  float oRadSqr = outerRadius * outerRadius;

  if (distSqr >= oRadSqr) return 0f;
  if (distSqr <= iRadSqr) return value;

  float dist = Mathf.Sqr(distSqr);
  float t = Mathf.InverseLerp(innerRadius, outerRadius, dist);
  // Use t with whatever easing you want here, or leave it as is for linear easing
  return value * t;
}

你可以这样使用它:

float value = Mathf.Max(Mathf.Abs(fallOff_A), Mathf.Abs(fallOff_B));
value = Evaluate(value)

fallOffMap[x,y] = RadialFalloff(value, someRadius, x, y, mapSize / 2f, mapSize / 2f);
// or
fallOffMap[x,y] = FeatheredRadialFalloff(value, someInnerRadius, someOuterRadius, x, y, mapSize / 2f, mapSize / 2f);