Wie man ein 3D-Mesh mit Aspose.3D in Python erstellt
Aspose.3D FOSS für Python ermöglicht es Ihnen, 3D-Geometrie vollständig im Code zu erstellen: kein externes Modellierungswerkzeug erforderlich. Sie erstellen ein Mesh, füllen es mit Scheitelpunktpositionen (control_points) und Flächendefinitionen (polygons), hängen optionale Vertex-Attribute wie Normalen an und speichern dann die Szene in ein beliebiges unterstütztes Format.
Schritt-für-Schritt-Anleitung
Schritt 1: Paket installieren
Installieren Sie Aspose.3D FOSS von PyPI. Keine nativen Erweiterungen oder Compiler‑Toolchain sind erforderlich.
pip install aspose-3d-fossInstallation überprüfen:
from aspose.threed import Scene
print("Aspose.3D FOSS ready")Unterstützte Python-Versionen: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Schritt 2: Erstelle eine Szene und einen Knoten
Jedes Mesh muss innerhalb eines Szenengraphen leben. Erstelle ein Scene und füge ein benanntes Node hinzu, um das Mesh zu halten:
from aspose.threed import Scene
scene = Scene()
node = scene.root_node.create_child_node("triangle")Der Knotenname wird in der exportierten Datei beibehalten und ist nützlich für das Debuggen und den späteren Abruf über node.get_child("triangle").
Schritt 3: Mesh-Objekt erstellen
Instanziieren Sie ein Mesh mit einem optionalen beschreibenden Namen:
from aspose.threed.entities import Mesh
mesh = Mesh("triangle")Das Mesh ist zunächst leer: keine Scheitelpunkte, keine Polygone. Sie füllen es in den folgenden Schritten.
Schritt 4: Kontrollpunkte hinzufügen (Scheitelpunkte)
Steuerpunkte sind die Scheitelpunktpositionen. Jeder Scheitelpunkt wird als Vector4(x, y, z, w) gespeichert, wobei w=1 einen Punkt im 3D‑Raum bezeichnet:
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)}")Wichtig: mesh.control_points gibt eine Kopie der internen Vertex‑Liste zurück (der Getter führt list(self._control_points) aus). Der Aufruf von mesh.control_points.append(v) fügt zur Kopie hinzu, nicht zum Mesh, sodass der Vertex stillschweigend verworfen wird. Verwenden Sie immer mesh._control_points.append(v), um Vertices hinzuzufügen. Der Zugriff auf privaten Zustand über _control_points ist ein bekannter Workaround; die Schnittstelle kann sich in einer zukünftigen Version der Bibliothek ändern.
Schritt 5: Polygonflächen erstellen
Definieren Sie die Flächentopologie mithilfe von Scheitelpunktindizes. Übergeben Sie die Scheitelpunktindizes an create_polygon(). Drei Indizes erzeugen ein Dreieck; vier erzeugen ein Viereck:
##Triangle: connect vertices 0 → 1 → 2
mesh.create_polygon(0, 1, 2)
print(f"Polygon count: {mesh.polygon_count}")Für ein Quad‑Mesh würden Sie vier Indizes übergeben: mesh.create_polygon(0, 1, 2, 3).
Indizes müssen gültige Positionen in control_points sein (0‑basiert, innerhalb des Bereichs). Die Windungsreihenfolge ist gegen den Uhrzeigersinn für nach außen gerichtete Normalen.
Schritt 6: Vertex‑Normalen hinzufügen
Vertex-Normalen werden als VertexElement am Mesh gespeichert. Verwenden Sie mesh.create_element() mit VertexElementType.NORMAL, MappingMode.CONTROL_POINT und 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 bedeutet ein Normalvektor pro Scheitelpunkt. ReferenceMode.DIRECT bedeutet, dass die Normaldaten in derselben Reihenfolge wie die Kontrollpunkte gelesen werden (kein zusätzlicher Indexpuffer).
Normalenvektoren verwenden FVector4(x, y, z, w) mit w=0, um eine Richtung statt einer Position anzugeben. FVector4 ist ein Single‑Precision‑Float‑Vektor; Vertex‑Attributdaten in VertexElementFVector‑Unterklassen verwenden diesen Typ.
Schritt 7: Das Mesh an den Knoten anhängen und speichern
Fügen Sie das Mesh dem Knoten hinzu, dann speichern Sie die Szene:
node.add_entity(mesh)
scene.save("triangle.gltf")
print("Saved triangle.gltf")Das vollständige funktionierende Skript (alle Schritte kombiniert):
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")Häufige Probleme
| Problem | Lösung |
|---|---|
IndexError in create_polygon | Stellen Sie sicher, dass alle Indizes innerhalb von range(len(mesh.control_points)) liegen. Indizes sind 0‑basiert. |
| Mesh-Export mit null Vertices | mesh.control_points.append(...) verwirft stillschweigend Vertices, weil die Eigenschaft eine Kopie zurückgibt. Verwenden Sie stattdessen mesh._control_points.append(...). |
| Anzahl der Normalen stimmt nicht mit der Vertex‑Anzahl überein | Beim Einsatz von MappingMode.CONTROL_POINT + ReferenceMode.DIRECT muss normals.data genau len(control_points) Einträge enthalten. |
| Mesh fehlt in der gespeicherten Datei | Stellen Sie sicher, dass node.add_entity(mesh) vor scene.save() aufgerufen wurde. Ein Mesh, das keinem Knoten zugeordnet ist, wird nicht exportiert. |
| Falsche Windungsreihenfolge (Fläche erscheint unsichtbar) | Eine gegen den Uhrzeigersinn verlaufende Vertex‑Reihenfolge erzeugt eine nach außen gerichtete Normale. Kehren Sie die Indexreihenfolge in create_polygon um, um sie zu invertieren. |
polygon_count returns 0 | polygon_count liest dieselbe Liste wie polygons. Wenn create_polygon nicht aufgerufen wurde, ist die Liste leer. |
| Normalen erscheinen im Viewer falsch | Stellen Sie sicher, dass alle Normalenvektoren eine Länge von 1 haben. Berechnen Sie sie mit n / abs(n) oder übergeben Sie vorab normalisierte Werte. |
Häufig gestellte Fragen
Was ist der Unterschied zwischen Vector3 und Vector4 für Kontrollpunkte?
control_points speichert Vector4 Objekte. Die w Komponente ist die homogene Koordinate: Verwenden Sie w=1 für Scheitelpunktpositionen und w=0 für Richtungsvektoren wie Normalen. Vector3 wird für Transformationen (Translation, Skalierung) verwendet, jedoch nicht für die Geometriespeicherung.
Kann ich ein Mesh mit Quads anstelle von Dreiecken erstellen?
Ja. Rufen Sie mesh.create_polygon(0, 1, 2, 3) mit vier Indizes auf, um ein Quad zu definieren. Einige Speicherziele (STL, 3MF) benötigen Dreiecke und triangulieren Quads automatisch. glTF und COLLADA erhalten Quads.
Wie füge ich UV‑Koordinaten hinzu?
Verwenden Sie mesh.create_element_uv(TextureMapping.DIFFUSE, MappingMode.POLYGON_VERTEX), um ein VertexElementUV für den Diffuse‑Kanal zu erstellen, und füllen Sie dann seine data‑Liste mit Vector4‑Einträgen. UV‑Koordinaten verwenden x und y; z und w sind typischerweise 0. Das erste Argument muss eine TextureMapping‑Konstante sein (z. B. TextureMapping.DIFFUSE), die angibt, welchem Texturslot die UV‑Ebene zugeordnet ist.
Benötigt das mesh Normalen, um korrekt exportiert zu werden?
Nein. Normalen sind optional. Wenn sie weggelassen werden, berechnen die meisten Viewer per-face normals aus der Polygon‑Windungsreihenfolge. Das Hinzufügen expliziter per-vertex normals erzeugt eine glattere Schattierung.
Kann ich mehrere Meshes zu einem Knoten hinzufügen?
Ja. Rufen Sie node.add_entity(mesh) mehrfach auf. Jeder Aufruf fügt eine neue Entität zu node.entities hinzu. Einige Formate können mehrere Entitäten beim Export zu einer zusammenfassen.
Wie trianguliere ich ein Mesh mit gemischten Polygon‑Typen?
Rufen Sie mesh.triangulate() auf, um alle Vierecke und N‑Gons vor Ort in Dreiecke zu konvertieren. Dies ist nützlich, bevor Sie in Formate speichern, die nur Dreiecke unterstützen.