Core API

Overview

Scene, Node, and Mesh form the backbone of every program written against this library. Scene owns the graph and the file I/O; Node provides the tree structure and per-node transform; Mesh is the concrete geometry most nodes carry.


Scene: the root container

A Scene owns a single root_node and the file-level open()/save() operations. Scene also tracks animation_clips and a library of shared objects (materials, for example) that multiple nodes can reference:

from aspose.threed import Scene
from aspose.threed.formats.obj import ObjLoadOptions

scene = Scene()
options = ObjLoadOptions()
options.enable_materials = True
scene.open("model.obj", options)

for node in scene.root_node.child_nodes:
    if node.entity is not None:
        mesh = node.entity
        print(f"{node.name}: {len(mesh.control_points)} vertices, {mesh.polygon_count} polygons")

Scene.from_file() is a shortcut that constructs a Scene and loads it from a path in one call, without a separate LoadOptions object.

Node: the scene-graph tree

Every Node has a parent_node, a list of child_nodes, an optional entity, and an optional material. create_child_node() is the usual way to grow the tree — it creates a new Node, attaches the entity and material you pass, and appends it as a child in one call:

from aspose.threed import Scene
from aspose.threed.entities import Box
from aspose.threed.shading import LambertMaterial
from aspose.threed.utilities import Vector3

scene = Scene()
box = Box(length=2.0, width=1.0, height=1.0)
material = LambertMaterial()
material.diffuse_color = Vector3(0.2, 0.6, 0.9)

scene.root_node.create_child_node("Crate", entity=box.to_mesh(), material=material)
scene.save("crate.gltf")

Each Node also carries a transform (local Transform: translation, scaling, rotation) and a global_transform (the accumulated GlobalTransform in world space), plus get_bounding_box() and evaluate_global_transform() for computing world-space extents.

Mesh: geometry data

Mesh stores geometry as control_points (a flat list of vertex positions) and polygons built from indices into that list via create_polygon(). Reading an imported mesh’s basic shape only needs two properties:

from aspose.threed.entities import Box

box = Box(10, 20, 30)
mesh = box.to_mesh()
print(f"Control points: {len(mesh.control_points)}")

mesh.polygon_count and mesh.polygons give the polygon count and the raw index lists; mesh.vertex_elements holds per-vertex data such as normals and UVs loaded from a file; mesh.deformers holds skin and morph-target data (see Deformers).


Tips and Best Practices

  • Use Scene.from_file() for a quick load when you don’t need format-specific LoadOptions; use Scene() + Scene.open() when you do.
  • A Node’s material and entity are independent — you can change one without touching the other.
  • evaluate_global_transform() computes the accumulated world-space matrix from the node up to the scene root; use it instead of manually combining parent transforms by hand.
  • Mesh.control_points and Mesh.polygons are read/write lists — treat them as live data, not an immutable snapshot.

Common Issues

IssueCauseFix
child_nodes is empty right after Scene()A brand-new Scene has no nodes until you add one or load a fileCall create_child_node() or Scene.open()/Scene.from_file() before inspecting child_nodes
node.material is None after create_child_nodematerial was not passed to create_child_nodePass material=… explicitly, or set node.material afterward
get_bounding_box() looks wrong after moving a nodeThe transform was changed but global state was read before re-evaluatingCall evaluate_global_transform() after changing transform, before relying on world-space bounds

FAQ

Does every Scene start with a populated root_node?

No — root_node always exists, but it has no child_nodes until you add one explicitly or load a file into the scene.

What is the difference between Node.transform and Node.global_transform?

transform is the node’s own local Transform relative to its parent. global_transform (a GlobalTransform) is the accumulated world-space result after combining every ancestor’s transform.

Can a Mesh exist without being attached to a Node?

Yes — box.to_mesh() returns a Mesh you can inspect immediately; it only becomes part of the scene graph once you attach it to a Node’s entity, for example through create_child_node().


API Reference Summary

Class/MethodDescription
Scene()Create an empty scene
Scene.open(file_or_stream, options)Load a file into an existing Scene
Scene.from_file(file_name)Create and load a Scene from a path in one call
Scene.save(file_or_stream, format_or_options)Save the scene
Scene.root_nodeThe root Node of the scene graph
Node.create_child_node(node_name, entity, material)Create and attach a child Node
Node.child_nodes / Node.parent_nodeTree navigation
Node.entity / Node.materialWhat the node carries
Node.transform / Node.global_transformLocal and world-space transforms
Node.evaluate_global_transform(with_geometric_transform)Compute the accumulated world-space matrix
Mesh.control_pointsVertex positions
Mesh.create_polygon()Build a polygon from control-point indices
Mesh.polygon_count / Mesh.polygonsPolygon count and raw index data

See Also