Comment charger des modèles 3D en Python
Aspose.3D FOSS for Python fournit une API simple pour ouvrir des fichiers 3D sans aucune dépendance native. Après avoir chargé un fichier dans un objet Scene, vous pouvez parcourir la hiérarchie des nœuds et lire les données de géométrie brute de chaque maillage de la scène.
Guide étape par étape
Étape 1 : Installer le package
Installez Aspose.3D FOSS depuis PyPI. Aucune bibliothèque système supplémentaire n’est requise.
pip install aspose-3d-fossVersions Python prises en charge : 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Étape 2 : Importer la classe Scene
La classe Scene est le conteneur de niveau supérieur pour toutes les données 3D. Importez‑la ainsi que toutes les classes d’options de chargement dont vous avez besoin.
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptionsToutes les classes publiques se trouvent sous aspose.threed ou ses sous‑packages (aspose.threed.entities, aspose.threed.formats, aspose.threed.utilities).
Étape 3 : Charger un fichier
Utilisez la méthode statique Scene.from_file() pour ouvrir n’importe quel format pris en charge. La bibliothèque détecte automatiquement le format à partir de l’extension du fichier.
##Automatic format detection
scene = Scene.from_file("model.obj")Sinon, créez une instance Scene et appelez open() ; cela est utile lorsque vous souhaitez transmettre des options de chargement ou gérer les erreurs explicitement :
scene = Scene()
scene.open("model.obj")Les deux méthodes prennent en charge les fichiers OBJ, STL (binaire et ASCII), glTF 2.0 / GLB, COLLADA (DAE) et 3MF.
Étape 4 : Parcourir les nœuds de la scène
Une scène chargée est un arbre d’objets Node dont la racine est scene.root_node. Parcourez récursivement pour trouver tous les nœuds :
from aspose.threed import Scene, Node
scene = Scene.from_file("model.obj")
def walk(node: Node, depth: int = 0) -> None:
indent = " " * depth
print(f"{indent}Node: {node.name!r}")
for child in node.child_nodes:
walk(child, depth + 1)
walk(scene.root_node)Chaque Node peut contenir zéro ou plusieurs objets Entity (maillages, caméras, lumières). Vérifiez node.entities pour voir ce qui est attaché.
Étape 5 : Accéder aux données de sommets et de polygones
Convertissez l’entité d’un nœud en Mesh et lisez ses points de contrôle (positions des sommets) et ses polygones (listes d’indices de faces) :
from aspose.threed import Scene
from aspose.threed.entities import Mesh
scene = Scene.from_file("model.obj")
for node in scene.root_node.child_nodes:
for entity in node.entities:
if isinstance(entity, Mesh):
mesh: Mesh = entity
print(f"Mesh '{node.name}': "
f"{len(mesh.control_points)} vertices, "
f"{len(mesh.polygons)} polygons")
# First vertex position
if mesh.control_points:
v = mesh.control_points[0]
print(f" First vertex: ({v.x:.4f}, {v.y:.4f}, {v.z:.4f})")
# First polygon face (list of control-point indices)
if mesh.polygons:
print(f" First polygon: {mesh.polygons[0]}")mesh.control_points est une liste d’objets Vector4 ; x, y, z portent la position et w est la coordonnée homogène (normalement 1.0).
mesh.polygons est une liste de listes d’entiers, où chaque liste interne est l’ensemble ordonné des indices de points de contrôle pour une face.
Étape 6: Appliquer les options de chargement spécifiques au format
Pour un contrôle granulaire sur la façon dont un fichier OBJ est interprété, passez une instance ObjLoadOptions à scene.open() :
from aspose.threed import Scene
from aspose.threed.formats import ObjLoadOptions
options = ObjLoadOptions()
options.flip_coordinate_system = True # Convert right-hand Y-up to Z-up
options.scale = 0.01 # Convert centimetres to metres
options.enable_materials = True # Load .mtl material file
options.normalize_normal = True # Normalize all normals to unit length
scene = Scene()
scene.open("model.obj", options)Pour les fichiers STL, la classe équivalente est StlLoadOptions. Pour glTF, utilisez GltfLoadOptions. Consultez la référence API pour une liste complète.
Problèmes courants et solutions
FileNotFoundError lors de l’appel de Scene.from_file()
Le chemin doit être absolu ou correctement relatif au répertoire de travail à l’exécution. Utilisez pathlib.Path pour créer des chemins fiables:
from pathlib import Path
from aspose.threed import Scene
path = Path(__file__).parent / "assets" / "model.obj"
scene = Scene.from_file(str(path))mesh.polygons est vide après le chargement d’un fichier STL
Les fichiers STL stockent les triangles sous forme de facettes brutes, et non sous forme de maillage indexé. Après le chargement, les polygones sont synthétisés à partir de ces facettes. Si polygons apparaît vide, vérifiez len(mesh.control_points) ; si le nombre est un multiple de 3, la géométrie est stockée sous forme non indexée et chaque triple consécutif de sommets forme un triangle.
Mauvaise correspondance du système de coordonnées (le modèle apparaît tourné ou reflété)
Différents outils utilisent des conventions différentes (Y-up vs Z-up, gauche vs droite). Définissez ObjLoadOptions.flip_coordinate_system = True ou appliquez une rotation au Transform du nœud racine après le chargement.
AttributeError: 'NoneType' object has no attribute 'polygons'
La liste d’entités d’un nœud peut contenir des entités non maillage (caméras, lumières). Toujours protéger avec isinstance(entity, Mesh) avant le transtypage.
Foire aux questions (FAQ)
Quels formats 3D puis-je charger ?
OBJ (Wavefront), STL (binaire et ASCII), glTF 2.0 / GLB, COLLADA (DAE), et 3MF. La tokenisation des fichiers FBX est partiellement prise en charge mais l’analyse complète n’est pas encore terminée.
Le chargement d’un fichier OBJ charge-t-il également le matériau .mtl ?
Oui, lorsque ObjLoadOptions.enable_materials = True (par défaut). La bibliothèque recherche le fichier .mtl dans le même répertoire que le fichier .obj. Si le .mtl est manquant, la géométrie est toujours chargée et un avertissement est émis.
Puis-je charger un fichier depuis un flux d’octets au lieu d’un chemin ?
Oui. scene.open() accepte tout objet de type fichier avec une méthode .read() en plus d’une chaîne de chemin de fichier. Passez directement un flux binaire ouvert (par ex., io.BytesIO). Scene.from_file() n’accepte que une chaîne de chemin de fichier.
Comment obtenir les normales de surface ?
Après le chargement, vérifiez mesh.get_element(VertexElementType.NORMAL). Cela renvoie un VertexElementNormal dont la liste data contient un vecteur normal par référence, mappé selon mapping_mode et reference_mode.
from aspose.threed.entities import Mesh, VertexElementType
normals = mesh.get_element(VertexElementType.NORMAL)
if normals:
print(normals.data[0]) # First normal vectorLa bibliothèque est‑elle thread-safe pour le chargement de plusieurs fichiers simultanément ?
Chaque objet Scene est indépendant. Charger des fichiers distincts dans des instances distinctes de Scene à partir de threads séparés est sûr tant que vous ne partagez pas un seul Scene entre les threads sans verrouillage externe.