Como Construir uma Malha 3D com Aspose.3D em Python
Aspose.3D FOSS for Python permite que você construa geometria 3D inteiramente em código: nenhuma ferramenta de modelagem externa necessária. Você cria um Mesh, preenche‑o com posições de vértices (control_points) e definições de faces (polygons), anexa atributos opcionais de vértice como normais e, então, salva a cena em qualquer formato suportado.
Guia passo a passo
Etapa 1: Instalar o Pacote
Instale Aspose.3D FOSS a partir do PyPI. Nenhuma extensão nativa ou cadeia de ferramentas do compilador é necessária.
pip install aspose-3d-fossVerifique a instalação:
from aspose.threed import Scene
print("Aspose.3D FOSS ready")Versões do Python suportadas: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.
Etapa 2: Criar uma Cena e um Nó
Cada malha deve viver dentro de um grafo de cena. Crie um Scene e adicione um Node nomeado para conter a malha:
from aspose.threed import Scene
scene = Scene()
node = scene.root_node.create_child_node("triangle")O nome do nó é preservado no arquivo exportado e é útil para depuração e recuperação posterior via node.get_child("triangle").
Etapa 3: Criar um Objeto Mesh
Instancie um Mesh com um nome descritivo opcional:
from aspose.threed.entities import Mesh
mesh = Mesh("triangle")A malha está inicialmente vazia: sem vértices, sem polígonos. Você a preenche nas etapas a seguir.
Etapa 4: Adicionar Pontos de Controle (Vértices)
Os pontos de controle são as posições dos vértices. Cada vértice é armazenado como um Vector4(x, y, z, w) onde w=1 indica um ponto no espaço 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 retorna uma cópia da lista interna de vértices (o getter executa list(self._control_points)). Chamar mesh.control_points.append(v) adiciona à cópia, não à malha, portanto o vértice é descartado silenciosamente. Sempre use mesh._control_points.append(v) para adicionar vértices. Acessar o estado privado via _control_points é uma solução conhecida; a interface pode mudar em uma versão futura da biblioteca.
Etapa 5: Criar faces de polígono
Defina a topologia da face usando índices de vértices. Passe os índices de vértices para create_polygon(). Três índices produzem um triângulo; quatro produzem um quad:
##Triangle: connect vertices 0 → 1 → 2
mesh.create_polygon(0, 1, 2)
print(f"Polygon count: {mesh.polygon_count}")Para uma malha quad, você passaria quatro índices: mesh.create_polygon(0, 1, 2, 3).
Os índices devem ser posições válidas em control_points (baseados em zero, dentro do intervalo). A ordem de enrolamento é no sentido anti‑horário para normais voltadas para fora.
Etapa 6: Adicionar Normais de Vértice
As normais dos vértices são armazenadas como um VertexElement anexado à malha. Use mesh.create_element() com 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 um normal por vértice. ReferenceMode.DIRECT significa que os dados de normal são lidos na mesma ordem dos pontos de controle (sem buffer de índice extra).
Vetores normais usam FVector4(x, y, z, w) com w=0 para indicar uma direção em vez de uma posição. FVector4 é um vetor de ponto flutuante de precisão simples; os dados de atributo de vértice nas subclasses VertexElementFVector usam esse tipo.
Etapa 7: Anexar a Malha ao Nó e Salvar
Adicione a malha ao nó, então salve a cena:
node.add_entity(mesh)
scene.save("triangle.gltf")
print("Saved triangle.gltf")O script completo em funcionamento (todas as etapas combinadas):
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")Problemas Comuns
| Issue | Resolution |
|---|---|
IndexError em create_polygon | Verifique se todos os índices estão dentro de range(len(mesh.control_points)). Os índices são baseados em zero. |
| Exportação de malha com zero vértices | mesh.control_points.append(...) descarta silenciosamente os vértices porque a propriedade retorna uma cópia. Use mesh._control_points.append(...) em vez disso. |
| A contagem de normais não corresponde à contagem de vértices | Ao usar MappingMode.CONTROL_POINT + ReferenceMode.DIRECT, normals.data deve ter exatamente len(control_points) entradas. |
| Malha ausente no arquivo salvo | Confirme que node.add_entity(mesh) foi chamado antes de scene.save(). Uma malha que não está anexada a nenhum nó não é exportada. |
| Ordem de winding incorreta (a face parece invisível) | A ordem de vértices no sentido anti‑horário produz uma normal voltada para fora. Inverta a ordem dos índices em create_polygon para alterá‑la. |
polygon_count retorna 0 | polygon_count lê a mesma lista que polygons. Se create_polygon não foi chamado, a lista está vazia. |
| As normais parecem incorretas no visualizador | Certifique‑se de que todos os vetores normais tenham comprimento unitário. Calcule com n / abs(n) ou passe valores pré‑normalizados. |
Perguntas Frequentes
Qual é a diferença entre Vector3 e Vector4 para pontos de controle?
control_points armazena objetos Vector4. O componente w é a coordenada homogênea: use w=1 para posições de vértices e w=0 para vetores de direção, como normais. Vector3 é usado para transformações (translação, escala), mas não para armazenamento de geometria.
Posso construir uma malha com quads em vez de triângulos?
Sim. Chame mesh.create_polygon(0, 1, 2, 3) com quatro índices para definir um quad. Alguns destinos de salvamento (STL, 3MF) exigem triângulos e triangularão quads automaticamente. glTF e COLLADA preservam quads.
Como adiciono coordenadas UV?
Use mesh.create_element_uv(TextureMapping.DIFFUSE, MappingMode.POLYGON_VERTEX) para criar um VertexElementUV para o canal difuso, então preencha sua lista data com entradas Vector4. As coordenadas UV usam x e y; z e w são tipicamente 0. O primeiro argumento deve ser uma constante TextureMapping (por exemplo, TextureMapping.DIFFUSE) que identifica a qual slot de textura a camada UV pertence.
A malha precisa de normais para exportar corretamente?
Não. Normais são opcionais. Se omitidas, a maioria dos visualizadores calcula normais por face a partir da ordem de winding do polígono. Adicionar normais explícitas por vértice produz sombreamento mais suave.
Posso adicionar várias malhas a um nó?
Sim. Chame node.add_entity(mesh) várias vezes. Cada chamada adiciona uma nova entidade a node.entities. Alguns formatos podem achatar várias entidades em uma única na exportação.
Como triangulo uma malha com tipos de polígonos mistos?
Chame mesh.triangulate() para converter todos os quads e N‑gons em triângulos no local. Isso é útil antes de salvar em formatos que suportam apenas triângulos.