Date de la dernière modification: 12 novembre 2023
Ce mini-chapitre, à l’origine, faisait partie de l’article Imprimante 3D – Creality Ender 3 V2.
Ce dernier devenait vraiment énorme et difficile à manager!
Imprimante 3D – Blender et Python
La documentation de l’API de Blender pour Python est impressionnante et en particulier la partie dédiée aux Mesh Operators.
J’ai déjà quelques lignes de code fonctionnelles. J’ai passé quand même plusieurs jours (quelques heures seulement) avant d’y arriver! Voici aussi quelques notes nécessaire pour débuter:
- Attention à la version de Blender (2.92 chez moi) donc de Python (3.7.7) et l’API dédié à 2.91-92. Il y a de nombreux sujets, questions et exemples sur le Web … mais pour d’anciennes versions, et on risque de n’y rien comprendre.
- Chez moi le binaire Python se trouve dans le répertoire D:\Program Files\Blender Foundation\Blender 2.92\2.92\python\bin. Je n’ai pas trop essayé de configurer PyDev (Eclipse) et PyCharm, mes outils Python traditionnels, car c’est un peu difficile de les intégrer à Blender. Pour les amateurs, mon article PyDev, un IDE pour Python, sous Eclipse et pour le Raspberry Pi 3, où PyCharm est mentionné tout à la fin, pourrait intéresser plus d’un.
- Comme Blender a une sérieuse tendance à se planter, lorsque le code Python n’est par trop bien testé, je recommande d’utiliser Notepad++ pour l’édition. Il possède une jolie syntaxe colorée pour ce langage!
- On pourra bien sûr commencer par la Blender 2.92.0 Python API Documentation, mais cela risque d’être vraiment ardu. Personnellement, je prendrais des lignes de code tirées de l’exemple ci-dessous, tout simplement et essayer. Une ligne de code avec bpy.ops.mesh.primitive_cube_add peut être entrée directement sur la page de l’API pour y découvrir des paramètres comme size ou location.
- Pour mon travail ici, j’ai repris l’objet de l’exercice précédent, l’attache_vis et je l’ai ouvert dans Blender. Cela m’a permis de visionner mes cubes et cylindres, et leurs positions et dimensions. J’ai ensuite ouvert un second Blender pour jouer avec Python.
- Dans Blender, l’éditeur de Python se lance avec le menu Scripting, en haut tout à droite.
- Nous pouvons charger un fichier avec Open ou alors, avec New pour entrer notre code ou le copier coller de l’extérieur.
- Le menu Texte et Save As… nous permet de sauvegarder le code Python dans un fichier où l’extension .py est généralement utilisé.
- Ce même menu Texte permet aussi de charger du disque un script Python avec Open.
- Dans de rares cas j’ai édité mon code dans Blender (et non avec Notepad++) et sauver avant exécution.
- Pour voir les erreurs et les résultats il faut activer le “Toggle System Console” dans le menu Windows.
Comme mon fichier Python attache_vis.py fonctionne déjà, je l’ai donc déposé ci-dessous! Il faudrait le documenter, voire l’améliorer. Au début, il contient du code pour effacer une scène existante: c’est nécessaire lors de réexécution du script Python. On devrait paramétriser, dans des variables Python, certaines valeurs comme les diamètres, les grandeurs et les positions. Je me suis bien amusé, en ajoutant tout à la fin, le code de création d’un fichier .STL prêt pour Ultimaker Cura et l’impression 3D!
Ce n’est pas facile du tout … au début! Il y a plein de détails comme le 1.57 qui correspond à une rotation de 90 degrés. Un programmeur y trouvera beaucoup de plaisir, car il pourra à tout moment naviguer entre le mode Scripting et celui de Layout (menu de Blender).
Bien sûr, Blender vient avec quelques exemples (en mode Scripting, menu Templates / Python) comme operator_mesh_add! Je laisse le lecteur juger si c’est un bon moyen de créer un simple cube de cette manière ou alors revenir à Blender dans sa manière traditionnelle, sans langage Python du tout (mais j’aime bien mes radius 2.1 et 4 qui me permettraient de customiser facilement l’épaisseur de ma vis). On peut aussi très bien créer ces objets en Python et apporter la touche finale en mode Layout!
# attache_vis.py
import bpy
print ("Clean workspace")
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='SELECT')
for obj in bpy.data.objects:
if obj.hide_get() == True:
obj.hide_set(False)
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# efface si des collections supplémentaires
context = bpy.context
scene = context.scene
for c in scene.collection.children:
scene.collection.children.unlink(c)
print ("attache_vis.py started")
cube = bpy.ops.mesh.primitive_cube_add(size=1, location=(0, 0, 0), scale=(1,1,1))
theCube = bpy.context.object
theCube.name = 'BaseCube'
bpy.ops.transform.resize(value=(20, 36, 1))
bpy.ops.mesh.primitive_cylinder_add(radius=4, depth=10, location=(-10, 10, 3.5), scale=(1,1,1))
bpy.ops.transform.rotate(value=1.57, orient_axis='X')
theCylA = bpy.context.object
theCylA.name = 'CylinderA'
bpy.ops.mesh.primitive_cylinder_add(radius=2.1, depth=10, location=(-10, 10, 3.5), scale=(1,1,1))
bpy.ops.transform.rotate(value=1.57, orient_axis='X')
theCylAint = bpy.context.object
theCylAint.name = 'CylinderAint'
bool_modifier1 = theCylA.modifiers.new(type="BOOLEAN", name="boolc1")
bool_modifier1.object = theCylAint
bool_modifier1.operation = 'DIFFERENCE'
theCylAint.hide_set(False)
bpy.ops.object.modifier_apply()
bpy.ops.mesh.primitive_cylinder_add(radius=4, depth=10, location=(-10, -10, 3.5), scale=(1,1,1))
bpy.ops.transform.rotate(value=1.57, orient_axis='X')
theCylB = bpy.context.object
theCylB.name = 'CylinderB'
bpy.ops.mesh.primitive_cylinder_add(radius=2.1, depth=10, location=(-10, -10, 3.5), scale=(1,1,1))
bpy.ops.transform.rotate(value=1.57, orient_axis='X')
theCylBint = bpy.context.object
theCylBint.name = 'CylinderBint'
bool_modifier2 = theCylB.modifiers.new(type="BOOLEAN", name="boolc2")
bool_modifier2.object = theCylBint
bool_modifier2.operation = 'DIFFERENCE'
theCylBint.hide_set(False)
bpy.ops.object.modifier_apply()
bpy.ops.object.select_all(action='SELECT')
bpy.data.objects['CylinderAint'].hide_set(True)
bpy.data.objects['CylinderBint'].hide_set(True)
out_file = 'D:/AJbDev/3d/Blender/pythonscripts/attache_vis.stl'
bpy.ops.export_mesh.stl(filepath=out_file, use_selection=True)
print ("attache_vis.py ended")