Jak zbudować siatkę 3D przy użyciu Aspose.3D w Pythonie

Jak zbudować siatkę 3D przy użyciu Aspose.3D w Pythonie

Aspose.3D FOSS for Python pozwala tworzyć geometrię 3D całkowicie w kodzie: nie jest wymagane żadne zewnętrzne narzędzie do modelowania. Tworzysz Mesh, wypełniasz go pozycjami wierzchołków (control_points) i definicjami ścian (polygons), dołączasz opcjonalne atrybuty wierzchołków, takie jak normalne, a następnie zapisujesz scenę w dowolnym obsługiwanym formacie.

Przewodnik krok po kroku

Krok 1: Zainstaluj pakiet

Zainstaluj Aspose.3D FOSS z PyPI. Nie są wymagane natywne rozszerzenia ani łańcuch narzędzi kompilatora.

pip install aspose-3d-foss

Sprawdź instalację:

from aspose.threed import Scene
print("Aspose.3D FOSS ready")

Obsługiwane wersje Pythona: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.


Krok 2: Utwórz scenę i węzeł

Każda siatka musi znajdować się wewnątrz grafu sceny. Utwórz Scene i dodaj nazwany Node, aby przechowywać siatkę:

from aspose.threed import Scene

scene = Scene()
node = scene.root_node.create_child_node("triangle")

Nazwa węzła jest zachowywana w wyeksportowanym pliku i jest przydatna do debugowania oraz późniejszego odczytu za pomocą node.get_child("triangle").


Krok 3: Utwórz obiekt siatki

Utwórz instancję Mesh z opcjonalną opisową nazwą:

from aspose.threed.entities import Mesh

mesh = Mesh("triangle")

Siatka jest początkowo pusta: brak wierzchołków, brak wielokątów. Wypełniasz ją w następujących krokach.


Krok 4: Dodaj punkty kontrolne (wierzchołki)

Punkty kontrolne to pozycje wierzchołków. Każdy wierzchołek jest przechowywany jako Vector4(x, y, z, w), gdzie w=1 wskazuje punkt w przestrzeni 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)}")

Ważne: mesh.control_points zwraca kopię wewnętrznej listy wierzchołków (getter wykonuje list(self._control_points)). Wywołanie mesh.control_points.append(v) dodaje do kopii, a nie do siatki, więc wierzchołek jest cicho odrzucany. Zawsze używaj mesh._control_points.append(v) do dodawania wierzchołków. Dostęp do prywatnego stanu za pomocą _control_points jest znanym obejściem; interfejs może ulec zmianie w przyszłej wersji biblioteki.


Krok 5: Utwórz powierzchnie wielokątów

Zdefiniuj topologię twarzy przy użyciu indeksów wierzchołków. Przekaż indeksy wierzchołków do create_polygon(). Trzy indeksy tworzą trójkąt; cztery tworzą czworokąt:

##Triangle: connect vertices 0 → 1 → 2
mesh.create_polygon(0, 1, 2)

print(f"Polygon count: {mesh.polygon_count}")

Dla siatki czworokątnej należy przekazać cztery indeksy: mesh.create_polygon(0, 1, 2, 3).

Indeksy muszą być prawidłowymi pozycjami w control_points (0‑bazowe, w zakresie). Kierunek wiązania jest przeciwny do ruchu wskazówek zegara dla normalnych skierowanych na zewnątrz.


Krok 6: Dodaj normalne wierzchołków

Normalne wierzchołków są przechowywane jako VertexElement dołączony do siatki. Użyj mesh.create_element() z 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 oznacza jedną normalną na wierzchołek. ReferenceMode.DIRECT oznacza, że dane normalnych są odczytywane w tej samej kolejności co punkty kontrolne (bez dodatkowego bufora indeksów).

Wektory normalne używają FVector4(x, y, z, w) wraz z w=0, aby wskazać kierunek, a nie pozycję. FVector4 jest wektorem zmiennoprzecinkowym pojedynczej precyzji; dane atrybutów wierzchołków w podklasach VertexElementFVector używają tego typu.


