首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >地形的Perlin噪声产生

地形的Perlin噪声产生
EN

Stack Overflow用户
提问于 2011-01-20 21:52:13
回答 4查看 54.3K关注 0票数 38

我正在尝试实现一些源代码,我发现在线使用Perlin噪声生成一个高度图。我已经成功地使用noise3函数获得了高度图,第三个坐标是一个随机的“种子”,以允许随机的高度映射。

我的问题是,生成的地形相当单调--我想要山,我要的是起伏的草原。我已经读了一些关于Perlin噪音(主要是这里)的内容。由于我发现源代码的编写显然没有考虑到可读性,而且我对Perlin噪声的概念理解不足,所以我不知道在代码中需要调整什么(幅度和频率?)创造更激烈的地形。

一些关于使用Perlin噪声生成高度图的更多信息,一般Perlin噪声,甚至更多的可解密代码也将受到欢迎。

编辑:I理解Perlin噪声是如何工作的,例如,关于振幅和频率,我只是想知道在我上面链接的代码中要更改哪些变量,这些变量用于这两个方面。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-01-20 21:59:52

Perlin噪声完全由您设置的不同变量控制,即振幅、频率和持续时间。八度的音阶变化不大,但变化不大。在我过去写的代码中,我只是按频率和持续性的数量级来玩,直到我得到了我所需要的。如果需要的话我可以去找我以前的线人。

PerlinNoise.h

代码语言:javascript
运行
复制
#pragma once

class PerlinNoise
{
public:

  // Constructor
    PerlinNoise();
    PerlinNoise(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed);

  // Get Height
    double GetHeight(double x, double y) const;

  // Get
  double Persistence() const { return persistence; }
  double Frequency()   const { return frequency;   }
  double Amplitude()   const { return amplitude;   }
  int    Octaves()     const { return octaves;     }
  int    RandomSeed()  const { return randomseed;  }

  // Set
  void Set(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed);

  void SetPersistence(double _persistence) { persistence = _persistence; }
  void SetFrequency(  double _frequency)   { frequency = _frequency;     }
  void SetAmplitude(  double _amplitude)   { amplitude = _amplitude;     }
  void SetOctaves(    int    _octaves)     { octaves = _octaves;         }
  void SetRandomSeed( int    _randomseed)  { randomseed = _randomseed;   }

private:

    double Total(double i, double j) const;
    double GetValue(double x, double y) const;
    double Interpolate(double x, double y, double a) const;
    double Noise(int x, int y) const;

    double persistence, frequency, amplitude;
    int octaves, randomseed;
};

PerlinNoise.cpp

代码语言:javascript
运行
复制
#include "PerlinNoise.h"

PerlinNoise::PerlinNoise()
{
  persistence = 0;
  frequency = 0;
  amplitude  = 0;
  octaves = 0;
  randomseed = 0;
}

PerlinNoise::PerlinNoise(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed)
{
  persistence = _persistence;
  frequency = _frequency;
  amplitude  = _amplitude;
  octaves = _octaves;
  randomseed = 2 + _randomseed * _randomseed;
}

void PerlinNoise::Set(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed)
{
  persistence = _persistence;
  frequency = _frequency;
  amplitude  = _amplitude;
  octaves = _octaves;
  randomseed = 2 + _randomseed * _randomseed;
}

double PerlinNoise::GetHeight(double x, double y) const
{
  return amplitude * Total(x, y);
}

double PerlinNoise::Total(double i, double j) const
{
    //properties of one octave (changing each loop)
    double t = 0.0f;
    double _amplitude = 1;
    double freq = frequency;

    for(int k = 0; k < octaves; k++) 
    {
        t += GetValue(j * freq + randomseed, i * freq + randomseed) * _amplitude;
        _amplitude *= persistence;
        freq *= 2;
    }

    return t;
}

double PerlinNoise::GetValue(double x, double y) const
{
    int Xint = (int)x;
    int Yint = (int)y;
    double Xfrac = x - Xint;
    double Yfrac = y - Yint;

  //noise values
  double n01 = Noise(Xint-1, Yint-1);
  double n02 = Noise(Xint+1, Yint-1);
  double n03 = Noise(Xint-1, Yint+1);
  double n04 = Noise(Xint+1, Yint+1);
  double n05 = Noise(Xint-1, Yint);
  double n06 = Noise(Xint+1, Yint);
  double n07 = Noise(Xint, Yint-1);
  double n08 = Noise(Xint, Yint+1);
  double n09 = Noise(Xint, Yint);

  double n12 = Noise(Xint+2, Yint-1);
  double n14 = Noise(Xint+2, Yint+1);
  double n16 = Noise(Xint+2, Yint);

  double n23 = Noise(Xint-1, Yint+2);
  double n24 = Noise(Xint+1, Yint+2);
  double n28 = Noise(Xint, Yint+2);

  double n34 = Noise(Xint+2, Yint+2);

    //find the noise values of the four corners
    double x0y0 = 0.0625*(n01+n02+n03+n04) + 0.125*(n05+n06+n07+n08) + 0.25*(n09);  
    double x1y0 = 0.0625*(n07+n12+n08+n14) + 0.125*(n09+n16+n02+n04) + 0.25*(n06);  
    double x0y1 = 0.0625*(n05+n06+n23+n24) + 0.125*(n03+n04+n09+n28) + 0.25*(n08);  
    double x1y1 = 0.0625*(n09+n16+n28+n34) + 0.125*(n08+n14+n06+n24) + 0.25*(n04);  

    //interpolate between those values according to the x and y fractions
    double v1 = Interpolate(x0y0, x1y0, Xfrac); //interpolate in x direction (y)
    double v2 = Interpolate(x0y1, x1y1, Xfrac); //interpolate in x direction (y+1)
    double fin = Interpolate(v1, v2, Yfrac);  //interpolate in y direction

    return fin;
}

