You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity程序化地形中如何添加Octaves实现自然地貌效果?

Unity程序化地形生成:Octaves八度优化解决尖刺地形问题

我正在为Unity游戏开发程序化地形生成系统,想用Octaves(八度)让地形更接近自然地貌,但尝试添加八度代码后,生成的地形呈尖刺状而非预期效果。现有基础代码用Perlin Noise生成地形,附上当前代码和尝试的八度代码,求解决方法。

当前基础代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
public class MapGenerator : MonoBehaviour
{
    Mesh mesh;
    Vector3[] vertices;
    int[] triangles;

    public int xSize = 20;
    public int zSize = 20;

    void Start()
    {
        mesh = new Mesh();
        GetComponent<MeshFilter>().mesh = mesh;    

        CreateShape();
        UpdateMesh();
    }

    void CreateShape()
    {
        vertices = new Vector3[(xSize + 1) * (zSize + 1)];

        for (int i = 0, z = 0; z <= zSize; z++)
        {
            for (int x = 0; x <= xSize; x++)
            {
                float y = Mathf.PerlinNoise(x * .3f, z * .3f) * 2f;
                vertices[i] = new Vector3(x, y, z);
                
                i++;
            }
        }

        triangles = new int[xSize * zSize * 6];

        int vert = 0;
        int tris = 0;

         for (int z = 0; z < zSize; z++)
         {
            for (int x = 0; x < xSize; x++) 
            {
                triangles[tris + 0] = vert + 0;
                triangles[tris + 1] = vert + xSize + 1;
                triangles[tris + 2] = vert + 1;
                triangles[tris + 3] = vert + 1;
                triangles[tris + 4] = vert + xSize + 1;
                triangles[tris + 5] = vert + xSize + 2;

                vert++;
                tris += 6;
            }

            vert++;
         }
    }

    void UpdateMesh()
    {
        mesh.Clear();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();
    }
}

尝试的八度代码

float[] octaveFrequencies=new float[] {1,1.5f,2,2.5f} ;
float[] octaveAmplitudes=new float[] {1,0.9f,0.7f,0.f} ;
float y=0;
for(int i=0;i<octaveFrequencies.Length;i++)
 y += octaveAmplitudes[i]* Mathf.PerlinNoise(
      octaveFrequencies[i]*x + .3f, 
      octaveFrequencies[i]* z + .3f) * 2f ;

问题分析与解决方法

你的八度代码存在三个核心问题,直接导致地形出现尖刺:

  • 频率缩放逻辑错误:直接用octaveFrequencies[i]*x替代原代码的x*.3f,会让高频率噪声的细节被过度放大,产生尖锐凸起;
  • 振幅配置不合理:振幅总和接近2.6(1+0.9+0.7),再乘以2后y值会远超原有的0-2范围,地形高度失控;最后一个八度振幅为0,完全无效;
  • 噪声偏移处理不当:所有八度共用同一个偏移.3f,导致噪声图案重叠,加剧突兀感。

修正后的八度实现代码

将CreateShape方法中的y值计算部分替换为以下代码:

// 可调整的八度参数,建议做成public变量方便Inspector调试
public int octaveCount = 4;
public float baseScale = 0.3f;
public float amplitudeMultiplier = 0.5f;
public float frequencyMultiplier = 2f;

// 在CreateShape的x/z循环内:
float y = 0;
float amplitude = 1;
float frequency = 1;
float maxPossibleY = 0; // 用于归一化,避免高度失控

// 提前生成随机偏移,避免噪声重复
Vector2[] octaveOffsets = new Vector2[octaveCount];
for (int i = 0; i < octaveCount; i++)
{
    float offsetX = Random.Range(-10000f, 10000f);
    float offsetY = Random.Range(-10000f, 10000f);
    octaveOffsets[i] = new Vector2(offsetX, offsetY);
}

for (int i = 0; i < octaveCount; i++)
{
    float xNoise = x * baseScale * frequency + octaveOffsets[i].x;
    float zNoise = z * baseScale * frequency + octaveOffsets[i].y;
    
    // PerlinNoise返回0-1的值,直接叠加振幅
    y += Mathf.PerlinNoise(xNoise, zNoise) * amplitude;
    
    maxPossibleY += amplitude;
    amplitude *= amplitudeMultiplier;
    frequency *= frequencyMultiplier;
}

// 归一化到0-2的范围,和原代码高度一致
y = (y / maxPossibleY) * 2f;

关键优化点说明

  • 标准八度配置:采用频率翻倍、振幅减半的行业通用规则,高频率的细节噪声会被低振幅弱化,自然融合到低频地形轮廓中;
  • 归一化处理:通过maxPossibleY将叠加后的y值映射到原代码的0-2范围,避免高度失控;
  • 随机偏移:每个八度使用独立的随机偏移,消除噪声重复图案,让地形更自然;
  • 可调试参数:把核心参数设为public,可在Unity编辑器中实时调整八度数量、缩放比例等,快速预览效果。

内容的提问来源于stack exchange,提问作者Smoothbrick578

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 21:15:31