Krok 7: Dołącz siatkę do węzła i zapisz

Dodaj siatkę do węzła, a następnie zapisz scenę:

node.add_entity(mesh)

scene.save("triangle.gltf")
print("Saved triangle.gltf")

Pełny działający skrypt (wszystkie kroki połączone):

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")

Typowe problemy

ProblemRozwiązanie
IndexError w create_polygonSprawdź, czy wszystkie indeksy mieszczą się w range(len(mesh.control_points)). Indeksy są zerowe.
Eksport siatki z zerową liczbą wierzchołkówmesh.control_points.append(...) cicho odrzuca wierzchołki, ponieważ właściwość zwraca kopię. Zamiast tego użyj mesh._control_points.append(...).
Liczba wektorów normalnych nie zgadza się z liczbą wierzchołkówPodczas używania MappingMode.CONTROL_POINT + ReferenceMode.DIRECT, normals.data musi mieć dokładnie len(control_points) wpisów.
Siatka brakująca w zapisanym plikuUpewnij się, że node.add_entity(mesh) zostało wywołane przed scene.save(). Siatka nie podłączona do żadnego węzła nie jest eksportowana.
Nieprawidłowy porządek wierzchołków (ściana niewidoczna)Porządek wierzchołków przeciwnie do ruchu wskazówek zegara generuje normalną skierowaną na zewnątrz. Odwróć kolejność indeksów w create_polygon, aby to zmienić.
polygon_count zwraca 0polygon_count odczytuje tę samą listę co polygons. Jeśli create_polygon nie zostało wywołane, lista jest pusta.
Wektory normalne wyglądają niepoprawnie w przeglądarceUpewnij się, że wszystkie wektory normalne mają długość jednostkową. Oblicz je za pomocą n / abs(n) lub przekaż wstępnie znormalizowane wartości.

Najczęściej zadawane pytania

Jaka jest różnica między Vector3 a Vector4 dla punktów kontrolnych?

control_points przechowuje obiekty Vector4. Składnik w jest współrzędną jednorodną: użyj w=1 do pozycji wierzchołków i w=0 do wektorów kierunkowych, takich jak normalne. Vector3 jest używany do przekształceń (przesunięcie, skalowanie), ale nie do przechowywania geometrii.

Czy mogę zbudować siatkę z czworokątów zamiast trójkątów?

Tak. Wywołaj mesh.create_polygon(0, 1, 2, 3) z czterema indeksami, aby zdefiniować czworokąt. Niektóre cele zapisu (STL, 3MF) wymagają trójkątów i automatycznie triangulują czworokąty. glTF i COLLADA zachowują czworokąty.

Jak dodać współrzędne UV?

Użyj mesh.create_element_uv(TextureMapping.DIFFUSE, MappingMode.POLYGON_VERTEX), aby utworzyć VertexElementUV dla kanału dyfuzyjnego, a następnie wypełnij jego listę data wpisami Vector4. Współrzędne UV używają x i y; z i w są zazwyczaj 0. Pierwszy argument musi być stałą TextureMapping (np. TextureMapping.DIFFUSE) określającą, do którego slotu tekstury należy warstwa UV.

Czy siatka wymaga wektorów normalnych, aby poprawnie eksportować?

Nie. Normals są opcjonalne. Jeśli pominięte, większość przeglądarek oblicza per-face normals z kolejności wierzchołków wielokąta. Dodanie jawnych per-vertex normals powoduje płynniejsze cieniowanie.

Czy mogę dodać wiele siatek do jednego węzła?

Tak. Wywołaj node.add_entity(mesh) wielokrotnie. Każde wywołanie dodaje nową jednostkę do node.entities. Niektóre formaty mogą spłaszczyć wiele jednostek w jedną przy eksporcie.

Jak trójkątować siatkę z mieszanymi typami wielokątów?

Wywołaj mesh.triangulate(), aby w miejscu przekształcić wszystkie czworokąty i N‑gony w trójkąty. Jest to przydatne przed zapisem do formatów, które obsługują wyłącznie trójkąty.

 Polski