double PerlinNoise::Interpolate(double x, double y, double a) const
{
    double negA = 1.0 - a;
  double negASqr = negA * negA;
    double fac1 = 3.0 * (negASqr) - 2.0 * (negASqr * negA);
  double aSqr = a * a;
    double fac2 = 3.0 * aSqr - 2.0 * (aSqr * a);

    return x * fac1 + y * fac2; //add the weighted factors
}

double PerlinNoise::Noise(int x, int y) const
{
    int n = x + y * 57;
    n = (n << 13) ^ n;
  int t = (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff;
    return 1.0 - double(t) * 0.931322574615478515625e-9;/// 1073741824.0);
}
票数 55
EN

Stack Overflow用户

发布于 2012-09-27 18:33:36

一位朋友刚刚把我和这个问题联系起来,我想我应该试着澄清一些在公认的答案中没有提到的事情。

Elias的有趣和有用的文章使用的是“值噪声”而不是"Perlin噪声“。值噪声涉及随机点的曲线拟合.梯度噪声( Perlin噪声是其中的一个主要例子)创建了一个0-值点的格,并给每个点一个随机梯度。他们经常互相混淆!

噪声

其次,使用第三个值作为种子是昂贵的。如果你想要随机地形,考虑把你的原点翻译成随机的数量。3D调用比2D调用要昂贵得多(例如,更喜欢getNoise2D(x + XSEED, y + YSEED)而不是getNoise3D(x, y, ZSEED))。假设z值保持不变,您所做的就是使用z值来选择特定的2D噪声片段。

第三,直线函数调用将返回的值是相当平滑和滚动的整体,不像真实地形那样崎岖,因为它的随机性仅限于一个频率。为了使地形更加粗糙,一种很好的方法是把在不同频率的噪声空间中进行的多次呼叫加在一起,通常设置一个“分形”值。

因此,例如,求和noise(x, y) + (1/2)(noise(x*2, y*2) + (1/4)(noise(x*4, y*4).

结果的和可能经常超出-1到1的范围,所以在这些值有用之前,您必须对结果进行规范化。我想建议设置一个系列,保证保持在-1,1,例如,通过累进加权取决于你使用多少‘八度’。(但我不知道这是否真的是最有效的方法。)

有四个八度的例子:(1/15)(noise(x, y) + (2/15)(noise(2x, 2y) + (4/15)(noise(4x, 4y) + (8/15)(noise(8x, 8y)

第四,当将结果从-1到1映射到更多地使用颜色值或颜色映射(0 ~ 1)的规范化时,Ken描述了两种算法。其中一个被命名为“平滑”,其中映射的值由一个简单的翻译算法操作:

代码语言:javascript
运行
复制
f(x) = (x + 1) / 2

另一个被命名为“湍流”,其中映射的值计算如下:

代码语言:javascript
运行
复制
f(x) = | x |;

对于前者,得到的值将在颜色范围内,稀疏的人口在极端范围内。对于后者,生成的值将在颜色范围或颜色地图的一端“折叠”。这种折叠将使地形角脊在褶皱点,而不是顺利滚动。(这假设是将八度和保持在-1到1之间,并且如果使用自定义颜色映射,则颜色范围在地图过程中进展顺利。但是,这些条件都不是“必需的”,而且可以用来进行有趣的效果。)

我正在研制一个SimplexNoise视觉器.SiVi:一种基于Java的二维梯度噪声可视化器] .[编辑:现在在GitHub: GitHub.作为Java项目。可视化工具的第一稿可以找到.编辑:我正在删除一个指向java-gaming.org旧站点的死链接。该站点已迁移到jvm.gaming.org。如果您去玩jvm游戏,请注意,对SiVi的旧引用也有死链接。

关于SimplexNoise如何工作的伟大文章(以及Perlin渐变背景):http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf

斯特凡·古斯塔夫森在这方面做得很好!

票数 21
EN

Stack Overflow用户

发布于 2011-01-20 21:56:00

振幅控制地形的高低,流动的频率,低频更流动。

所以,如果你想要一个参差不齐的山地景观,你需要两者兼而有之。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4753055

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档