Introduction

Voilà bien un problème que tous les modeleurs procéduraux rencontrerons tôt ou tard sur des setups : éviter les interférences sur un système de copie d’objets aléatoires.

La cas classique étant les stores sur les façades d’un bâtiment :

Bien souvent on se retrouve désemparé face à ce souci et on finit par le contourner.
La plupart des solutions simple offre toutes le désavantage de générer « des patterns » que l’oeil humain repère très facilement.
Par exemple la solution classique qui consiste à interdire la copie du même objet sur « la case suivante » crée une sorte de pattern en forme d’escargot ou d’escalier qui se repère aisément.

Donc cette article je vous propose une solution pour faire « un vrai » système de détection d’interférences qui garantit l’absence de pattern et qui reste aléatoire à 100%

Le coeur du système se base sur deux principes :

  • Le Node « Intersection Analysis » qui génère des points lorsque deux géométries sont en interférence.
  • Une boucle « Foreach » dont nous allons modifier le comportement par défaut pour faire en sorte d’avoir un contrôle sur le renvoi des itérations dans la boucle.
    Lorsque interférences il y a, nous allons indiquer à Houdini de copier un Null object au lieu de l’itération qui génère des interférences.

ATTENTION, ce système fonctionne bien pour quelques dizaines à quelques centaines d’objets. Au dela il sera trop gourmand en ressource : le Node « Intersection Analysis » coute cher, un peu plus de 10ms sur ma machine. Pour une boucle de 100 objets il doit faire 682 cook… plus tout le reste du setup.
Vous pouvez donc utiliser ce système sur des bâtiments par exemple, mais inutilisable sur des scatters de landscape, il faudra alors se tourner sur des setups en VEX.

Configuration de la boucle foreach

Voila mon setup de départ, une grid de 10×10 avec 10 Rows et 10 Colons, un « Point Jitter » en x et z pour mettre un peu d’bordel, un « Attribue Randomize » sur pscale pour générer de l’aléatoire sur les objets à copier :

Puis, on pose une boucle « Foreach Points », une sphère, un « Copy to Points » :

Ensuite, c’est là qu’il faut suivre un peu..

Par defaut, une boucle renvoi automatiquement chaque itérations puis les merges sur le « Foreach End ». Très pratique, sauf que dans notre cas on ne veut pas de ce comportement puisqu’on veut écarter les itérations qui génèrent des interférences. Let’s go :

  • On commence par dupliquer le Node « Foreach begin » (alt Clic & Drag)
  • Dans ce nouveau Node « foreach_begin2 » on règle sa méthode sur « Fetch feedback » autrement dit « choppe les retours » quoi… C’est donc par ce Node que les itérations vont revenir dans la boucle.
  • Sur le Node « Foreach End », régler le Gather Method sur « Feedback Each iteration » autrement dit, renvoyer les iterations (au début de la boucle).
  • Si vous suivait la méthode, à ce moment du setup, la boucle à perdu sa capacité à merger toutes les itérations. On va reproduire cette capacité en posant un node de « Merge » avec en Input le « foreach_begin2 », le « Copy to Points » et en output le « Foreach End ».

Pour bien comprendre, avant de continuer, voilà maintenant le chemin d’une itération dans la boucle :

Voila, notre boucle est prête à gérer le contrôle du renvoi des itérations en fonction de si elle génère une interférence…. ou pas.

Une étape optionnel : Dans le Node « Foreach End », vous pouvez régler le Default Block Path sur le second Foreach Begin. Cela fonctionne sans y toucher tant qu’on ne compile pas…

Système de contrôle des interférences.

Ici rien de très complexe, on pose un Node « Intersection Analysis » avec en input le « Copy to Points » et le « Foreach Begin 2 », on pose un null object correctement nommé pour bien identifié la système de détection d’intersections :

Comme on peut le voir, le Node « Intersection Analysis » génére des points à l’intersection de chaque géométrie.

Système d’élimination des itérations générant des interférences

Avant d’attaque en détail, explication du principe : Après le Copy to Points, qui est le Node qui nous envoi en premier dans la boule chaque itérations, nous allons placer un « Switch Node ».
Sur la seconde entrée de ce « Switch » (donc d’index 1 c’est important) nous allons connecter un Null Object qui va nous servir à copier un objet None à la place de nos objets normaux sous une certaine condition.
Cette condition étant la présence de point(s) sur le Node « OUT_Intersect ». En effet, si il y des points sur ce Node, c’est que l’itération en cours génère une interférence et on souhaite donc l’éliminer. Let’s go :

  • On commence par poser un « Switch » après le « Copy to Point ». L’output va vers le Node « Foreach End »
  • Puis sur la seconde entrée de ce « Switch Node » connecter un « Null Object ». Attention, c’est très important qu’il soit sur la seconde entrée, donc à droite comme sur le screenshot en dessous.
    Vous pouvez voir que lorsque vous faites prendre la valeurs « 1 » au slider du Switch, qu’aucun objet n’est copié, ou plutot qu’uniquement des objets None sont copiés.
  • Reste à concocté l’expression qui va déterminer quand le switch passe automatiquement sur 0 ou 1. On voit ça en détail dans le prochain paragraphe.

Pour cette expression nous allons utiliser la fonction HScript npoints() : https://www.sidefx.com/docs/houdini/vex/functions/npoints.html

Comme on le voit, cette fonction renvoie un nombre entier (integer) correspondant au nombre de points d’une shape. Ici ce qui nous intéresse, c’est de savoir si on a des points ou pas sur le Node « Out_Intersect ».

Pour faire simple, nous allons utiliser la capacité du HScript a renvoyer un booléen True = 1 ou False = 0. Autrement dis, si un expression est fausse, elle renvoi la valeur de 0 et si elle est vrai, elle renvoi la valeur 1…. Ca ne vous rappel rien ? C’est pile les valeurs d’entrée qui nous intéresse sur notre Switch 🙂

L’expression est toute simple :

npoints("../OUT_intersect/")!=0

En langage courant, « la valeur de npoint est différente de 0 »
Pas besoin de « alors » puisque cette expression suffit à déclanché un booléen.
Autrement dit, si cette expression se vérifie bien (donc avec 1, 2, 8, 54789… points) l’expression est vrai…. et vrai en code ca s’appel True et True ça vaut 1. Le switch prendra donc sur la valeur 1 => un objet None est copié à la place d’un objet normal. CQFD.
Bien sûr, si le nombre de points vaut 0, l’expression est fausse, donc False donc égale à 0, le switch est sur l’entrée 0, l’itération de l’objet en cours est mergé.

Fini…. ou presque.

Optimiser la boucle

Cette partie est facultative, toutefois, pour des raisons de performance je vous conseils de le faire : compiler la boucle.

En effet, comme on l’a vu au début de cette article, cette boucle requiert un grand nombre d’itérations avec des Nodes gourmand en ressource. Le fait de compiler la boucle va permettre un calcul Multi-thread ce qui est justement parfait lorsqu’il y a un grand nombre d’une même tâche à accomplir. Ce setup profite tout particulièrement de la compilation :

Je ferai un autre article détailé de comment compiler des boucles.


0 commentaire

Laisser un commentaire