Com crear una malla 3D amb Aspose.3D a Python
Aspose.3D FOSS per a Python et permet crear geometria 3D completament amb codi: no cal cap eina de modelatge externa. Crees un Mesh, l’omples amb posicions de vèrtex (control_points) i definicions de cares (polygons), adjuntes atributs de vèrtex opcionals com ara normals, i després guardes l’escena en qualsevol format compatible.
Guia pas a pas
Pas 1: Instal·la el paquet
Instal·la Aspose.3D FOSS des de PyPI. No es requereixen extensions natives ni cadena d’eines del compilador.
pip install aspose-3d-fossVerifiqueu la instal·lació:
from aspose.threed import Scene
print("Aspose.3D FOSS ready")Versions de Python compatibles: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Pas 2: Crea una Escena i un Node
Cada malla ha d’estar dins d’un gràfic d’escena. Crea un Scene i afegeix un Node amb nom per contenir la malla:
from aspose.threed import Scene
scene = Scene()
node = scene.root_node.create_child_node("triangle")El nom del node es conserva al fitxer exportat i és útil per a la depuració i la recuperació posterior mitjançant node.get_child("triangle").
Pas 3: Crea un objecte Mesh
Instancia una Mesh amb un nom descriptiu opcional:
from aspose.threed.entities import Mesh
mesh = Mesh("triangle")La malla està inicialment buida: sense vèrtexs, sense polígons. La omples en els passos següents.
Pas 4: Afegeix punts de control (Vèrtexs)
Els punts de control són les posicions dels vèrtexs. Cada vèrtex s’emmagatzema com a Vector4(x, y, z, w) on w=1 indica un punt en l’espai 3D:
from aspose.threed.utilities import Vector4
##Vertex 0: origin
# Note: control_points returns a copy of the internal vertex list.
# Appending to the returned copy discards the vertex silently.
# Use _control_points to mutate the backing list directly.
# This is a known library limitation — a public add_control_point() API is not yet available.
mesh._control_points.append(Vector4(0.0, 0.0, 0.0, 1.0))
##Vertex 1: 1 unit along X
mesh._control_points.append(Vector4(1.0, 0.0, 0.0, 1.0))
##Vertex 2: apex
mesh._control_points.append(Vector4(0.5, 1.0, 0.0, 1.0))
print(f"Vertices added: {len(mesh.control_points)}")Important: mesh.control_points retorna una còpia de la llista interna de vèrtexs (el getter executa list(self._control_points)). En cridar mesh.control_points.append(v) s’afegeix a la còpia, no a la malla, de manera que el vèrtex es descarta silenciosament. Utilitzeu sempre mesh._control_points.append(v) per afegir vèrtexs. Accedir a l’estat privat mitjançant _control_points és una solució alternativa coneguda; la interfície pot canviar en una futura versió de la biblioteca.
Pas 5: Crea cares de polígon
Definiu la topologia de la cara mitjançant índexs de vèrtex. Passeu els índexs de vèrtex a create_polygon(). Tres índexs produeixen un triangle; quatre produeixen un quad:
##Triangle: connect vertices 0 → 1 → 2
mesh.create_polygon(0, 1, 2)
print(f"Polygon count: {mesh.polygon_count}")Per a una malla de quàdrups hauries de passar quatre índexs: mesh.create_polygon(0, 1, 2, 3).
Els índexs han de ser posicions vàlides a control_points (basat en zero, dins del rang). L’ordre d’enrotllament és en sentit antihorari per a normals orientades cap a fora.
Pas 6: Afegeix normals de vèrtex
Les normals dels vèrtexs s’emmagatzemen com a VertexElement adjuntat a la malla. Utilitzeu mesh.create_element() amb VertexElementType.NORMAL, MappingMode.CONTROL_POINT i ReferenceMode.DIRECT:
from aspose.threed.entities import VertexElementType, MappingMode, ReferenceMode, VertexElementNormal
from aspose.threed.utilities import Vector4, FVector4
##Create the normal element (returns VertexElementNormal, a VertexElementFVector subclass)
normals: VertexElementNormal = mesh.create_element(
VertexElementType.NORMAL,
MappingMode.CONTROL_POINT,
ReferenceMode.DIRECT
)
##One normal per vertex: all pointing out of the XY plane (0, 0, 1)
normals.set_data([
FVector4(0, 0, 1, 0), # vertex 0
FVector4(0, 0, 1, 0), # vertex 1
FVector4(0, 0, 1, 0), # vertex 2
])
print("Normal layer attached.")MappingMode.CONTROL_POINT significa una normal per vèrtex. ReferenceMode.DIRECT significa que les dades de normals es llegeixen en el mateix ordre que els punts de control (sense cap buffer d’índex addicional).
Els vectors normals utilitzen FVector4(x, y, z, w) amb w=0 per indicar una direcció en lloc d’una posició. FVector4 és un vector de coma flotant de precisió simple; les dades d’atribut de vèrtex en les subclasses VertexElementFVector fan servir aquest tipus.
Pas 7: Adjunta la malla al node i desa
Afegeix la malla al node, després desa l’escena:
node.add_entity(mesh)
scene.save("triangle.gltf")
print("Saved triangle.gltf")El script complet que funciona (tots els passos combinats):
from aspose.threed import Scene
from aspose.threed.entities import Mesh, VertexElementType, MappingMode, ReferenceMode, VertexElementNormal
from aspose.threed.utilities import Vector3, Vector4, FVector4
scene = Scene()
node = scene.root_node.create_child_node("triangle")
mesh = Mesh("triangle")
##Add 3 vertices (x, y, z, w)
# Use _control_points to mutate the backing list directly (control_points returns a copy)
mesh._control_points.append(Vector4(0.0, 0.0, 0.0, 1.0))
mesh._control_points.append(Vector4(1.0, 0.0, 0.0, 1.0))
mesh._control_points.append(Vector4(0.5, 1.0, 0.0, 1.0))
##Create a triangle polygon
mesh.create_polygon(0, 1, 2)
##Add normals (create_element returns VertexElementNormal, a VertexElementFVector subclass)
normals: VertexElementNormal = mesh.create_element(VertexElementType.NORMAL, MappingMode.CONTROL_POINT, ReferenceMode.DIRECT)
normals.set_data([
FVector4(0, 0, 1, 0),
FVector4(0, 0, 1, 0),
FVector4(0, 0, 1, 0),
])
node.add_entity(mesh)
scene.save("triangle.gltf")Problemes comuns
| Issue | Resolution |
|---|---|
IndexError a create_polygon | Verifiqueu que tots els índexs estiguin dins de range(len(mesh.control_points)). Els índexs comencen a 0. |
| Exportació de malla amb zero vèrtexs | mesh.control_points.append(...) descarta silenciosament els vèrtexs perquè la propietat retorna una còpia. Useu mesh._control_points.append(...) en canvi. |
| El recompte de normals no coincideix amb el recompte de vèrtexs | Quan s’utilitza MappingMode.CONTROL_POINT + ReferenceMode.DIRECT, normals.data ha de tenir exactament len(control_points) entrades. |
| Malla absent del fitxer desat | Confirmeu que node.add_entity(mesh) s’ha cridat abans de scene.save(). Una malla que no està adjuntada a cap node no s’exporta. |
| Ordre d’enrotllament incorrecte (la cara apareix invisible) | L’ordre de vèrtexs en sentit antihorari produeix una normal cap a fora. Inverteix l’ordre dels índexs a create_polygon per girar-la. |
polygon_count retorna 0 | polygon_count llegeix la mateixa llista que polygons. Si create_polygon no s’ha cridat, la llista és buida. |
| Les normals apareixen incorrectes al visualitzador | Assegureu-vos que tots els vectors normals tinguin longitud unitària. Calculeu-los amb n / abs(n) o passeu valors pre-normalitzats. |
Preguntes freqüents
Quina és la diferència entre Vector3 i Vector4 per als punts de control?
control_points emmagatzema objectes Vector4. El component w és la coordenada homogènia: utilitzeu w=1 per a les posicions dels vèrtexs i w=0 per a vectors de direcció com ara normals. Vector3 s’utilitza per a transformacions (traducció, escala) però no per a l’emmagatzematge de geometria.
Puc crear una malla amb quads en lloc de triangles?
Sí. Crida mesh.create_polygon(0, 1, 2, 3) amb quatre índexs per definir un quad. Alguns destinacions de desament (STL, 3MF) requereixen triangles i triangul·laran els quads automàticament. glTF i COLLADA conserven els quads.
Com puc afegir coordenades UV?
Utilitzeu mesh.create_element_uv(TextureMapping.DIFFUSE, MappingMode.POLYGON_VERTEX) per crear un VertexElementUV per al canal difús, i després ompliu la seva llista data amb Vector4 entrades. Les coordenades UV utilitzen x i y; z i w són típicament 0. El primer argument ha de ser una constant TextureMapping (p. ex., TextureMapping.DIFFUSE) que identifica a quin slot de textura pertany la capa UV.
La malla necessita normals per exportar correctament?
No. Les normals són opcionals. Si s’ometen, la majoria de visualitzadors calculen les normals per cara a partir de l’ordre de gir del polígon. Afegir normals per vèrtex explícites produeix una ombreig més suau.
Puc afegir diverses malles a un node?
Sí. Crida node.add_entity(mesh) diverses vegades. Cada crida afegeix una nova entitat a node.entities. Alguns formats poden aplanar diverses entitats en una sola en l’exportació.
Com puc triangul·lar una malla amb tipus de polígons mixtes?
Crida mesh.triangulate() per convertir tots els quads i N-gons en triangles in situ. Això és útil abans de desar a formats que només admeten triangles.