Petit défi pour amateurs de Geometry Nodes
2 participants
- petitagore
Petit défi pour amateurs de Geometry Nodes
Dim 14 Mai - 16:21
Bonjour les blenderiens compétents... et bonjour aussi aux semi-pignoufs dans mon genre, qui sans y connaître grand-chose arrivent quand même parfois à venir à bout de maillages très simples pour aboutir à des images horriblement moches mais lisibles.
La 3D était mon violon d'Ingres des années avant que je ne rencontre Blender, et en particulier à la grande époque de VRML et de POV-Ray (je vous parle d'un temps que les moins de vingt ans ne peuvent pas connaître). A l'époque, on faisait de la 3D sans raccourci de clavier, sans clic droit, sans clic gauche, rien qu'en pondant du beau code informatique imbitable. Je n'étais pas mauvais à ce jeu-là, et... j'en ai gardé le goût, même si de nos jours ça ressemble de plus en plus à du masochisme: pourquoi se casser le tronc à écrire des pages et des pages de lignes de code, alors qu'un blenderien qui sait y faire arrive à faire des trucs époustouflants en un tournemain rien qu'en connectant des Geometry Nodes?
Eh bien... principalement, parce que je ne sais pas le faire, et aussi parce qu'à ce stade du récit je n'ai jamais trouvé une démo de Geometry Nodes qui ait le moindre rapport avec ce que je savais très bien faire avec mon code informatique.
C'est bien abstrait, ce que je vous dis là, alors je vous ai concocté un exemple. Voici un truc pas très compliqué et que nonobstant je ne trouve pas inintéressant, et qui en tout cas m'intéresse, moi (moi, je, le centre du monde)... Je sais très bien faire ce truc avec des lignes de code, et je n'ai jamais rencontré un adepte des Geometry Nodes qui ait réussi à m'expliquer comment faire plus ou moins la même chose avec des Nodes:
Alors voilà, je vous mets au défi, vous les petits jeunes champions du clicodrome: imitez ce que le vieux con que je suis arrive très bien à faire avec ses lignes de code, montrez-moi qu'on peut faire la même chose et même quarante fois mieux, beaucoup plus vite, avec des Geometry Nodes... mais surtout expliquez-moi comment vous vous y prenez parce que moi, vraiment, j'en ai pas la moindre idée. Et je ne voudrais pas mourir idiot.
Si vous arrivez à me faire comprendre, promis-juré j'utiliserai mes petits talents pédagogiques pour faire connaître vos techniques modernes à l'immense foule des abonnés de ma chaîne YouTube... Ils sont quand même 89 (faut un début à tout), et ma vidéo la plus pédagogique a quand même atteint 2400 vues, OK c'est pas le Pérou mais c'est quand même mieux que rien.
Allez-y, allez-y, montrez-moi, soyez pas chiens. Et poutous.
La 3D était mon violon d'Ingres des années avant que je ne rencontre Blender, et en particulier à la grande époque de VRML et de POV-Ray (je vous parle d'un temps que les moins de vingt ans ne peuvent pas connaître). A l'époque, on faisait de la 3D sans raccourci de clavier, sans clic droit, sans clic gauche, rien qu'en pondant du beau code informatique imbitable. Je n'étais pas mauvais à ce jeu-là, et... j'en ai gardé le goût, même si de nos jours ça ressemble de plus en plus à du masochisme: pourquoi se casser le tronc à écrire des pages et des pages de lignes de code, alors qu'un blenderien qui sait y faire arrive à faire des trucs époustouflants en un tournemain rien qu'en connectant des Geometry Nodes?
Eh bien... principalement, parce que je ne sais pas le faire, et aussi parce qu'à ce stade du récit je n'ai jamais trouvé une démo de Geometry Nodes qui ait le moindre rapport avec ce que je savais très bien faire avec mon code informatique.
C'est bien abstrait, ce que je vous dis là, alors je vous ai concocté un exemple. Voici un truc pas très compliqué et que nonobstant je ne trouve pas inintéressant, et qui en tout cas m'intéresse, moi (moi, je, le centre du monde)... Je sais très bien faire ce truc avec des lignes de code, et je n'ai jamais rencontré un adepte des Geometry Nodes qui ait réussi à m'expliquer comment faire plus ou moins la même chose avec des Nodes:
Alors voilà, je vous mets au défi, vous les petits jeunes champions du clicodrome: imitez ce que le vieux con que je suis arrive très bien à faire avec ses lignes de code, montrez-moi qu'on peut faire la même chose et même quarante fois mieux, beaucoup plus vite, avec des Geometry Nodes... mais surtout expliquez-moi comment vous vous y prenez parce que moi, vraiment, j'en ai pas la moindre idée. Et je ne voudrais pas mourir idiot.
Si vous arrivez à me faire comprendre, promis-juré j'utiliserai mes petits talents pédagogiques pour faire connaître vos techniques modernes à l'immense foule des abonnés de ma chaîne YouTube... Ils sont quand même 89 (faut un début à tout), et ma vidéo la plus pédagogique a quand même atteint 2400 vues, OK c'est pas le Pérou mais c'est quand même mieux que rien.
Allez-y, allez-y, montrez-moi, soyez pas chiens. Et poutous.
busanga et Pwett aiment ce message
- busanga
Re: Petit défi pour amateurs de Geometry Nodes
Dim 14 Mai - 19:37
Salut @petitagore ,
En guise de participation à ton challenge, je t'envoie ce .blend à explorer. Pas de mérite à une réponse aussi rapide, c'est en fait le résultat des mêmes réflexions que je me suis faites avec un de mes projets suite au sujet que tu nous avais posté sur ton église.
Assez peu de GN dans l'affaire tu verras, car on peut souvent paramétrer sa modélisation plus efficacement avec d'autres modificateurs (Mirror, Solidify, Array...) ou des contraintes, et c'est sur ce dernier aspect que j'ai trouvé le plus de choses intéressantes. En fait tout est faisable en GN, mais tu peux vite passer un temps fou sur une broutille.
Une petite description :
Ce que tu peux manipuler en mode objet :
- le cube Corps : S en X, Y ou Z pour ajuster la taille. Je n'ai pas bloqué la translation et la rotation, mais l'objet est censé rester à l'origine.
- le cube Tour : S en X, Y ou Z. Il reste aligné avec le mesh Corps grâce à une contrainte Limit Location dans le Custom Space de l'objet Corps ;
- l'objet Arches A : G Z, S X, Y ou Z. Pour le reste sa position est contrainte de la même manière par une Limit Location ;
- les objets Arches B et Arches C : S XX (axe X local) seulement. Leurs positions, hauteurs et profondeurs suivent celles des arches A
- le plan SymArches n'a pas à être modifié, il suit le mesh Corps et sert de plan de symétrie pour les arches A
Les contraintes Limit Location utilisent des repères relatifs à la taille des objets, donc il ne faut pas les modifier en Edit Mode. Si tu veux voir la géométrie initiale de chaque objet, tu peux faire un Alt S, Alt G (puis les annuler avec un Ctrl -Z). Ce sont essentiellement des cubes de dimensions 1 ou 2, avec l'origine au centre du cube, d'une face ou d'un coin suivant les cas, de manière à pouvoir positionner les objets de manière relative les uns par rapport aux autres.
Pour les meshs Arches ABC, la géométrie initiale est un cube, mais elle est remplacée par une géométrie construite par les GN (c'est le même modificateur sur les 3 objets), et c'est juste là qu'ils interviennent. Si tu édites le modificateur, tu verras qu'au départ on a un Input Object où je récupère la géométrie d'un objet Profil qui est automatiquement dimensionnée suivant l'objet qui porte le modificateur, ça c'est bien pratique. J'aurais pu modéliser mon arche "unité" et la brancher directement sur la sortie, mais j'ai brodé un peu pour pouvoir rendre paramétrable également le nombre de segments de l'arche (et donc paramétrer non seulement la géométrie mais aussi sa topologie).
Au final, tant qu'on applique pas les modificateurs, on a une géométrie assez complexe basée sur très peu de paramètres :
- les deux poignées de l'objet Profil pour donner la forme des arches (accessibles en éditant la courbe),
- le nombre de segments pour la topo (accessible dans n'importe laquelle des instances du modificateur GN),
- la taille du bâtiment et des tours (en dimensionnant en Object Mode les meshs correspondants),
- la position, la hauteur et l'épaisseur des arches (en dimensionnant en Object Mode le mesh Arches A),
- la larguer des arches A, B, C, individuellement
Ça te fait 3 objets distincts, mais on peut tout à fait imaginer intégrer ce nœud GN en triple exemplaire dans un modificateur unique sur un objet-maître dont les arches seraient des composants. Ce qui serait compliqué (en tout cas très chronophage), ce serait de vouloir compléter la modélisation en reliant les arches entre elles (je n'ai pas trouvé d'équivalent au Bridge Edge Loops ou au Grid Fill en GN). Mais là déjà tu gardes une certaine souplesse dans la modé, tu peux disposer les éléments comme tu le veux, et quand tu as le résultat voulu, tu appliques les modificateurs et tu termines à la main au pire, c'est guère plus lourd qu'un travail de retopo.
On peut s'y prendre un peu autrement, avec une armature, ou des emptys, mais au final on place les mêmes contraintes. De tous mes essais, celui que je te présente là est celui qui va mobiliser le moins d'objets.
Enfin, c'est très largement expérimental tu as compris, je te laisse explorer l'ensemble, voir comment j'ai disposé les contraintes et les modificateurs, je pense que ça répondra à une partie de tes questions.
En guise de participation à ton challenge, je t'envoie ce .blend à explorer. Pas de mérite à une réponse aussi rapide, c'est en fait le résultat des mêmes réflexions que je me suis faites avec un de mes projets suite au sujet que tu nous avais posté sur ton église.
Assez peu de GN dans l'affaire tu verras, car on peut souvent paramétrer sa modélisation plus efficacement avec d'autres modificateurs (Mirror, Solidify, Array...) ou des contraintes, et c'est sur ce dernier aspect que j'ai trouvé le plus de choses intéressantes. En fait tout est faisable en GN, mais tu peux vite passer un temps fou sur une broutille.
Une petite description :
Ce que tu peux manipuler en mode objet :
- le cube Corps : S en X, Y ou Z pour ajuster la taille. Je n'ai pas bloqué la translation et la rotation, mais l'objet est censé rester à l'origine.
- le cube Tour : S en X, Y ou Z. Il reste aligné avec le mesh Corps grâce à une contrainte Limit Location dans le Custom Space de l'objet Corps ;
- l'objet Arches A : G Z, S X, Y ou Z. Pour le reste sa position est contrainte de la même manière par une Limit Location ;
- les objets Arches B et Arches C : S XX (axe X local) seulement. Leurs positions, hauteurs et profondeurs suivent celles des arches A
- le plan SymArches n'a pas à être modifié, il suit le mesh Corps et sert de plan de symétrie pour les arches A
Les contraintes Limit Location utilisent des repères relatifs à la taille des objets, donc il ne faut pas les modifier en Edit Mode. Si tu veux voir la géométrie initiale de chaque objet, tu peux faire un Alt S, Alt G (puis les annuler avec un Ctrl -Z). Ce sont essentiellement des cubes de dimensions 1 ou 2, avec l'origine au centre du cube, d'une face ou d'un coin suivant les cas, de manière à pouvoir positionner les objets de manière relative les uns par rapport aux autres.
Pour les meshs Arches ABC, la géométrie initiale est un cube, mais elle est remplacée par une géométrie construite par les GN (c'est le même modificateur sur les 3 objets), et c'est juste là qu'ils interviennent. Si tu édites le modificateur, tu verras qu'au départ on a un Input Object où je récupère la géométrie d'un objet Profil qui est automatiquement dimensionnée suivant l'objet qui porte le modificateur, ça c'est bien pratique. J'aurais pu modéliser mon arche "unité" et la brancher directement sur la sortie, mais j'ai brodé un peu pour pouvoir rendre paramétrable également le nombre de segments de l'arche (et donc paramétrer non seulement la géométrie mais aussi sa topologie).
Au final, tant qu'on applique pas les modificateurs, on a une géométrie assez complexe basée sur très peu de paramètres :
- les deux poignées de l'objet Profil pour donner la forme des arches (accessibles en éditant la courbe),
- le nombre de segments pour la topo (accessible dans n'importe laquelle des instances du modificateur GN),
- la taille du bâtiment et des tours (en dimensionnant en Object Mode les meshs correspondants),
- la position, la hauteur et l'épaisseur des arches (en dimensionnant en Object Mode le mesh Arches A),
- la larguer des arches A, B, C, individuellement
Ça te fait 3 objets distincts, mais on peut tout à fait imaginer intégrer ce nœud GN en triple exemplaire dans un modificateur unique sur un objet-maître dont les arches seraient des composants. Ce qui serait compliqué (en tout cas très chronophage), ce serait de vouloir compléter la modélisation en reliant les arches entre elles (je n'ai pas trouvé d'équivalent au Bridge Edge Loops ou au Grid Fill en GN). Mais là déjà tu gardes une certaine souplesse dans la modé, tu peux disposer les éléments comme tu le veux, et quand tu as le résultat voulu, tu appliques les modificateurs et tu termines à la main au pire, c'est guère plus lourd qu'un travail de retopo.
On peut s'y prendre un peu autrement, avec une armature, ou des emptys, mais au final on place les mêmes contraintes. De tous mes essais, celui que je te présente là est celui qui va mobiliser le moins d'objets.
Enfin, c'est très largement expérimental tu as compris, je te laisse explorer l'ensemble, voir comment j'ai disposé les contraintes et les modificateurs, je pense que ça répondra à une partie de tes questions.
- petitagore
Re: Petit défi pour amateurs de Geometry Nodes
Lun 15 Mai - 10:14
@busanga Waouh! Super-pédagogique, merci!
Effectivement ça ouvre plein de pistes... mais ma première impression est que c'est très loin d'être plus simple que mes listings Python! En revanche on peut voir avec les yeux les effets de toutes les modifications, donc on a beaucoup moins besoin de développer des capacités d'abstraction qu'avec les listings... et ça c'est magique.
Quoique les capacités d'abstraction, ça puisse être super dans d'autres contextes.
Je vais étudier ça et ça va m'occuper un moment! Merci beaucoup!
Effectivement ça ouvre plein de pistes... mais ma première impression est que c'est très loin d'être plus simple que mes listings Python! En revanche on peut voir avec les yeux les effets de toutes les modifications, donc on a beaucoup moins besoin de développer des capacités d'abstraction qu'avec les listings... et ça c'est magique.
Quoique les capacités d'abstraction, ça puisse être super dans d'autres contextes.
Je vais étudier ça et ça va m'occuper un moment! Merci beaucoup!
- petitagore
Re: Petit défi pour amateurs de Geometry Nodes
Sam 20 Mai - 9:51
Bon, finalement je n'ai pas (encore?) relevé mon propre défi à l'aide de Geometry Nodes, mais en écrivant une nouvelle primitive avec un listing Python d'une simplicité... relative. N'empêche que ça marche, mon maillage est bel et bien modifiable en direct à la souris, ce qui était bien le but de la manoeuvre:
Ce n'est pas un exercice pour débutants en Python, certes... mais ça n'est pas non plus d'une complexité ingérable -- la preuve, j'y suis arrivé.
Cela dit, je ne suis pas sûr de persévérer dans cette voie, j'ai quand même un peu l'impression d'avoir employé un marteau-pilon pour écraser une mouche...
Vous en pensez quoi?
Ce n'est pas un exercice pour débutants en Python, certes... mais ça n'est pas non plus d'une complexité ingérable -- la preuve, j'y suis arrivé.
Cela dit, je ne suis pas sûr de persévérer dans cette voie, j'ai quand même un peu l'impression d'avoir employé un marteau-pilon pour écraser une mouche...
Vous en pensez quoi?
meltingman aime ce message
- busanga
Re: Petit défi pour amateurs de Geometry Nodes
Sam 20 Mai - 18:31
Salut,
Tu pourrais partager le script Python que tu fais défiler dans la vidéo ?
Tu pourrais partager le script Python que tu fais défiler dans la vidéo ?
- petitagore
Re: Petit défi pour amateurs de Geometry Nodes
Sam 20 Mai - 18:57
busanga a écrit:Tu pourrais partager le script Python que tu fais défiler dans la vidéo ?
Tu crois que ça en vaut la peine? En tout cas je n'ai rien contre...
Si les dieux de l'informatique sont avec moi, ce lien devrait directement te télécharger le script.
Quant au schéma explicatif (un peu indispensable pour comprendre la partie géométrique du script), le plus simple est sans doute que je le diffuse comme une image:
Ah, et puis dernière chose: pour que ça marche dans Blender, il faut évidemment lancer le script, ce que je n'ai pas montré dans la vidéo... mais il n'y a qu'à cliquer sur le bouton avec une pointe de flèche vers la droite, tout en haut dans l'éditeur de scripts -- ce que tu as certainement déjà dû faire si tu as déjà travaillé sur des scripts.
Ce n'est pas marqué dedans, mais tu peux considérer que ce script est diffusé sous la fameuse license WTFPL.
- busanga
Re: Petit défi pour amateurs de Geometry Nodes
Sam 20 Mai - 19:04
Tu crois que ça en vaut la peine?
C'est par curiosité, je voulais faire quelques tests, et plutôt que de réinventer la roue, autant partir d'un code déjà fonctionnel.
J'utilise pas mal les GN sans Python, et tu fais l'inverse, je me dis qu'on doit avoir des approches qui se complètent.
- busanga
Re: Petit défi pour amateurs de Geometry Nodes
Dim 21 Mai - 4:51
Voilà ton code réorganisé dans l'esprit GN (enfin tel que je le vois). Je suis revenu a tes noms de variables (en retirant celles quI n'étaient que les opposées d'autres).
Avec des boucles for, tu t'épargnes un bon paquet de lignes et tu n'as plus besoin de tes variables globales.
Pour être franc, j'ai un peu changé le cahier des charges (je n'ai pas pris en compte la hauteur du plafond, et j'ai positionné les fenêtres par rapport à l'axe central) dans un souci de clarté. Sous forme schématique, l'équivalent du script en GN ressemblerait à ça, avec des groupes de nœuds pour les différentes étapes) :
Les alternatives qui se présentent alors sont de piloter les paramètres avec des objets (par exemple un empty Toit dont la rotation donnerait la pente du toit). Pour l'assemblage, on serait vite coincé à gérer les index de points, mais en contrepartie on a plein d'autres outils qui permettent de créer et modifier des géométries de manière très efficace en fonction des paramètres donnés. Je te laisse découvrir tout ça si mon aide t'a inspiré.
Avec des boucles for, tu t'épargnes un bon paquet de lignes et tu n'as plus besoin de tes variables globales.
- Code:
#! /usr/bin/env python3
# coding: utf8
# Ce listing n'est comprehensible que si on l'accompagne
# du schema variables_mur_sud.png... mais alors il se révèle
# un peu moins abstrait qu'il n'en a l'air.
bl_info = {
"name": "Nouvelle façade",
"author": "Jean-Luc Ancey",
"version": (1, 0),
"blender": (2, 93, 0),
"location": "View3D > Add > Mesh > New Object",
"description": "Crée une façade de maison paramétrable",
"warning": "",
"doc_url": "",
"category": "Add Mesh",
}
import bpy
from bpy.types import Operator
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector
from math import pi, tan
def add_object(self, context):
composants = {
"etage" : {"G" : Vector((0.,0.,self.etageGz)), "S" : self.etageS},
"porte" : {"S" : Vector((self.porteSx, self.etageS.y, self.porteSz))},
"fenetre" : {"G" : Vector((self.fenetreGx, 0., self.fenetreGz)), "S" : Vector((self.fenetreSx, self.etageS.y, self.porteSz))},
"toit" : {"R" : Vector((0.,self.toitRy,0.))}
}
verts, faces = assemble(composants)
edges = []
mesh = bpy.data.meshes.new(name="facade")
mesh.from_pydata(verts, edges, faces)
object_data_add(context, mesh, operator=self)
def assemble(composants):
etage = composants['etage']
porte = composants['porte']
fenetre = composants['fenetre']
toit = composants['toit']
bravo = etage["G"].z
romeo = etage["S"].x/2
foxtrot = bravo + etage["S"].z
charlie, golf = bravo + fenetre["G"].z, foxtrot + fenetre["G"].z
delta, hotel = bravo + porte["S"].z, foxtrot + porte["S"].z
echo, india = etage["S"].z, 2*etage["S"].z
juliet = india + romeo*tan(toit["R"].y)
oscar = porte["S"].x/2
papa = fenetre["G"].x
quebec = papa + fenetre["S"].x
vertsRecto, vertsVerso, facesRecto, facesVerso, facesContour = [], [], [], [], []
# points :
for x in [-romeo,-papa,0.,papa,romeo] : vertsRecto.append(Vector((x,0.,0.))) # 1 à 5
for x in [-quebec,-papa] : vertsRecto.append(Vector((x,0.,charlie))) # 6 et 7
for x in [-oscar,oscar] : vertsRecto.append(Vector((x,0.,bravo))) # 8 et 9
for x in [papa,quebec] : vertsRecto.append(Vector((x, 0.,charlie))) # 10 et 11
for x in [-quebec,-papa,-oscar,oscar,papa,quebec] : vertsRecto.append(Vector((x,0.,delta))) # 12 à 17
for x in [-romeo,-papa,0.,papa,romeo] : vertsRecto.append(Vector((x, 0.,echo))) # 18 à 22
for x in [-quebec,-papa] : vertsRecto.append(Vector((x,0.,golf))) # 23 et 24
for x in [-oscar,oscar] : vertsRecto.append(Vector((x,0.,foxtrot))) # 25 et 26
for x in [papa,quebec] : vertsRecto.append(Vector((x,0.,golf))) # 27 et 28
for x in [-quebec,-papa,-oscar,oscar,papa,quebec] : vertsRecto.append(Vector((x, 0.,hotel))) # 29 à 34
for x in [-romeo,-papa,0.,papa,romeo] : vertsRecto.append(Vector((x, 0.,india))) # 35 à 39
for x in [-romeo/2,romeo/2] : vertsRecto.append(Vector((x,0.,(india+juliet)/2))) # 40 et 41
vertsRecto.append(Vector((0., 0., juliet))) # 42
vertsRectoNb = len(vertsRecto)
for vert in vertsRecto: vertsVerso.append(Vector((vert.x, etage["S"].y, vert.z)))
# faces du recto
facesRecto = [[0, 1, 6, 5], [1, 2, 7, 6], [2, 8, 7], [2, 3, 9, 8], [3, 4, 10, 9], \
[0, 5, 11, 17], [6, 7, 13, 12], [8, 9, 15, 14], [10, 4, 21, 16], \
[11, 12, 18, 17], [12, 13, 19, 18], [13, 14, 19], [14, 15, 20, 19], [15, 16, 21, 20], \
[17, 18, 23, 22], [18, 19, 24, 23], [19, 25, 24], [19, 20, 26, 25], [20, 21, 27, 26], \
[17, 22, 28, 34], [23, 24, 30, 29], [25, 26, 32, 31], [27, 21, 38, 33], \
[28, 29, 35, 34], [29, 30, 36, 35], [30, 31, 36], [31, 32, 37, 36], [32, 33, 38, 37], \
[34, 35, 39], [35, 36, 41, 39], [36, 37, 40, 41], [37, 38, 40]]
# faces du verso
for faceRecto in facesRecto :
faceVerso = []
for vertIndex in faceRecto :
faceVerso.append(vertIndex + vertsRectoNb)
facesVerso.append(faceVerso) # le reverse merdouille on dirait
# faces de la tranche
contours = [\
[5,6,12,11],[7,8,14,13],\
[9,10,16,15],[26,27,33,32],\
[24,25,31,30],[22,23,29,28],\
[0,1,2,3,4,21,38,40,41,39,34,17]\
]
for contour in contours :
nbAretes = len(contour)
for index in range(nbAretes):
vertIndex0, vertIndex1 = contour[index], contour[(index + 1) % nbAretes]
facesContour.append([vertIndex0, vertIndex1, vertIndex1 + vertsRectoNb, vertIndex0 + vertsRectoNb])
return (vertsRecto + vertsVerso, facesRecto + facesVerso + facesContour)
class OBJECT_OT_add_object(Operator, AddObjectHelper):
"""Crée une nouvelle façade"""
bl_idname = "mesh.add_facade"
bl_label = "Paramètres façade"
bl_options = {'REGISTER', 'UNDO'}
etageS: bpy.props.FloatVectorProperty(
name = 'Dim. étage', description = "Dimensions d'un étage",
default=(9, .5, 4),
subtype='XYZ_LENGTH', unit='LENGTH',)
etageGz: bpy.props.FloatProperty(
name = "Niveau Sol", description = "Niveau du sol au RdC",
default = .4,
)
porteSx : bpy.props.FloatProperty(
name = "Porte DimX", description = "Largeur des portes",
default = 1., min = .3, max = 2.,
)
porteSz : bpy.props.FloatProperty(
name = "Porte DimZ", description = "Hauteur des portes",
default = 2.,
)
fenetreGx : bpy.props.FloatProperty(
name = "Fenetre PosX", description = "Espace entre le bord d'une fenetre et l'axe de la façade",
default = 1.5,
)
fenetreGz : bpy.props.FloatProperty(
name = "Fenetre PosZ", description="Hauteur sous fenetre",
default = .8, min = 0., max = 2.,
)
fenetreSx : bpy.props.FloatProperty(
name = "Fenetre DimX", description = "Largeur des fenetres",
default = .9,
)
toitRy : bpy.props.FloatProperty(
name = "Pente Toit", description = "Pente du toit",
default = pi/6, min = pi/12, max = 5*pi/6,
unit = 'ROTATION', # comme ça, pas besoin de convertir en radians
)
def execute(self, context):
add_object(self, context)
return {'FINISHED'}
# Registration
def add_object_button(self, context):
self.layout.operator(
OBJECT_OT_add_object.bl_idname,
text="Façade paramétrable",
icon='PLUGIN')
# This allows you to right click on a button and link to documentation
def add_object_manual_map():
url_manual_prefix = "https://docs.blender.org/manual/en/latest/"
url_manual_mapping = (
("bpy.ops.mesh.add_object", "scene_layout/object/types.html"),
)
return url_manual_prefix, url_manual_mapping
def register():
bpy.utils.register_class(OBJECT_OT_add_object)
bpy.utils.register_manual_map(add_object_manual_map)
bpy.types.VIEW3D_MT_mesh_add.append(add_object_button)
def unregister():
bpy.utils.unregister_class(OBJECT_OT_add_object)
bpy.utils.unregister_manual_map(add_object_manual_map)
bpy.types.VIEW3D_MT_mesh_add.remove(add_object_button)
nbPointsSurUneFace = 0 # juste histoire de délcarer la VG, mais elle est recalculée à la création des points
if __name__ == "__main__":
register()
Pour être franc, j'ai un peu changé le cahier des charges (je n'ai pas pris en compte la hauteur du plafond, et j'ai positionné les fenêtres par rapport à l'axe central) dans un souci de clarté. Sous forme schématique, l'équivalent du script en GN ressemblerait à ça, avec des groupes de nœuds pour les différentes étapes) :
Les alternatives qui se présentent alors sont de piloter les paramètres avec des objets (par exemple un empty Toit dont la rotation donnerait la pente du toit). Pour l'assemblage, on serait vite coincé à gérer les index de points, mais en contrepartie on a plein d'autres outils qui permettent de créer et modifier des géométries de manière très efficace en fonction des paramètres donnés. Je te laisse découvrir tout ça si mon aide t'a inspiré.
- petitagore
Re: Petit défi pour amateurs de Geometry Nodes
Dim 21 Mai - 9:25
Le style, c'est l'homme, et chacun conçoit la lisibilité à sa guise... mais je ne comprends strictement pas pourquoi tant de programmeurs ont tant de mal avec l'idée de donner des noms intelligibles aux variables, et surtout pourquoi tant croient ingénieux de donner aux variables, en guise de nom, une lettre UNIQUE... Quand dans un listing de 500 lignes, tu cherches une aiguille dans une botte de foin, par exemple la variable "maSuperVariableAuNomExplicite" au milieu de quarante routines, pouf, tu tombes directement dessus, tandis que si tu cherches la variable "i", tu vas perdre un temps fou à tomber sur tous les "if", sur tous les "while"...
(sauf à utiliser des éditeurs de texte absurdement sophistiqués en lieu et place de cette merveille de simplicité qu'est emacs...)
Moi, j'ai commencé à programmer avec du BASIC Applesoft sur Apple II, et à l'époque on avait royalement droit à DEUX lettres pour les noms de variables... j'en pleure encore des larmes de sang tellement j'ai perdu de temps à déboguer mes listings à cause de cette ânerie. Depuis lors, je me suis juré que plus JAMAIS JAMAIS je ne nommerais mes variables avec moins de CINQ lettres. Et je n'en démordrai pas!
(c'est pas vrai, d'ailleurs: j'ai des variables "alfa", "echo", "golf", "kilo", "mike", "papa" et "zulu"...)
(sauf à utiliser des éditeurs de texte absurdement sophistiqués en lieu et place de cette merveille de simplicité qu'est emacs...)
Moi, j'ai commencé à programmer avec du BASIC Applesoft sur Apple II, et à l'époque on avait royalement droit à DEUX lettres pour les noms de variables... j'en pleure encore des larmes de sang tellement j'ai perdu de temps à déboguer mes listings à cause de cette ânerie. Depuis lors, je me suis juré que plus JAMAIS JAMAIS je ne nommerais mes variables avec moins de CINQ lettres. Et je n'en démordrai pas!
(c'est pas vrai, d'ailleurs: j'ai des variables "alfa", "echo", "golf", "kilo", "mike", "papa" et "zulu"...)
- busanga
Re: Petit défi pour amateurs de Geometry Nodes
Dim 21 Mai - 17:43
@petitagore J'ai édité mon post précédent (avec un code qui fonctionne cette fois), je m'arrête là, j'espère que cet éclairage t'aura été utile.
- petitagore
Re: Petit défi pour amateurs de Geometry Nodes
Lun 22 Mai - 0:25
@busanga Peste! Bravo pour la concision de ton code!
Cela étant, cette concision, louable dans l'absolu, n'était pas du tout au nombre de mes ambitions: j'ai fait la première vidéo en haut de ce fil d'abord à l'intention de débutants complets en Python (à qui je donne des cours), pour leur faire passer l'idée que fabriquer un maillage par programmation n'est vraiment pas difficile, particulièrement pas si on accompagne le listing d'un petit croquis pour fixer les idées. Pédagogiquement, je pense que c'est une bonne idée.
Ensuite, après avoir vu ça, divers copains du Blender User Group avec qui je papote sur Discord m'ont signalé des tutoriels permettant pensaient-ils d'aboutir à une version éditable "avec les yeux" (à la souris, quoi). J'ai suivi servilement la syntaxe de ces tutoriels, vu que je la découvrais, en m'astreignant à changer mon code initial aussi peu que possible, pour pouvoir plus facilement faire des comparaisons.
Je n'avais donc absolument aucune ambition en matière d'élégance... mais cela dit je suis loin d'être familier des techniques que tu as employées pour aboutir à cette élégance, et je confesse qu'elles me déconcertent. Elles me plairont sûrement davantage quand je les aurai comprises (si j'y parviens).
Les adopterai-je? Peut-être, mais vraiment pas forcément: j'ai une tendance prononcée à préférer une syntaxe moche et bavarde, mais compréhensible dès le premier regard, à une syntaxe concise et élégante aux allures de casse-tête chinois... parce qu'un listing est fait pour être exécuté tout de suite par une machine qui se contrefout de l'élégance et beaucoup plus tard adapté par quelqu'un qui a tout oublié de la logique du bazar -- à supposer qu'il l'ait jamais connue -- et a donc tout intérêt à pouvoir entrer dedans très rapidement sans que ça lui colle une migraine.
A la grande époque du langage Perl (que j'ai connue, privilège de l'âge), j'avais remarqué que les perlistes mettaient un point d'honneur à toujours hausser l'illisibilité au niveau d'un art... et le pire c'est qu'ils y parvenaient très souvent! Moi, ça me donnait surtout envie de leur dire comme le grand Corneille "Souffrez que je vous admire et ne vous imite point": à mon avis, il vaut toujours mieux faire bavard et compréhensible plutôt qu'élégant et imbitable -- et quand on reprend un listing cinq ans après l'avoir écrit avec l'intention de l'adapter à une nouvelle idée (ce qui m'arrive très souvent), on est bien content d'avoir opté pour la première approche.
Et cela étant, bravo.
Cela étant, cette concision, louable dans l'absolu, n'était pas du tout au nombre de mes ambitions: j'ai fait la première vidéo en haut de ce fil d'abord à l'intention de débutants complets en Python (à qui je donne des cours), pour leur faire passer l'idée que fabriquer un maillage par programmation n'est vraiment pas difficile, particulièrement pas si on accompagne le listing d'un petit croquis pour fixer les idées. Pédagogiquement, je pense que c'est une bonne idée.
Ensuite, après avoir vu ça, divers copains du Blender User Group avec qui je papote sur Discord m'ont signalé des tutoriels permettant pensaient-ils d'aboutir à une version éditable "avec les yeux" (à la souris, quoi). J'ai suivi servilement la syntaxe de ces tutoriels, vu que je la découvrais, en m'astreignant à changer mon code initial aussi peu que possible, pour pouvoir plus facilement faire des comparaisons.
Je n'avais donc absolument aucune ambition en matière d'élégance... mais cela dit je suis loin d'être familier des techniques que tu as employées pour aboutir à cette élégance, et je confesse qu'elles me déconcertent. Elles me plairont sûrement davantage quand je les aurai comprises (si j'y parviens).
Les adopterai-je? Peut-être, mais vraiment pas forcément: j'ai une tendance prononcée à préférer une syntaxe moche et bavarde, mais compréhensible dès le premier regard, à une syntaxe concise et élégante aux allures de casse-tête chinois... parce qu'un listing est fait pour être exécuté tout de suite par une machine qui se contrefout de l'élégance et beaucoup plus tard adapté par quelqu'un qui a tout oublié de la logique du bazar -- à supposer qu'il l'ait jamais connue -- et a donc tout intérêt à pouvoir entrer dedans très rapidement sans que ça lui colle une migraine.
A la grande époque du langage Perl (que j'ai connue, privilège de l'âge), j'avais remarqué que les perlistes mettaient un point d'honneur à toujours hausser l'illisibilité au niveau d'un art... et le pire c'est qu'ils y parvenaient très souvent! Moi, ça me donnait surtout envie de leur dire comme le grand Corneille "Souffrez que je vous admire et ne vous imite point": à mon avis, il vaut toujours mieux faire bavard et compréhensible plutôt qu'élégant et imbitable -- et quand on reprend un listing cinq ans après l'avoir écrit avec l'intention de l'adapter à une nouvelle idée (ce qui m'arrive très souvent), on est bien content d'avoir opté pour la première approche.
Et cela étant, bravo.
meltingman aime ce message
- busanga
Re: Petit défi pour amateurs de Geometry Nodes
Lun 22 Mai - 10:20
je suis loin d'être familier des techniques que tu as employées
Pourtant il n'y a rien de bien compliqué, et malgré les apparences peut-être, l'objectif était bien de garder un code qui reste lisible .
La règle essentielle à suivre en programmation en général, c'est que dès que tu fais quelque chose deux fois de suite de manière similaire, c'est déjà une fois de trop, et qu'on doit pouvoir faire mieux avec une variable bien choisie, une fonction, une boucle...
Je te donne quelques exemples tirés de ton code initial :
- Code:
verts = []
verts.append(fabriquePointY0(1, kilo, alfa))
verts.append(fabriquePointY0(2, mike, alfa))
verts.append(fabriquePointY0(3, 0.0, alfa))
verts.append(fabriquePointY0(4, papa, alfa))
verts.append(fabriquePointY0(5, romeo, alfa))
def fabriquePoint (num, xrays, yankee, zulu):
monPoint = Vector((xrays, yankee, zulu))
return monPoint
def fabriquePointY0 (num, xrays, zulu):
monPoint = fabriquePoint(num, xrays, 0.0, zulu)
return monPoint
Dans les 5 premières lignes, en langage courant, c'est "pour chacune des cotes kilo, mike, 0, papa et romeo, tu fais ça". Bon, bah Python est très intuitif de ce côté-là, tu peux remplacer par :
- Code:
verts = []
num = 1 # pour conserver la numérotation, que j'ai retirée dans ce que je t'ai proposé plus haut
for cote in [kilo, mike, 0., papa, romeo] :
verts.append(fabriquePointY0(num, cote, alfa))
num += 1
def fabriquePoint (num, xrays, yankee, zulu):
monPoint = Vector((xrays, yankee, zulu))
return monPoint
def fabriquePointY0 (num, xrays, zulu):
monPoint = fabriquePoint(num, xrays, 0.0, zulu)
return monPoint
Du coup la fonction fabriquePointY0 n'a plus trop lieu d'être, vu qu'elle n'intervient que sur une ligne de code, tu peux remplacer son occurrence par son contenu :
- Code:
verts = []
num = 1
for cote in [kilo, mike, 0., papa, romeo] :
verts.append(fabriquePoint(num, cote, 0.0, alfa))
num += 1
def fabriquePoint (num, xrays, yankee, zulu):
monPoint = Vector((xrays, yankee, zulu))
return monPoint
Dans la fonction qui reste, tu crées une variable locale que tu retourne immédiatement, autant simplifier en :
- Code:
verts = []
num = 1
for cote in [kilo, mike, 0., papa, romeo] :
verts.append(fabriquePoint(num, cote, 0.0, alfa))
num += 1
def fabriquePoint (num, xrays, yankee, zulu):
# print(num) # pour déboguage éventuel
return Vector((xrays, yankee, zulu))
Le print(num) de déboguage peut être mis dans la boucle, ce qui fait que ta fonction fabriquePoint est peu ou prou la fonction déjà existante Vector (si ce n'est, avantage qui peut quand même être jugé appréciable, qu'on a besoin d'un niveau de parenthèses en moins). Et hop ça devient :
- Code:
verts = []
num = 1
for cote in [kilo, mike, 0., papa, romeo] :
# print(num) # pour déboguage
verts.append(Vector((cote, 0.0, alfa)))
num += 1
Autre exemple avec la partie :
- Code:
faces = []
faces.append(fabriqueFace([1, 2, 7, 6]))
faces.append(fabriqueFace([2, 3, 8, 7]))
faces.append(fabriqueFace([3, 9, 8]))
faces.append(fabriqueFace([3, 4, 10, 9]))
def fabriqueFace (tabIndex):
tableau2 = []
for valeur in tabIndex:
tableau2.append(valeur - 1)
return tableau2
que tu peux déjà raccourcir (pas flagrant ici, mais il y a une quarantaine de faces.append dans le code initial) en :
- Code:
facesATraiter = [[1, 2, 7, 6], [2, 3, 8, 7], [3, 9, 8], [3, 4, 10, 9]]
faces = []
for face in facesATraiter :
faces.append(fabriqueFace(face))
def fabriqueFace (tabIndex):
tableau2 = []
for valeur in tabIndex:
tableau2.append(valeur - 1)
return tableau2
Ensuite sur les tableaux, tu as tout un tas de fonctions natives qui te permettent de renverser une liste, la décaler, n'en prendre qu'une partie... Je te renvoie à la doc de Swinnen que tu connais sans doute. D'ailleurs, je ne me considère par comme un expert de Python, et je vais fréquemment chercher des bouts de code sur le net, comme celui-ci qui te permet de retirer 1 à toutes les valeurs de la liste :
- Code:
facesATraiter = [[1, 2, 7, 6], [2, 3, 8, 7], [3, 9, 8], [3, 4, 10, 9]]
faces = []
for face in facesATraiter :
faces.append(fabriqueFace(face))
def fabriqueFace(listeDesVertIndex): # là ça peut être utile un nom de variable explicite
listeDesNouveauxVertIndex = [vertIndex - 1 for vertIndex in listeDesVertIndex]
return listeDesNouveauxVertIndex
raccourci en :
- Code:
facesATraiter = [[1, 2, 7, 6], [2, 3, 8, 7], [3, 9, 8], [3, 4, 10, 9]]
faces = []
for face in facesATraiter :
faces.append(fabriqueFace(face))
def fabriqueFace(listeDesVertIndex):
# on retire - 1 à chaque index des points constituant la face # <- là tu peux expliciter ton code # <- oui je commente mes propres commentaires
return [vertIndex - 1 for vertIndex in listeDesVertIndex]
et finalement on peut se dispenser de la fonction fabriqueFace :
- Code:
facesATraiter = [[1, 2, 7, 6], [2, 3, 8, 7], [3, 9, 8], [3, 4, 10, 9]]
faces = []
for face in facesATraiter :
faces.append([vertIndex - 1 for vertIndex in face])
(au final, j'ai fini par décrémenter manuellement tous les indices dans la variable facesATraiter, qui se trouvait alors être directement la variable faces dont on avait besoin).
En simplifiant ton code de manière méthodique comme ça, il t'apparaît de plus en plus lisible, et d'autres simplifications t'apparaissent évidentes, et ainsi de suite. Ce n'est vraiment pas du codage obscur, la structure de ton algorithme reste la même.
Ton code m'a quand même inspiré pour le tuto que je préparais sur les arches, je vais l'aiguiller vers une présentation de différentes méthodes pour une modélisation paramétrable.
petitagore aime ce message
- petitagore
Re: Petit défi pour amateurs de Geometry Nodes
Lun 22 Mai - 10:58
@busanga Merci de ces explications, avec elles c'est effectivement beaucoup moins cryptique... Je vais donc y réfléchir.
Pour le principe, je réagis à ça:
C'est le fameux débat entre DRY (don't repete yourself) et WET (write everything twice). Ta "règle essentielle" paraît frappée au coin du bon sens, mais en pratique ça peut sensiblement varier en fonction du contexte. Par exemple, tu as pris grand soin de remplacer mes numéros de points par une variable num, ce qui est bien sûr plus élégant... mais en pratique est le type même de la fausse bonne idée. Cas pratique réel sur ma façade: dans une première version de mon code, les points 40 et 41 étaient alignés en X sur les cotes mike et papa, de sorte que quand je déplaçais les fenêtres horizontalement le toit cessait d'avoir une pente rectiligne: il y avait donc une faute de logique et un bug à corriger... pour les points 40 et 41 et eux seuls, en sorte que j'ai été rudement content de pouvoir me reporter directement aux lignes de code où apparaissaient les valeurs 40 et 41, pour leur affecter des abscisses mikePrime et papaPrime, créées pour l'occasion. Difficulté: nulle... parce que mon code était moche et bavard, mais aussi très facile à parcourir. Avec ton code élégant, ç'aurait été sensiblement plus prise de tête...
L'élégance, c'est bien... mais ça n'est pas une fin en soi. La simplicité de débogage, en revanche, c'est un truc dont en pratique on a vraiment très souvent besoin.
Pour le principe, je réagis à ça:
busanga a écrit:La règle essentielle à suivre en programmation en général, c'est que dès que tu fais quelque chose deux fois de suite de manière similaire, c'est déjà une fois de trop, et qu'on doit pouvoir faire mieux avec une variable bien choisie, une fonction, une boucle...
C'est le fameux débat entre DRY (don't repete yourself) et WET (write everything twice). Ta "règle essentielle" paraît frappée au coin du bon sens, mais en pratique ça peut sensiblement varier en fonction du contexte. Par exemple, tu as pris grand soin de remplacer mes numéros de points par une variable num, ce qui est bien sûr plus élégant... mais en pratique est le type même de la fausse bonne idée. Cas pratique réel sur ma façade: dans une première version de mon code, les points 40 et 41 étaient alignés en X sur les cotes mike et papa, de sorte que quand je déplaçais les fenêtres horizontalement le toit cessait d'avoir une pente rectiligne: il y avait donc une faute de logique et un bug à corriger... pour les points 40 et 41 et eux seuls, en sorte que j'ai été rudement content de pouvoir me reporter directement aux lignes de code où apparaissaient les valeurs 40 et 41, pour leur affecter des abscisses mikePrime et papaPrime, créées pour l'occasion. Difficulté: nulle... parce que mon code était moche et bavard, mais aussi très facile à parcourir. Avec ton code élégant, ç'aurait été sensiblement plus prise de tête...
L'élégance, c'est bien... mais ça n'est pas une fin en soi. La simplicité de débogage, en revanche, c'est un truc dont en pratique on a vraiment très souvent besoin.
- busanga
Re: Petit défi pour amateurs de Geometry Nodes
Lun 22 Mai - 13:20
Effectivement, tu as raison, mon système de déboguage n'en est pas vraiment un, car le num qui serait affiché n'est pas forcément celui de la figure. Après une numérotation "logique" comme celle que tu avais faite et quelques commentaires pour baliser les zones traitées permettent de s'y retrouver facilement aussi.
- petitagore
Re: Petit défi pour amateurs de Geometry Nodes
Jeu 6 Juil - 11:24
Un copain informaticien très très compétent a vu sur YouTube mon petit défi et l'a relevé... et surtout il m'a envoyé son fichier Blender pour que je l'étudie. En le simplifiant à mort, j'ai réussi à aboutir à la merveille ci-dessous:
Ca fabrique seulement le seul élément non parallélépipédique de ma façade, c'est-à-dire le triangle isocèle qui la coiffe, mais ça le fabrique ex nihilo, et ça, ça change la vie. Surtout, ça fournit un exemple simple, celui que je cherchais désespérément dans les tutoriels YouTube depuis des lustres... et ça va me changer la vie: maintenant que j'ai compris ça, je sens que je suis (enfin!) capable de faire tout et n'importe quoi avec les Geometry Nodes.
Si comme moi vous avez toujours voulu comprendre les Geometry Nodes sans avoir jamais osé rien leur demander... je vous conseille vivement d'étudier l'image ci-dessus, ça vous changera la vie.
Ca fabrique seulement le seul élément non parallélépipédique de ma façade, c'est-à-dire le triangle isocèle qui la coiffe, mais ça le fabrique ex nihilo, et ça, ça change la vie. Surtout, ça fournit un exemple simple, celui que je cherchais désespérément dans les tutoriels YouTube depuis des lustres... et ça va me changer la vie: maintenant que j'ai compris ça, je sens que je suis (enfin!) capable de faire tout et n'importe quoi avec les Geometry Nodes.
Si comme moi vous avez toujours voulu comprendre les Geometry Nodes sans avoir jamais osé rien leur demander... je vous conseille vivement d'étudier l'image ci-dessus, ça vous changera la vie.
- busanga
Re: Petit défi pour amateurs de Geometry Nodes
Jeu 6 Juil - 12:45
Bienvenue dans le monde des GN , une fois lancé tu trouveras petit a petit les façons d'optimiser telle ou telle étape.
Si je comprends bien, c'est le nœud Convex Hull qui génère les faces ? Du coup sur des objets non convexes tu seras bloqué avec cette manière.
Une autre approche serait de partir d'une Mesh Primitive, en l'occurrence un cylindre à 3 vertices, et de la redimensionner avec un nœud Geometry Transform en fonction des dimensions données en entrée. Ça restera gourmand en boîtes et spaghettis, ceci dit, comme ta solution au-dessus, mais tu as les Node Groups qui fonctionnent comme des sous-programmes quand ça devient volumineux.
Si je comprends bien, c'est le nœud Convex Hull qui génère les faces ? Du coup sur des objets non convexes tu seras bloqué avec cette manière.
Une autre approche serait de partir d'une Mesh Primitive, en l'occurrence un cylindre à 3 vertices, et de la redimensionner avec un nœud Geometry Transform en fonction des dimensions données en entrée. Ça restera gourmand en boîtes et spaghettis, ceci dit, comme ta solution au-dessus, mais tu as les Node Groups qui fonctionnent comme des sous-programmes quand ça devient volumineux.
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
|
|