Come creare una mesh 3D con Aspose.3D in Python
Aspose.3D FOSS per Python ti consente di creare geometria 3D interamente tramite codice: non è necessario alcun strumento di modellazione esterno. Crei un Mesh, lo popoli con le posizioni dei vertici (control_points) e le definizioni delle facce (polygons), aggiungi attributi opzionali dei vertici come le normali, quindi salvi la scena in qualsiasi formato supportato.
Guida passo-passo
Passo 1: Installa il pacchetto
Installa Aspose.3D FOSS da PyPI. Non sono richieste estensioni native o toolchain del compilatore.
pip install aspose-3d-fossVerifica l’installazione:
from aspose.threed import Scene
print("Aspose.3D FOSS ready")Versioni Python supportate: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Passo 2: Crea una scena e un nodo
Ogni mesh deve vivere all’interno di un grafo della scena. Crea un Scene e aggiungi un Node con nome per contenere la mesh:
from aspose.threed import Scene
scene = Scene()
node = scene.root_node.create_child_node("triangle")Il nome del nodo viene conservato nel file esportato ed è utile per il debug e per il successivo recupero tramite node.get_child("triangle").
Passo 3: Crea un oggetto Mesh
Istanzia un Mesh con un nome descrittivo opzionale:
from aspose.threed.entities import Mesh
mesh = Mesh("triangle")La mesh è inizialmente vuota: nessun vertice, nessun poligono. La popoliamo nei passaggi seguenti.
Passo 4: Aggiungi punti di controllo (Vertici)
I punti di controllo sono le posizioni dei vertici. Ogni vertice è memorizzato come Vector4(x, y, z, w) dove w=1 indica un punto nello spazio 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)}")Importante: mesh.control_points restituisce una copia dell’elenco interno dei vertici (il getter esegue list(self._control_points)). Chiamare mesh.control_points.append(v) aggiunge alla copia, non alla mesh, quindi il vertice viene silenziosamente scartato. Usa sempre mesh._control_points.append(v) per aggiungere vertici. Accedere allo stato privato tramite _control_points è una soluzione alternativa nota; l’interfaccia potrebbe cambiare in una futura versione della libreria.
Passo 5: Crea facce poligonali
Definisci la topologia della faccia usando gli indici dei vertici. Passa gli indici dei vertici a create_polygon(). Tre indici producono un triangolo; quattro producono un quad:
##Triangle: connect vertices 0 → 1 → 2
mesh.create_polygon(0, 1, 2)
print(f"Polygon count: {mesh.polygon_count}")Per una mesh quad dovresti passare quattro indici: mesh.create_polygon(0, 1, 2, 3).
Gli indici devono essere posizioni valide in control_points (basate su zero, entro l’intervallo). L’ordine di avvolgimento è in senso antiorario per le normali rivolte verso l’esterno.
Passo 6: Aggiungi le Normali dei Vertici
Le normali dei vertici sono memorizzate come VertexElement allegata alla mesh. Usa mesh.create_element() con VertexElementType.NORMAL, MappingMode.CONTROL_POINT e 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 normale per vertice. ReferenceMode.DIRECT significa che i dati delle normali vengono letti nello stesso ordine dei punti di controllo (senza buffer di indice aggiuntivo).
I vettori normali usano FVector4(x, y, z, w) con w=0 per indicare una direzione piuttosto che una posizione. FVector4 è un vettore float a precisione singola; i dati degli attributi dei vertici nelle sottoclassi VertexElementFVector utilizzano questo tipo.
Passo 7: Collegare la Mesh al Nodo e Salvare
Aggiungi la mesh al nodo, quindi salva la scena:
node.add_entity(mesh)
scene.save("triangle.gltf")
print("Saved triangle.gltf")Lo script completo funzionante (tutti i passaggi combinati):
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")Problemi comuni
| Problema | Risoluzione |
|---|---|
IndexError in create_polygon | Verificare che tutti gli indici siano entro range(len(mesh.control_points)). Gli indici sono a base 0. |
| Mesh esportata con zero vertici | mesh.control_points.append(...) elimina silenziosamente i vertici perché la proprietà restituisce una copia. Utilizzare mesh._control_points.append(...) invece. |
| Il conteggio delle normali non corrisponde al conteggio dei vertici | Quando si utilizza MappingMode.CONTROL_POINT + ReferenceMode.DIRECT, normals.data deve contenere esattamente len(control_points) voci. |
| Mesh mancante dal file salvato | Confermare che node.add_entity(mesh) sia stato chiamato prima di scene.save(). Una mesh non collegata a nessun nodo non viene esportata. |
| Ordine di avvolgimento errato (la faccia appare invisibile) | Un ordine dei vertici in senso antiorario genera una normale rivolta verso l’esterno. Invertire l’ordine degli indici in create_polygon per capovolgerlo. |
polygon_count returns 0 | polygon_count legge la stessa lista di polygons. Se create_polygon non è stato chiamato, la lista è vuota. |
| Le normali appaiono errate nel visualizzatore | Assicurarsi che tutti i vettori normali abbiano lunghezza unitaria. Calcolarli con n / abs(n) o fornire valori pre‑normalizzati. |
Domande Frequenti
Qual è la differenza tra Vector3 e Vector4 per i punti di controllo?
control_points memorizza oggetti Vector4. Il componente w è la coordinata omogenea: usa w=1 per le posizioni dei vertici e w=0 per i vettori di direzione come le normali. Vector3 è usato per le trasformazioni (traslazione, scala) ma non per l’archiviazione della geometria.
Posso creare una mesh con quad invece di triangoli?
Sì. Chiama mesh.create_polygon(0, 1, 2, 3) con quattro indici per definire un quad. Alcuni formati di salvataggio (STL, 3MF) richiedono triangoli e triangoleranno automaticamente i quad. glTF e COLLADA preservano i quad.
Come aggiungo le coordinate UV?
Usa mesh.create_element_uv(TextureMapping.DIFFUSE, MappingMode.POLYGON_VERTEX) per creare un VertexElementUV per il canale diffuso, quindi popola la sua lista data con Vector4 voci. Le coordinate UV usano x e y; z e w sono tipicamente 0. Il primo argomento deve essere una costante TextureMapping (ad esempio, TextureMapping.DIFFUSE) che identifica a quale slot di texture appartiene lo strato UV.
La mesh ha bisogno di normali per esportare correttamente?
No. Le normali sono opzionali. Se omesse, la maggior parte dei visualizzatori calcola le normali per faccia dall’ordine di avvolgimento del poligono. L’aggiunta di normali per vertice esplicite produce un’ombreggiatura più fluida.
Posso aggiungere più mesh a un nodo?
Sì. Chiama node.add_entity(mesh) più volte. Ogni chiamata aggiunge una nuova entità a node.entities. Alcuni formati potrebbero appiattire più entità in una sola durante l’esportazione.
Come triangolo una mesh con tipi di poligono misti?
Chiama mesh.triangulate() per convertire tutti i quadrilateri e i N-gon in triangoli in loco. Questo è utile prima di salvare in formati che supportano solo triangoli.