Partage

ZNoise

Bibliotheque de bruits pour la génération procedurale

30 décembre 2011 à 14:13:19

ZNoise


Qu'est ce qu'une bibliothèque de bruits ?



C'est un ensemble de fonctions mathématiques qui permettent de générer pour chaque point de l'espace une valeur de bruit présentant un côté aléatoire et cohérent. Ce module ne génère pas d'images en lui même, il permet juste de donner une valeur a des coordonnes.

Contrairement a une simple fonction aléatoire (bruit blanc), ces fonctions génèrent des motifs "doux" dont certains paramètres sont réglables.

Voici quelques exemples d'images réalisées avec cette bibliothèque (la partie gestion/enregistrement des images est assuree par la SFML) :

Image utilisateurImage utilisateurImage utilisateurImage utilisateur

La bibliothèque a été codée pour être simple à utiliser et très performante. Elle comporte deux types de fonctions différentes :

  • Bruits (Perlin, Simplex, Worley) de 2 dimensions a 4 dimensions
  • Mixers (Melangeurs de bruits) : FBM, HybridMultifractal

Perlin(2,3 et 4D) :
Image utilisateur


Simplex(2,3 et 4D) :
Image utilisateur


Cell Noise(3D) :

Les bruits complexes suivants :
  • Fractionnal Brownian Motion noise(2D et 3D)
  • Hybrid Multifractal Noise(2D et 3D)

Site web

github.com/Overdrivr/Znoise

Gallerie


Image utilisateur
Image utilisateur
Image utilisateur
Image utilisateur
Image utilisateur

-
Edité par OveRdrivR 11 novembre 2015 à 0:14:07

3 janvier 2012 à 13:15:05

Un petit up pour montrer quelques exemples d'applications :

Génération d'un ciel étoilé :
Image utilisateur

Génération d'une image de planète (WIP)
Image utilisateur

Ces deux images ont été automatiquement créées par le programme, je n'ai utilisé aucun logiciel de dessin pour les retoucher (je suis une bille en dessin de toute façon)
3 janvier 2012 à 13:50:17

Très bon travail continu comme ca !
Dev Blog ; Deep Learning R&D aws.amazon.com
3 janvier 2012 à 18:14:30

Projet très intéressant, je m'en servirais certainement ! Beau travail !
3 janvier 2012 à 19:09:46

Merci à vous, ça motive ! Les sources pour le générateur d'images seront disponibles d'ici deux semaines, je sais pas encore si j'utiliserais seulement la sfml ou alors un système de renderer, à voir...
4 janvier 2012 à 4:59:20

C'est incroyable!¡! Je t'encourage à continuer. Ce projet est extrèmement intérressant.
L'être humain, contrairement aux geeks qui ne sont de toute façon pas des êtres humains, est un animal social taillé pour vivre en "meute".
5 janvier 2012 à 19:07:58

Je ne code pas en C++ ni en C, mais je sais que c'est assez difficile, et te félicite donc !
Ne lâche pas l'affaire, ta librairie est superbe (ou le sera).
Je vous ai aidé ? Appuyez sur le bouton "Ce message est utile", avec le pouce levé vers le haut !  (en bas à gauche de mon message)
5 janvier 2012 à 19:29:07

Merci à vous, un Wiki est disponible, encore un peu maigre et en anglais, mais ça s'enrichira au fur et à mesure !
5 janvier 2012 à 21:43:51

Salut, juste pour remercier l'auteur de ce sujet. Voici ce que l'on est capable de faire en moins de 20 lignes de codes avec ça :




Image utilisateur
5 janvier 2012 à 23:07:11

Et surtout 4 lignes d'appel à la librairie :D
6 janvier 2012 à 18:46:07

Citation : OveRdrivR

Merci à vous, un Wiki est disponible, encore un peu maigre et en anglais, mais ça s'enrichira au fur et à mesure !



