Comment créer un bruit solide pouvant être carrelé pour la génération de cartes?

16

Hé les gars, j'essaie de comprendre comment générer des fractales à carreler dans le code (pour les cartes de jeu, mais ce n'est pas pertinent ) J'ai essayé de modifier le plug-in Solid Noise livré avec GIMP (avec ma compréhension extrêmement limitée de la façon dont le code fonctionne) mais je ne peux pas faire fonctionner le mien correctement.

Mon code modifié jusqu'à présent (Java)

Module de bruit solide de GIMP dont je fonde mon code (C)

Voici ce que j'essaie de réaliser, mais c'est ce que je reçois

Donc, si quelqu'un peut voir ce que j'ai fait de mal ou a une suggestion sur la façon de procéder différemment, je l'apprécierais beaucoup. Merci d'avance. Et si je demande beaucoup de chemin ou si c'est juste un énorme échec dans la vie, je m'excuse.

Nick Badal
la source
essayez d'utiliser l' interpolation bicubique au lieu de bilinéaire? Je n'ai aucune idée si c'est votre problème, mais ça A l'air comme ça.
Stephen Furlani

Réponses:

4

Je ne suis pas exactement votre code, mais voici une description simplifiée de l'algorithme qui produira à peu près l'effet (basé sur l'image que vous avez publiée).

L'explication suivante n'est pas la version super optimisée, mais celle qui est conceptuellement claire (j'espère). Une fois que vous l'avez lancé, vous pouvez l'optimiser (de manière assez drastique, en fait).

  1. Générez n couches de bruit aléatoire uniforme (juste des pixels en niveaux de gris aléatoires).
  2. Échantillonnez maintenant chacun de ces éléments en échantillonnant tous les 1, 2, 4, 8, ... 2 ^ (n-1) pixels et en interpolant les pixels intermédiaires. Chaque couche est plus lisse que la précédente.
  3. Maintenant l'échelle de ceux-ci avec un facteur de 1, 2, 4, 8, etc. Chaque couche est plus sombre que la précédente.
  4. Ajoutez tous ces éléments ensemble.
  5. Normalisez en divisant chaque pixel par (1 + 2 + 4 + 8 + ... 2 ^ (n-1)).

L'étape difficile est l'étape d'échantillonnage et d'interpolation. Supposons que nous soyons dans la couche en sautant l'échantillonnage chaque m-ème pixel. Voici l'idée de base pour m> 1 (si m est 1, nous utilisons l'image telle quelle):

for each pixel x and y
   left_sample_coord = m *(x / m) //(integer division, automatically truncated)
   right_sample_coord = (left_sample_point + m) % image_width
   top_sample_point = m*(y / m) 
   bottom_sample_coord = (top_sample_point + m) % image_height

   horizontal_weight = (x - left_sample_point) / (m - 1)
   vertical_weight = (y - top_sample_point) / (m - 1)

   sample_top_left = image(left_sample_coord, top_sample_point)
   //and the same for the other four corners

   //now combine the top two points
   top_interpolate = sample_top_left * horizontal_weight + sample_top_right * (1-horizontal_weight)

  //now combine the bottom two points
  bottom_interpolate = sample_bottom_left * horizontal_weight + sample_bottom_right * (1-horizontal_weight)

  //and combine these two last obtained values

  smooth_noise(x, y) = top_interpolate * vertical_weight  + bottom_interpolate * (1 - vertical_weight)

Quelques conseils:

  • Le résultat de l'algorithme ci-dessus peut sembler un peu délavé. Vous pouvez réduire cet effet en utilisant le même calque de bruit pour tous les calques, ou améliorer le contraste de l'image par la suite.
  • L'algorithme ci-dessus utilise une interpolation linéaire, mais une interpolation en cosinus (faire une recherche) donne de bien meilleurs résultats.
  • Permet de regarder vos couches séparément pendant toutes les parties de l'algorithme. Cela vous aidera à éliminer rapidement les bogues.
Herman Tulleken
la source
3

Il semble que ma pâte originale ait expiré d'une manière ou d'une autre, donc je n'ai aucun moyen de comparer mon code non fonctionnel, mais sur mon jeu actuel, j'ai parcouru et traduit à nouveau le code GIMP en java et cela semble bien fonctionner maintenant.

Si quelqu'un prévoit d'utiliser ce code, je recommanderais de modifier le constructeur pour modifier les paramètres de réglage (détail et taille) afin que vous puissiez le faire fonctionner comme vous le souhaitez. EDIT: J'ai réalisé que ma question initiale était de le rendre tuilable, alors n'oubliez pas de mettre tilable sur true!

Code: http://pastebin.com/KsfZ99Xa

Exemple: exemple de générateur Perlin

Nick Badal
la source
2

Je viens de parcourir les versions Java et C et j'ai remarqué une légère différence dans la façon dont vous utilisez la fonction de bruit. Voici le vôtre:

int val = Math.abs((int) Math.floor(255.0 * noise(((double)col/(double)width), ((double)row/(double)height))));

Code C:

val = (guchar) floor (255.0 * noise ((col - xoffset) / width,

                                           (row - yoffset) / height));

Pourquoi avez-vous choisi de ne pas soustraire le décalage? (col - xoffset) et (ligne - yoffset)

Je me demandais juste. Je n'ai pas le temps de faire une analyse complète du code.

J'espère que cela t'aides.

Cloueur
la source
xoffset et yoffset doivent calculer la manière dont GIMP divise les images en grilles, mais mon programme fonctionne tous sur une seule tuile donc les décalages x et y seraient de 0
Nick Badal
2

Je ne sais pas si cela pourrait aider, mais l'astuce suivante a fonctionné pour moi:

http://www.gamedev.net/blog/33/entry-2138456-seamless-noise/

Ce boursier utilise une fonction de bruit 4d et fournit simplement des valeurs xy de deux cercles en tant que valeurs xyzw pour le bruit 4d. Le résultat est parfait en boucle.

Voici l'idée (simplifiée) d'une image 1000 * 1000:

for(i = 0;i < 1000; i++){

  for(j = 0; j < 1000; j++){

    nx = cos((i/1000) * 2 * PI);
    ny = cos((j/1000) * 2 * PI);
    nz = sin((i/1000) * 2 * PI);
    nw = sin((j/1000) * 2 * PI);

    looped_noise = noise_4D( nx, ny, nz, nw, octaves, persistence, lacunarity, blah...);
    noise_buffer[(i*1000)+j] = looped_noise;

  }
}
Ok
la source
1

Je vous recommande d'utiliser l' algorithme du diamant carré , également connu sous le nom de fractale au plasma ou fractale à déplacement médian aléatoire. En utilisant cet algorithme, il est très facile de contraindre les bords à avoir les mêmes valeurs. Lorsque vous générez une valeur pour une arête, copiez-la sur l'arête correspondante de l'autre côté. Cela donne une carte parfaitement carrelée.

drxzcl
la source
0

Il y a un excellent article sur la génération de bruit ici . Ce n'est pas du bruit Perlin comme le prétend l'article (c'est du bruit rose en fait), mais c'est toujours incroyablement utile pour comprendre comment les images de bruit sont générées.

Donc, pour répondre à votre question: pour créer une image de bruit à carreler, il vous suffit de conserver la "mosaïque" tout au long de la génération. Autrement dit, lorsque le bruit est lissé, vous le lissez comme s'il se répétait à l'infini dans toutes les directions - en mosaïque.

Ça ne fait rien
la source
0

D'après la capture d'écran, je suppose que seules les "grandes" couches sont générées, c'est pourquoi le bruit semble trop régulier et manque de détails.

Cela peut sembler stupide, mais avez-vous essayé d'augmenter la variable "détail" (ligne 16)? Dans votre code, il est défini sur 1, ce qui signifie que l'algorithme ne générera que deux couches de détails avant de s'arrêter. Essayez de l'augmenter à quelque chose comme 8.

Utilisateur non trouvé
la source
0

Vous devriez également jeter un coup d'œil à Simplex Noise , qui a été développé par Ken Perlin pour corriger certaines des lacunes du bruit Perlin.

J'ai travaillé sur une implémentation de Simplex Noise pour un jeu C ++. Il prend en charge le bruit multi-octave 1D / 2D / 3D / 4D. À l'heure actuelle, la seule texture intégrée est le marbre, mais vous pouvez facilement en ajouter plus:

(http://code.google.com/p/battlestar-tux/source/browse/trunk/src/lib/procedural/)

i_grok
la source