Question

Je suis en train de mettre en œuvre un code source, j'ai trouvé en ligne pour générer une carte de hauteur à l'aide du bruit Perlin. J'ai réussi à obtenir la carte de hauteur à l'aide de la fonction noise3, la troisième coordonnée étant une « graine » au hasard, pour permettre des cartes de hauteur aléatoires.

Mon problème est que le terrain généré est assez terne - Je veux des montagnes et je suis en train de prairies de roulement. Je l'ai fait un peu de lecture sur Perlin Noise (la plupart du temps ) . En raison du code source que j'ai trouvé évidemment pas écrit avec la lisibilité à l'esprit et ma faible emprise sur le concept de bruit de Perlin en général, je ne peux pas comprendre ce que je dois modifier dans le code (amplitude et fréquence?) À créer un terrain plus drastique.

Un peu plus d'informations sur la génération de hauteur cartes à l'aide Perlin Noise, Perlin Noise en général, ou même un code plus déchiffrable serait également bienvenue.

EDIT: Je comprends (genre de) comment fonctionne Perlin Noise, par exemple, par rapport à l'amplitude et la fréquence, je me demandais quelles variables au changement dans le code I liés ci-dessus, qui sont utilisé pour ces deux aspects.

Était-ce utile?

La solution

Perlin bruit est entièrement contrôlé par les différentes variables que vous avez définies, à savoir l'amplitude, la fréquence et la persistance. La quantité de a un peu octaves changement, mais pas beaucoup. Dans le code que je l'ai écrit dans le passé, je viens joué avec l'ordre de grandeur de la fréquence et persistence jusqu'à ce que j'ai obtenu ce que je avais besoin. Je peux essayer de trouver mon ancienne source si nécessaire.

PerlinNoise.h

#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

#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);
}

Autres conseils

Un ami me lié à cette question, et je pensais que je vais essayer et éclaircir une ou deux choses qui ne sont pas abordés dans la réponse acceptée.

article intéressant et utile d'Elias utilisations « bruit de valeur » non « bruit Perlin ». bruit de valeur implique ajustement de la courbe de points aléatoires. bruit de gradient (dont Perlin est un bruit primaire exemple) crée un réseau de points 0-valeur et donne à chacun un gradient aléatoire. Ils sont souvent confondus avec les uns les autres!

http://en.wikipedia.org/wiki/Gradient_noise

En second lieu, en utilisant une 3ème valeur comme une graine est cher. Si vous voulez un terrain aléatoire, envisager de traduire votre origine une quantité aléatoire au lieu. appels 3D vont être plus chers que les appels 2D. Et tout ce que vous faites est d'utiliser la valeur de z pour sélectionner une tranche particulière du bruit 2D.

En troisième lieu, l'appel de fonction droite va renvoyer des valeurs qui sont lisses et assez roulant dans l'ensemble, pas aussi escarpé que le terrain réel, depuis sa est limitée à l'aléatoire une seule fréquence. Pour obtenir un terrain accidenté que, une bonne technique consiste à résumer ensemble des appels multiples que les progrès dans l'espace de bruit à différentes fréquences, généralement défini une valeur « fractale ».

Ainsi, par exemple, somme ensemble noise(x, y) + (1/2)(noise(x*2, y*2) + (1/4)(noise(x*4, y*4) ...

La somme résultante sera probablement souvent en dehors de la plage -1 à 1, de sorte que vous devrez normaliser le résultat avant que les valeurs sont utiles. Je voudrais suggérer la mise en place de la série de facteurs (1, 1/2, 1/4, etc.) de sorte que vous êtes assuré de rester dans [-1, 1] qui peut être fait par pondération progressive en fonction du nombre « » octaves que vous utilisez. (Mais je ne sais pas si cela est vraiment la façon la plus efficace de le faire.)

Exemple de quatre octaves: (1/15)(noise(x, y) + (2/15)(noise(2x, 2y) + (4/15)(noise(4x, 4y) + (8/15)(noise(8x, 8y)

Ensuite, utilisez la normalisation « du bruit turbulent » de la somme et prendre ce qui en fait = |sum| (À savoir, en utilisant la fonction ABS). Cela donnera le terrain précis des crêtes de la vallée angulaire, par opposition à rouler en douceur.

Je travaille sur un Visualiseur de SimplexNoise, espoir d'open source sur GitHub finalement, comme un projet Java. On peut trouver une première ébauche du Visualiseur et exécutée via ce poste à java-gaming.org: http: // www. java-gaming.org/topics/simplex-noise-experiments-towards-procedural-generation/27163/view.html L'accent mis sur le premier projet est plus tutoriel, avec des exemples de code générés (mais ils sont en Java).

Grand article sur la façon dont fonctionne SimplexNoise (et Perlin vs fond dégradé): http://staffwww.itn.liu.se/~stegu/simplexnoise/ simplexnoise.pdf

Stefan Gustavson a fait un très bon travail de tout cela!

contrôle Amplitude comment haut / bas du terrain est, comment la fréquence qui coule est, avec une fréquence inférieure étant plus fluide.

Donc, si vous voulez un paysage de montagne en dents de scie que vous devez à la fois.

Voici un exemple de génération de surface, j'ai écrit il y a un moment à l'aide de JavaScript bruit 3D Perlin. Etant donné que dans une surface voxels sont soit présent ou non je demande simplement un seuil après avoir calculé le cube de bruit Perlin. Dans l'exemple la probabilité de bruit est égale pour toutes les dimensions. Vous pouvez obtenir un paysage plus réaliste lorsque vous augmentez les valeurs aléatoires vers le sol et réduire vers le ciel.

http://kirox.de/test/Surface.html

WebGL doit être activé. Au moment de la rédaction de ce que je recommande d'utiliser Chrome pour une meilleure performance.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top