Je pense que tu fais une petite erreur, tu es sur un forum français, des français ont peut être envie d'utiliser ta librairie sans traduire le "tutoriel", pour la version anglaise ça peut attendre ;)
Je vous ai aidé ? Appuyez sur le bouton "Ce message est utile", avec le pouce levé vers le haut !  (en bas à gauche de mon message)
6 janvier 2012 à 20:18:59

Non, les sources sont (normalement) commentées en anglais, les infos de commit en anglais, les méthodes/classes etc sont des noms anglais, je me vois mal faire ça en français. Toute librairie digne de ce nom se soit d'avoir un wiki en anglais...

Mais pour les anglophobes désirant utiliser la librairie, je le dis et le répète, vous pouvez me contacter par mp.
16 janvier 2012 à 14:13:42

J'ai une question : Pourquoi ne pas avoir utilisé le générateur aléatoire de base ?
Le mieux serait de prendre celui de la norme C++11 (qui est plus ou moins celui de Boost) ; du coup tu n'aurait pas de problème pour générer ta loi normale.

Une autre remarque, pourquoi n'avoir fais qu'une seule classe ? Ça fais un gros morceaux non ?
16 janvier 2012 à 14:34:15

A vrai dire il n'y a aucune raison particulière, j'avais entendu il y a très longtemps qu'exécuter plusieurs fois srand() dans un programme pour changer la racine n'était pas une bonne chose, ce qui est sûrement faux, et un peu inconsciemment j'ai mis ce générateur. :p

Je connaissais pas tout ces générateurs du C++11, c'est bon à savoir ! La loi normale était de toute façon foirée, elle va dégager. J'ai pas besoin de la loi normale dans le fonctionnement interne de la classe.

Sinon la classe est un peu grosse, mais n'en avoir qu'une facilite l'utilisation, et certaines choses sont partagées entre plusieurs méthodes pour optimiser la conso mémoire et cpu. En fait je me pose cette question depuis un moment, c'est pas définitif, ça viendra peut être même à changer.



Sinon en ce moment, je bosse en parallèle sur une appli Qt qui permettrait de designer ses bruits dans une GUI. L'interface serait semblable au génial node editor de blender. Il sera aussi possible d'exporter le réseau de nodes dans un fichier, et d'utiliser simplement le fichier dans ses programmes C++ (via une classe spéciale qui reconstruira le bruit avec le fichier). Ca devrait définitivement rendre les choses simples pour tout le monde :D
16 janvier 2012 à 15:33:10

Petite question: comment tu as fait pour que les images générées soient tileable ? (les pixels gauches correspondent aux pixels droits, de même pour haut et bas)
Parce que ça fait des semaines que j'ai fait un code pour parer ce problème du Perlin Noise et c'est plutôt moche, et je trouve pas comment faire mieux..
16 janvier 2012 à 16:23:28

En fait les images sont pas tileables, mais à vrai dire tu n'en as pas besoin. L'astuce, c'est de prendre la valeur du bruit en utilisant les coordonnées absolues du pixel comme paramètre pour perlin (et pas la valeur relative, cad située par rapport à au point en haut à gauche du tile). Exemple : 3 tiles alignés horizontalement, chacun fait 50 pixels :

Image utilisateur

Pour chaque pixel, tu vas chercher le bruit aux coordonnées de l'écran, pas du tile. Si tu utilises des coordonnées relative au tile, il te suffit de faire :

Get2DPerlinNoiseValue(xpixel+xtile*taille_tile_x , ypixel+ypixel*taille_tile_y)


avec xpixel, coordonnées du pixel par rapport au tile
xtile la position du tile
et taille_tile, sa taille
16 janvier 2012 à 19:04:07

Citation : OveRdrivR

A vrai dire il n'y a aucune raison particulière, j'avais entendu il y a très longtemps qu'exécuter plusieurs fois srand() dans un programme pour changer la racine n'était pas une bonne chose, ce qui est sûrement faux, et un peu inconsciemment j'ai mis ce générateur. :p


