Comment charger des modèles 3D dans Python
Aspose.3D FOSS pour Python fournit une API simple pour ouvrir des fichiers 3D sans aucune dépendance native. Après avoir chargé un fichier dans un Scene objet, 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
Le Scene class est le conteneur de niveau supérieur pour toutes les données 3D. Importez‑la avec 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 le static Scene.from_file() méthode 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")Alternativement, créez un Scene instance et appelez open(); utile lorsque vous souhaitez passer 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 de Node objets enracinés à 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 Entity objets (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 de Vector4 objets ; x, y, z conserver 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 fin sur la façon dont un fichier OBJ est interprété, passez un ObjLoadOptions instance à 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. Voir le référence API pour une liste complète.
Problèmes courants et solutions
FileNotFoundError lors de l’appel Scene.from_file()
Le chemin doit être absolu ou correctement relatif au répertoire de travail à l’exécution. Utilisez pathlib.Path pour construire 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, pas d’un 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.
Incohérence 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, main gauche vs main droite). Définissez ObjLoadOptions.flip_coordinate_system = True ou appliquez une rotation au root node’s Transform 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). Protégez toujours 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 .mtl matériau ?
Oui, quand ObjLoadOptions.enable_materials = True (par défaut). La bibliothèque recherche le .mtl fichier dans le même répertoire que le .obj fichier. Si le .mtl est manquant, la géométrie est toujours chargée et un avertissement est émis.
Puis-je charger un fichier à partir d’un flux d’octets au lieu d’un chemin ?
Oui. scene.open() accepte tout objet de type fichier avec un .read() méthode en plus d’une chaîne de chemin de fichier. Passez un flux binaire ouvert (par ex., io.BytesIO) directement. Scene.from_file() n’accepte qu’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 data la liste 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 Scene objet est indépendant. Charger des fichiers séparés dans des Scene instances provenant de threads séparés est sûr tant que vous ne partagez pas un seul Scene entre les threads sans verrouillage externe.