Praca z grafem sceny

Praca z grafem sceny

Każda scena 3D w Aspose.3D dla .NET jest zorganizowana jako drzewo Node obiektów. Scene.RootNode jest korzeniem tego drzewa i każdy element geometrii, materiału i przekształcenia znajduje się pod nim jako dziecko lub potomek.


Tworzenie sceny i dostęp do węzła korzenia

Scene inicjalizuje się automatycznie z węzłem głównym o nazwie "RootNode":

using Aspose.ThreeD;

var scene = new Scene();
Node root = scene.RootNode; // always "RootNode"

Dodawanie węzłów potomnych

Call CreateChildNode() na dowolnym węźle, aby dodać dziecko. Metoda ma trzy powszechnie używane przeciążenia:

using Aspose.ThreeD;
using Aspose.ThreeD.Entities;

var scene = new Scene();
Node root = scene.RootNode;

// 1. Named node with no entity — useful as a pivot or transform container
Node pivot = root.CreateChildNode("pivot");

// 2. Named node with an entity
var box = new Box(2, 2, 2);
Node boxNode = root.CreateChildNode("box", box);

// 3. Named node with entity and material
var mat = new Aspose.ThreeD.Shading.PhongMaterial("red");
mat.Diffuse = new Vector4(0.8, 0.2, 0.2, 1.0);
Node decorated = pivot.CreateChildNode("red_box", box, mat);

Aby dołączyć węzeł utworzony osobno, użyj AddChildNode():

var detached = new Node("standalone");
root.AddChildNode(detached);

Odpytywanie węzłów potomnych

Znajdź bezpośredniego potomka po nazwie lub indeksie, lub iteruj wszystkie bezpośrednie potomki:

// By name — returns null if no direct child has that name
Node? found = root.GetChild("box");
if (found != null)
    Console.WriteLine("Found: " + found.Name);

// By index
Node first = root.GetChild(0);

// Iterate all direct children
foreach (Node child in root.ChildNodes)
    Console.WriteLine(child.Name);

GetChild(string name) przeszukuje tylko bezpośrednie dzieci, nie pełne poddrzewo. Użyj rekurencyjnego pomocnika lub Accept() aby przeszukać całe drzewo.


Przechodzenie pełnego drzewa

Aby wykonać pełne przejście wgłąb, iteruj ChildNodes rekursywnie:

static void Walk(Node node, int depth = 0)
{
    Console.WriteLine(new string(' ', depth * 2) + node.Name);
    foreach (var child in node.ChildNodes)
        Walk(child, depth + 1);
}

Walk(scene.RootNode);

Dla przeglądania z wczesnym zakończeniem, node.Accept(NodeVisitor) jest dostępne i wywołuje odwiedzającego na każdym potomku, aż odwiedzający zwróci false.


Używanie Group do organizacji powiązanych obiektów

Group jest encją kontenera, która logicznie organizuje węzły bez dodawania geometrii. Dołącz ją do węzła, którego dzieci reprezentują jednostkę logiczną:

using Aspose.ThreeD;
using Aspose.ThreeD.Entities;

var scene = new Scene();

// A group node for all furniture in a room
var furnitureGroup = new Group("furniture");
Node roomNode = scene.RootNode.CreateChildNode("living_room", furnitureGroup);

// Child nodes under the group node
Node sofaNode  = roomNode.CreateChildNode("sofa",         new Box(3, 1, 1));
Node tableNode = roomNode.CreateChildNode("coffee_table", new Box(2, 0.5, 1));

Przemieszczanie roomNode transformuje wszystkie meble razem, ponieważ dzieci dziedziczą jego Transform.


Kontrola widoczności i wykluczanie z eksportu

Węzły mogą być ukryte lub wykluczone z eksportu bez usuwania ich z hierarchii:

Node ground = scene.RootNode.CreateChildNode("ground_plane", new Box(100, 0.1, 100));
ground.Visible = false;       // hidden in viewport / renderer

Node helperNode = scene.RootNode.CreateChildNode("debug_arrow", new Box());
helperNode.Excluded = true;   // omitted from all export operations

Visible = false jest wskazówką wyświetlania. Excluded = true zapobiega pojawieniu się węzła w wyeksportowanych plikach, niezależnie od formatu.


Dołączanie wielu encji do jednego węzła

Węzeł ma podstawowy entity (Entity property), ale może przechowywać dodatkowe encje poprzez AddEntity(). Jest to przydatne, gdy różne części siatki współdzielą pojedynczą transformację:

var bodyMesh  = new Mesh("body");
var wheelMesh = new Mesh("wheel");

Node carNode = scene.RootNode.CreateChildNode("car");
carNode.AddEntity(bodyMesh);
carNode.AddEntity(wheelMesh);

// Retrieve all entities on this node
foreach (Entity ent in carNode.Entities)
    Console.WriteLine(ent.GetType().Name + ": " + ent.Name);

Scalanie węzłów

Merge() przenosi wszystkie dzieci, encje i materiały z węzła źródłowego do węzła docelowego. Węzeł źródłowy pozostaje pusty:

Node lod0 = scene.RootNode.CreateChildNode("lod0");
lod0.CreateChildNode("mesh_high", new Box(1, 1, 1));

Node lod1 = scene.RootNode.CreateChildNode("lod1");
lod1.CreateChildNode("mesh_low", new Box(1, 1, 1));

// Consolidate lod0 children into lod1
lod1.Merge(lod0);
// lod1 now has both mesh_high and mesh_low; lod0 is empty

Kolejne kroki


Szybkie odniesienie do API

CzłonekOpis
scene.RootNodeKorzeń drzewa sceny; zawsze obecny po new Scene()
node.CreateChildNode(name)Utwórz nazwany węzeł potomny bez encji
node.CreateChildNode(name, entity)Utwórz nazwany węzeł potomny z encją
node.CreateChildNode(name, entity, material)Utwórz nazwany węzeł potomny z encją i materiałem
node.AddChildNode(node)Dołącz osobno skonstruowany Node
node.GetChild(name)Znajdź bezpośredniego potomka po nazwie; zwraca null jeśli nie znaleziono
node.GetChild(index)Pobierz bezpośredniego potomka pod danym indeksem
node.ChildNodesIList<Node> wszystkich bezpośrednich dzieci
node.Accept(visitor)Przejdź po tym węźle i wszystkich potomkach w kolejności głębokościowej
node.AddEntity(entity)Dołącz dodatkową encję do węzła
node.EntitiesIList<Entity> wszystkich encji na tym węźle
node.VisiblePokaż lub ukryj węzeł
node.ExcludedDołącz lub wyklucz węzeł z eksportu
node.Merge(other)Przenieś wszystkie dzieci i encje z other do tego węzła
new Group(name)Encja kontenerowa do logicznego grupowania węzłów potomnych
 Polski