Utiliser srand plusieurs fois dans un programme ne pose pas de problème en soi. Il n'a toutefois pas l'usage escompté par les débutants. srand() sert à définir la graine aléatoire du programme. Ceci peut être utile afin de rejouer une séquence sauvegardée par exemple. Si on souhaite un rand réellement aléatoire, la seule chose qui ne soit pas prévisible par l'ordinateur, c'est la seconde à laquelle on lance le programme. Ainsi, on est quasi assuré dans le cadre d'une utilisation normale du programme qu'il sera initialisé différemment à chaque fois. C'est pourquoi, faire srand(time(NULL)); plusieurs fois par seconde est une aberration. Toutefois, il est nécessaire de faire au moins un srand() avant de se servir de rand() puisque l'aléatoire est initialisé avec la même graine à chaque lancement, puis modifié par srand.
16 janvier 2012 à 19:13:59

Yep le pire c'est que je savais déjà ça, je devais pas être très clair au moment où j'ai codé ça haha
2 février 2012 à 14:32:17

Bel effort !

Je retiens au cas où j'en aurais besoin pour un futur projet...

Bon courage pour la suite.
Anonyme
2 février 2012 à 16:06:16

Bonjour,

Très beau boulot.

Petite question : comment sont générés les nombres aléatoires ? Comment simules-tu les lois exponentielles et normales ?
(je me doute que pour l'exponentielle tu utilises la fonction de répartition réciproque appliquée à une distribution uniforme, mais pour la normale ? Box-Muller ?)
2 février 2012 à 16:31:17

Vraiment superbe cette librairie, elle a dut te prendre un temps. Mais quand on voit le résultat ça vaut le coup vraiment, bravo !
2 février 2012 à 18:34:00

Merci à tous, ça fait plaisir ! le plus dur n'était pas vraiment de coder mais de comprendre quoi coder...

Pour les nombres aléatoires selon la loi uniforme, j'utilises un bête générateur congruentiel :


int NoiseGenerator::GetUniformRandomValue()
{
    Ulast = Ua*Uprevious + Uc%Um;
    Uprevious = Ulast;
    return Ulast;
}

//Avec comme valeurs :
Ua = 16807;
Uc = 0;
Um = 2147483647;
//La première valeur de Uprevious est la racine, choisie par l'utilisateur


j'aurais pu utiliser la biblio standard, mais j'ai testé ce code qui marche du tonnerre alors je l'ai laissé.

Pour la loi normale je m'était basé sur l'algo de ziggurat, en fait c'est une approximation de loi normale, mais mon implémentation était un peu (beaucoup) foirée, et vu que c++11 intègre la génération de nombres aléatoires selon la loi normale, poisson, etc, je vais virer cette implémentation et utiliser la bibliothèque standard. Et sinon pour l'exponentielle je ne l'ai jamais implémentée, désolé si j'ai dit ça.

Je bosse toujours sur un éditeur de nodes pour faciliter la conception de bruits composites, par contre ne maitrisant pas suffisamment Qt, j'ai un peu du mal à créer les widgets personnalisés, mais ça va venir. Si certains ont déjà tenté ou même créer les widgets nécessaires je suis plus que preneur, car franchement coder de la gui me casse vraiment les pieds...

Ah et bien sûr si certains veulent rajouter de la génération procédurale dans leurs projets, c'est dans la plupart des cas très simples, n'hésitez pas à me mp.
Anonyme
2 février 2012 à 18:40:25

J'ai mal lu pour la loi uniforme.
Ceci dit, tu peux la générer très facilement :
-ln(1+u) où u suit une loi uniforme, d'après le théorème de simulation. Sachant que 1+u a même loi que u par théorème des moments (ou simple transformation linéaire), -ln(u) suit une loi exponentielle.

Pour la loi normale, si ça t'intéresse de l'implémenter, ne serait-ce que pour le challenge, Box-Muller est une très bonne méthode.
A ce propos j'explique au travers d'un exercice toute la procédure pour justifier cette méthode : http://sciences.siteduzero.com/forum-8 [...] x-muller.html
D'ailleurs tu as besoin de générer une loi exponentielle pour générer une loi normale avec cette méthode. :lol:
7 avril 2012 à 23:48:15

Les tutos sont disponibles en français dans le wiki (c'est pas trop tôt :p )
https://github.com/Overdrivr/ZNoise/wiki

Quand j'aurais un peu de temps je coderai un compositeur de bruits en processing, ainsi qu'une nouvelle architecture pour znoise, plus adaptée aux bruits composites.
8 avril 2012 à 22:38:29

Un grand merci à l'auteur de cette bibliothèque vraiment excellente !
16 avril 2012 à 14:31:10

Salut !

Je trouve ta bibliothèque assez sympathique d’après les images, et je serais intéressé par le code qu’il y a derrière une des images que tu présentes : le ciel étoilé.

Je m’intéresse pas mal à la génération procédurale, et je pense que je vais utiliser ta bibliothèque (ou en tout cas m’en inspirer) pour un de mes projets ;) .
16 avril 2012 à 22:12:08

J'continue ma ptite pub pour ta lib :3

Sinon, tu pourrais mettre à jour le premier post? Parce que comme ça fait un bon bout de temps que tu l'as pas fait, je sais pas si t'as développé le cellnoise (dont la 4D m'intéresse ^^ )
"J'aimerai faire un jeu, mais pas un gros jeu hein. Un petit truc simple du style MMO."
17 avril 2012 à 19:39:56

Bon pour le code, il était vraiment sale, mais j'en ai une version un peu plus minimale, la seule chose en moins c'est que les étoiles ont toutes la même intensité lumineuse ou presque, mais changer ça devrait pas poser problème :

sf::Image gradient;
    gradient.LoadFromFile("spacegradient.png");

    for(int i(0); i < x; i++)
    {
        for(int j(0); j < y; j++)
        {
            const double a(500);
            float Val = nGene->Get2DFBMNoiseValue(i, j, 0.7, 1.5, 3, 235);
            float Val1 = nGene->Get2DPerlinNoiseValue(i, j, 5);

            int Final = ((Val+10)/20)*255;
            int Test = ((Val1+1)/2)*1500;

            if(Test == a || Test == a + 1)
            {
                if(Final < 128)
                {
                    img.SetPixel(i, j, sf::Color(255, 255, 255));
                }
            }
            else
            {
                sf::Color color = gradient.GetPixel(0, Final);
                img.SetPixel(i , j, color);
            }
        }
    }


Et le gradient fait sous inkscape :
Image utilisateur
On dirait que c'est tout noir, mais c'est un gradient bleu vers noir

@Fraggy : Merci beaucoup :D Pourquoi pas un cell noise pour te remercier en effet ? Il me faut juste trouver une fonction de "hash" à peu près correcte, j'ai improvisé ça ce matin (pas réveillé) ouais ben pas génial :
return (float)(((x0 >> 4 | (y0 << 4 ^ (0x07))) ^ (y0 >> 4 | (!z0 & !0x07)) ^ (z0 >> 4 | (!w0 & !0x07)) ^ w0 >> 4 | (!x0 & !0x07)) & 65535)/32768.f - 1;

Les fonctions de hash, ça s'improvise pas. Mais ça va plus tarder
18 avril 2012 à 9:43:26

Ok, merci pour le code, je pensais que ce serait plus compliqué ^^ . En tout cas, ta bibliothèque a l’air bien sympathique ;) . Par contre, je n’ai pas encore eu le temps d’essayer, mais ça mets du temps à générer une image ? C’est envisageable de regénérer en temps réel l’image entière (à 60fps on va dire) ? (C’est juste pour avoir un ordre d’idée, je ne pense pas que je ferai ça :p )

PS : Pour ta fonction de hash, je crois que tu as confondu l’opérateur "!" qui est le non booléen et l’opérateur "~" qui correspond à la négation bit à bit. Peut-être parce que comme tu l’as dit t’étais pas trop réveillé :p .

ZNoise

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
  • Editeur
  • Markdown