Pour les vues orthogonales (Front, Side, Top), je préfère les touches 1, 3 et 7 du pavé numérique à la touche tilde “~”
10:42
Double-clic sur un Edge ne sélectionne pas la boucle (loop), c’est sans doute un shortcut qu’a configuré Christopher 3D sans s’en rappeler.
Pour sélection une loop, Alt-Left click.
10:46
Si le menu Dissolve Edges n’apparaît pas sous le menu Edges, c’est parce qu’on activé les Pie Menus.
Avec la loop sélectionnée, faites plutôt X puis choisir Dissolve Edges.
29:11
Le Knife tool (k), dans mon cas, n’a pas fait de loop cut faisant tout le tour de l’objet. Aucune idée pourquoi. Alors j’ai sélectionné le Vertex du début et celui de la fin et j’ai fait “J” (Connect Vertex Path).
31:50
Pour Merge Vertices, dans notre cas, il faut faire M et le Pie Menu va apparaître.
Tant que vous avez des quad-gons plus ou moins équilibrés, pas obligé de faire exactement comme lui.
49:18
Zarbi, il a le Base Gold Rim de sélectionné, mais le mirror modifier s’applique au base. Mais bon, au Base, il faut un Mirror Axis le long de X et Y avec Bisect X et Y et Flip Y, pour le base Gold Rim, juste Mirror Axis X et Y.
01:03:20
C’est slash (/) pas backslash () pour isoler un objet
(Je vous montrerai au prochain cours comment appliquer les autres fichiers (bump map, roughness maps, normal maps, etc.)
01:21:35
Ne pas oublier, pour sélectionner un loop au complet, c’est Alt-clic. Pour en sélectionner un 2e, Shift-Alt-clic.
01:28:30
Ah oui, j’ai désactivé “Align to View” (Edit → Preferences → Align to) et remis à Align to “World”, ça me rendait dingue :)
Je préfère savoir que l’objet sera crée et aligné selon les axes du World et aligner moi-même l’objet ensuite à ce que je veux.
01:29:39
La touche “.” (pas celle du pavé numérique, l’autre) est super pratique en mode Edit. Par exemple pour faire un Scale par rapport à un pivot qui n’est pas le curseur 3D
On aurait pu faire aussi S puis Z pour contraindre la mise à l’échelle à l’axe des Z seulement
01:31:33
Arêtes Manifold vs. Non-Manifold dans Blender
Arêtes manifold :
Ce sont des arêtes appartenant à un maillage bien défini et fermé, où chaque arête est connectée exactement à deux faces.
Cela signifie que la géométrie est solide et peut être utilisée pour des opérations comme l’impression 3D ou les simulations physiques.
Arêtes non-manifold :
Ce sont des arêtes problématiques qui indiquent la présence de trous, de faces internes ou de géométrie détachée. Elles peuvent apparaître dans les cas suivants :
Arêtes ouvertes (qui ne sont attachées qu’à une seule face ou à aucune).
Faces internes (faces cachées à l’intérieur du modèle).
Arêtes connectées à plus de deux faces (comme dans une géométrie qui s’intersecte).
Sélectionner les arêtes Manifold dans Blender
Pour sélectionner les arêtes non-manifold, vous pouvez utiliser :
Mode Édition → Menu Sélection (Sélection > Sélectionner tout par attribut > Non-manifold).
Raccourci : Shift + Ctrl + Alt + M.
01:40:53
Quand vous ajoutez le Mirror Modifier, assurez-vous qu’il soit, dans le stack, avant le Smooth by Angle. En d’autres termes, on Bevel, on Mirror et seulement ensuite on Smooth by angle.
P.S.: vous n’aurez pas tout les points si vous ne faites que le minimum.
Ici, j’ai ajouté un peu de Bloom ainsi qu’une distortion de la lentille (vous avez ça dans le compositor d’un fichier défaut). J’ai également transféré le denoise au Compositor.
Cours 06 (3h) - Raycasting et autres trucs intéressants
TBD
Cours 07 (3h) - Intro aux Sim Nodes
Devoir
TBD
Cours 08 (3h) - Animations et Game Engines
Banque de cours - Transfert de shape keys de Vertex vers Shape Blends (format mdd)
Transfert de shape keys de Vertex vers Shape Blends (format mdd)
Une technique pour exporter une animation geo nodes ou par modifiers (e.g. Ocean ou Wave Modifier) de Blender vers Unity,
Cette technique fonctionne bien lorsqu’il s’agit, un peu comme les VAT (Vertex Animation Texture), de modifier les vecteurs des vertices sans en ajouter ou en retirer.
⚠️
Il est important de choisir un frame rate adéquat. On va choisir, ici, 60 fps (dans les paramètres Output).
Créer un Plane et ajoutez un Ocean Modifier.
Dans les paramètres Waves, mettre l’échelle à 2.5 et le “Choppiness” à 2 pour avoir des vagues plus hautes et plus cassées.
Pour que que le Blend Shape fonctionne dans Unity, il faut une animation avec des keyframes.
Keyframer le time à 0 au Frame 1, puis à 10 par exemple, au frame 250.
Assurez-vous que l’interpolation est linéaire et qu’il n’y a pas de Ease-In ou Ease-Out (Sélectionner tous les keyframes, ou tout les points dans le graph editor, cliquer-droit et choisir Interpolation Mode → Linear et Easing Type → Automatic Easing).
Installer et activer l’add-on “NewTek MDD format” et l’activer.
Le format NewTek MDD (Motion Designer Data) est un format de fichier d’animation basé sur l’utilisation de shape keys utilisé qui permet de stocker les données de déplacement de vertex dans une animation 3D. Il a été développé à l’origine pour LightWave 3D, un logiciel de modélisation et d’animation de NewTek, mais il est aussi utilisé dans d’autres logiciels 3D comme Blender, Maya (via des plugins), Houdini, etc.
Le fichier .mdd contient les positions de tous les sommets d’un objet 3D à chaque frame de l’animation. (Ça ressemble au textures VAT hein!). Cela permet de :
Transférer des animations précises (notamment des simulations complexes comme des cloths, fluides ou destructions) entre différents logiciels.
Jouer une animation en “bake”, c’est-à-dire sans avoir besoin des armatures, simulations ou contraintes d’origine.
Faciliter le rendu dans des moteurs externes ou pipelines complexes.
Structure typique d’un fichier .mdd :
Nombre de points (sommets)
Nombre de frames
Pour chaque frame : une liste de positions (x, y, z) pour chaque sommet
Sélectionner le Plane et faire File → Export → “Lightwave Point Cache (.mdd)”. Ce sous-menu a été ajouté par l’add-on qu’on vient d’activer.
Appliquer le modifier. L’animation va disparaître, mais elle est, maintenant, frame par frame et vertex par vertex, dans le fichier .mdd.
Sélectionner encore une fois l’objet inanimé et sans modifiers et faire “File → Import → “Lightwave Point Cache (.mdd)” et choisir le fichier qu’on a exporté durant l’opération d’export.
Faites Play, l’objet est à nouveau animé, mais cette fois-ci avec des keyframes pour chaque frame et pour chaque Vertex!
Maintenant, il vous suffit d’exporter l’objet en format FBX. Ne pas oublier d’activer “Limnit to: Selected Objects” et d’activer le checkbox “Animation”.
Ok, on passe à Unity.
Unity est capable de comprendre les shape keys (qu’il appelle Blend Shapes) mais il faut écrire un script pour looper à travers tous les blend shapes. Le script est inspiré de ceci, qu’on peut trouver dans la doc de Unity 6:
Dans Unity, drag and drop le FBX dans les assets puis dans la scène.
Créer un nouveau script (+ en dessous de Project, “Monobehaviour script”) et le nommer ShapeBend.cs
Drag and drop le FBX dans la scène (sous Hierarchy)
Associer à cet objet le script suivant (appelez-le “ShapeBend.cs” par exemple) que vous aurez écrit. La bonne nouvelle, c’est que c’est le même script pour n’importe quel animation généré par cette méthode.
using System.Collections;using System.Collections.Generic;using UnityEngine;public class NewMonoBehaviourScript : MonoBehaviour{ SkinnedMeshRenderer skinnedMeshRenderer; Mesh skinnedMesh; int blendShapeCount; int playIndex = 0; // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>(); skinnedMesh = GetComponent<SkinnedMeshRenderer>().sharedMesh; blendShapeCount = skinnedMesh.blendShapeCount; } // Update is called once per frame void Update() { if (playIndex > 0) skinnedMeshRenderer.SetBlendShapeWeight(playIndex - 1, 0f); if (playIndex == 0) skinnedMeshRenderer.SetBlendShapeWeight(blendShapeCount - 1, 0f); skinnedMeshRenderer.SetBlendShapeWeight(playIndex, 100f); playIndex++; if (playIndex > blendShapeCount - 1) playIndex = 0; }}
Ajouter un Empty à la scène et lui associer le code suivant (Appelez-le ”FpsLock.cs” par exemple). Ce code impose le même frame rate que celui utilisé dans Blender (donc modifier la valeur en fonction de votre animation Blender).
Si vous ne le faites pas, l’animation va tourner trop vite.
🔥
Ceci est un quickfix. Idéalement, on impose pas de frame rate, mais on contrôle la durée de l’animation.
using System.Collections;using System.Collections.Generic;using UnityEngine;public class FpsLock : MonoBehaviour{ // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { Application.targetFrameRate = 30; } // Update is called once per frame void Update() { }}
Jouez la scène. Badabeen, badaboon! (Ajouter un component “Free Camera” à l’objet “Main Camera” si vous voulez vous promener dedans en mode “Play”).
Key stuff:
Limitation: la géométrie doit être la même en termes de nombre de vertex. Si l’animation dans Blender on ajoute ou en enlève, cette méthode ne fonctionnera pas.
Ça fonctionne donc avec, par exemple, Wave Modifier, Lattice Modifier, cloth simulation, etc.
Pour le geo nodes, ça ne fonctionne pas si les geo nodes ajoutent de la géométrie par rapport à l’objet de base. Et pourtant…
FpsLock C# file associated with an empty in the scene, frame rate should be the same as the one set in Blender
Enable mdd add-on in Blender
Une manière brillante de rendre votre loop “seamless”:
Dans ce fichier, un robot a été modélisé et animé. Les morceaux de robots (les Québécois de ma génération verront la référence :D) se trouvent dans une collection nommée “Robot parts”
On voudrait expérimenter avec de la simulation de particules (la première simulation intégrée au Geo Nodes) à partir de la géométrie du robot.
Comme le robot est composé de plusieurs objets distincts, les amener à la main en tant que “Object Info” dans un système de geo nodes serait fastidieux (il y a une centaine objets!).
Commençons par le créer un objet pour avoir un système de geo nodes. Un Plane suffit.
⚠️
Assurez-vous de ne pas être dans la collection “Robot parts”!
Aller dans le système de Geo Nodes et faire New en s’assurant que le Plane est sélectionné. Nommer le geo nodes “Particle Sim” et l’épingler.
Maintenant on va écrire un script Python qui va aller chercher tous les objets de la collection “Robot parts”, les ajouter de manière ordonnée avec full cable management en tant que noeuds Object Info et les connecter à un Join Geometry.
Aller dans l’espace de travail “Scripting”.
Faites “Text → New”
Copier coller le code suivant:
import bpydef add_object_info_nodes_from_collection(collection_name): # Get the active object and its Geo Node tree obj = bpy.context.active_object if not obj or not obj.modifiers or obj.modifiers[-1].type != 'NODES': print("No active object with a Geometry Nodes modifier selected!") return geo_nodes = obj.modifiers[-1].node_group nodes = geo_nodes.nodes links = geo_nodes.links # Find or create a Join Geometry node join_node = None for node in nodes: if node.type == 'JOIN_GEOMETRY': join_node = node break if not join_node: join_node = nodes.new(type='GeometryNodeJoinGeometry') # Load the collection collection = bpy.data.collections.get(collection_name) if not collection: print(f"Collection '{collection_name}' not found!") return # Create a Frame node to hold all Object Info nodes frame = nodes.new(type='NodeFrame') frame.label = f"{collection_name} Objects" frame.name = f"{collection_name}_Frame" frame.width = 400 # Grid layout settings spacing_x = 200 # Horizontal spacing between columns spacing_y = -200 # Vertical spacing between rows nodes_per_column = 10 created_nodes = [] max_col = 0 max_row = 0 for index, obj_in_collection in enumerate(collection.objects): # Calculate grid position col = index // nodes_per_column row = index % nodes_per_column max_col = max(max_col, col) max_row = max(max_row, row) x = -600 + (col * spacing_x) y = row * spacing_y # Create Object Info node obj_info = nodes.new(type='GeometryNodeObjectInfo') obj_info.parent = frame obj_info.location = (x, y) obj_info.inputs['As Instance'].default_value = False obj_info.inputs['Object'].default_value = obj_in_collection if hasattr(obj_info, 'transform_space'): obj_info.transform_space = 'RELATIVE' # Create a Reroute node reroute = nodes.new(type='NodeReroute') reroute.location = (x + 150, y) # Connect Object Info to Reroute links.new(obj_info.outputs['Geometry'], reroute.inputs[0]) # Connect Reroute to Join Geometry links.new(reroute.outputs[0], join_node.inputs['Geometry']) created_nodes.append(obj_info) # Calculate Frame Size (optional: Blender does it automatically if you move nodes manually) frame.location = (-650, 150) frame_width = (max_col + 1) * spacing_x frame_height = (max_row + 1) * abs(spacing_y) # Move Join Geometry node to right of Frame join_node.location = (-600 + frame_width + 300, 0) print(f"Added {len(created_nodes)} Object Info nodes from collection '{collection_name}', framed, with reroutes, 10x10 grid, Join Geometry neatly positioned.")# Direct call (no popup)add_object_info_nodes_from_collection("Robot parts")
En gros, le script crée des Object Info pour chaque objet trouvé dans la collection “Robot parts”, les configure en mode “relative”, les grouper dans un Frame nommé “Robot Parts Objects” et les connecte à un noeud “Join Geometry”.
Déplacer le noeud Group Output assez loin à droite
Cliquer sur le bouton “Run script” (le bouton “Play” du Script Editor.
⚠️
J’ai configuré mon Scripting workspace pour qu’on voit à droite le 3D Viewport ainsi que le Geo Node.
Aussi, il se peut que le système de nodes crée cache les noeuds Group Input et Group Output. Comme les Object Info et le Join Geo sont sélectionnés, vous pouvez les déplacer (G then move with the mouse).
On a terminé avec le script. Revenir au workspace Geometry Nodes.
Connecter la sortie de Join Geometry à l’entrée Group Output. Déconnecter Group Input (on ne veut pas voir le Plane).
Cacher les objects Robot Parts dans l’Outliner, on veut voir le résultat du système de geo nodes seulement.
Faites Play dans le timeline!
Comme les objects sont la géométrie du robot tel qu’animé, l’animation est conservée dans la version geo nodes. Chouette non?
On est prêt pour de la simulation de particules!
Simulation 1 - Onion Skin shadow trail
Ajouter une Simulation Zone et connecter la sortie du Join Geomtery à l’entrée d’un 2e Join geometry qui, lui, se trouve dans la simulation Zone.
Faites Play.
Que constatez-vous?
That’s right! Les geo nodes, sans Simulation zone, sone “stateless”, c’est-à dire que tout est calculé à chaque frame.
Mais avec un simulation Zone, tout d’un coup, les frames précédents sont accumulés! On vient de créer un “Stateful” machine!
Ok, et si on voulait retenir seulement, disons, les 5 frames précédents seulement?
On veut effacer tout ce qui est plus ancien que “n” frames. Comment faire?
On va commencer par garder en mémoire la géométrie courante:
Maintenant, il nous suffit de retirer du Join Geometry de la Simulation Zone, les géométries des frames plus petits qu’une certaine distance du Frame courant.
Ici, on “Delete Geometry” tout ce qui fait partie de “Selection”.
Ce qui aliment le socket Selection du noeud Delete Geometry, c’est le noeud Compare → Less than, qui évalue la valeur de “Frame_courant” (dans le noeud Named Attributed) par rapport au No de frame de l’animation (Scene Time) moins une certaine valeur, ici 4.
Ce que ça fait effectivement, c’est effacer toutes les géométries dont le No de frame est plus petit que le frame courant moins 4.
L’effet est un trail Onion Skin.
Je réalise que je devrais nommer “Frame_courant” à “stored_frame” plutôt, car il n’est plus courant dès qu’il ne l’est plus :) Je le fais de suite:
⚠️
Ah oui, si vous changez quelque chose dans la simulation zone, faut revenir au frame 1 pour recalculer la cache et voir l’effet du chngement.