Trabalhar com o gráfico de cena

Trabalhar com o gráfico de cena

Todo o conteúdo 3D em Aspose.3D FOSS para TypeScript vive dentro de um Scene objeto organizado como uma árvore de Node Entender esta hierarquia é a base para construir, carregar e processar qualquer arquivo 3D.

Instalação

Instale o pacote a partir do npm antes de executar qualquer um dos códigos deste guia:

asposefoss/3d is not yet published — build from source until it ships. See the project README for build instructions.

Assegure-se de que o seu tsconfig.json inclui: "module": "commonjs" e a) "moduleResolution": "node" para a resolução correta de importação por sub-pista.

Conceitos de gráfico de cena

O gráfico de cena tem três níveis:

Nível de avaliaçãoClasse:Função
EscenárioSceneContainer de nível superior. rootNode, animationClips, e assetInfo.
Nodo de ligaçãoNodePode ter nós filhos, uma entidade, um transformador e materiais.
Emissão de dadosMesh, Camera, Light, …Conteúdo ligado a um nó. Um nó carrega no máximo uma entidade.

A cadeia de herança dos principais elementos é a seguinte:

A3DObject
  └─ SceneObject
       ├─ Node          (tree structure)
       └─ Entity
            └─ Geometry
                 └─ Mesh   (polygon geometry)

scene.rootNode Não o cria manualmente, você cria nós filhos por baixo dele.

Passo 1: Faça uma cena

import { Scene } from '@aspose/3d';

const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)

Um novo Scene Começa com um nó raiz vazio e sem clipes de animação. Você constrói conteúdo anexando nós filhos.

Passo 2: Adicionar Nodos Filhos

Utilização: createChildNode() O método retorna o novo Node, para poderem fazer chamadas de qualquer nível:

import { Scene } from '@aspose/3d';

const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');

console.log(scene.rootNode.childNodes.length); // 1 (parent)
console.log(parent.childNodes.length);         // 1 (child)

Nomes de nós são strings arbitrários. Os nomes não precisam ser únicos, mas usar nomes significativos torna o código de travessagem mais fácil de depurar.

Passo 3: Criar uma malha e definir vértices

Mesh é a classe de geometria primária. Adicionar posições vértices pressionando Vector4 valores em mesh.controlPoints,Então , liga-me . createPolygon() para definir as faces por índice de vértices:

import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4 } from '@aspose/3d/utilities';

const scene = new Scene();
const child = scene.rootNode.createChildNode('parent').createChildNode('child');

const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3); // quad face using all four vertices

child.entity = mesh;

console.log(mesh.controlPoints.length); // 4
console.log(mesh.polygonCount);         // 1

Vector4 utiliza coordenadas homogéneas: o w componente é: 1 para posições e 0 para vetores de direcção.

Passo 4: Configurar transformações de nó

Cada nó tem um transform propriedade com translation, rotation, e scaling.- Está pronto . translation para mover o nó em relação ao seu núcleo-mãe:

import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';

const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');

const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;

child.transform.translation = new Vector3(2.0, 0.0, 0.0);

globalTransform fornece a matriz de transformação do espaço-mundo (somente leitura), calculada por concatenando todas as transformações ancestrais.

Passo 5: Atravesse a árvore

Escreva uma função recursiva para visitar cada nó. Verifique node.entity e a) node.childNodes em cada nível:

function traverse(node: any, depth = 0): void {
    const indent = '  '.repeat(depth);
    const entityType = node.entity ? node.entity.constructor.name : 'none';
    console.log(`${indent}${node.name} [${entityType}]`);
    for (const child of node.childNodes) {
        traverse(child, depth + 1);
    }
}

traverse(scene.rootNode);

Para a hierarquia criada acima, o resultado será:

 [none]
  parent [none]
    child [Mesh]

O nome do nó raiz é uma cadeia vazia porque Scene cria-o sem argumento de nome.

Sempre proteja o acesso de entidades com uma verificação nula antes de lançar para um tipo específico. Nem todos os nós carregam uma entidade.

Etapa 6: Salvar para o GLTF ou GLB

Utilização: GltfSaveOptions Para controlar o formato de saída. binaryMode = true para produzir um único auto-contido, .glb Arquivo; deixe-o. false para o JSON .gltf + .bin Par de sidecar:

import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');

const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;

child.transform.translation = new Vector3(2.0, 0.0, 0.0);

const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true;                             // write a single .glb file
scene.save('scene.glb', GltfFormat.getInstance(), saveOpts);

console.log('Scene saved to scene.glb');

Passagem . GltfFormat.getInstance() como o argumento de formato, então a biblioteca usa o codificador correto independentemente da extensão do arquivo.

Dicas e melhores práticas

  • Utilização: createChildNode() Em vez de construir Node direta: createChildNode() automaticamente liga a relação pai-filho e registra o nó na árvore.
  • Verificação node.entity antes de aceder às propriedades da entidade: muitos nós (nodes de grupo, ossos, localizadores) não carregam nenhuma entidade. Sempre proteja com uma verificação nula ou instanceof teste.
  • Set (s) translation Em nós filhos, não em vértices de malha: modificação transform.translation Não é destrutivo e composto com as transformações-mãe.
  • Preferência binaryMode = true para o GLB:Uma única: .glb arquivo é mais fácil de distribuir, carregar em navegadores e importar para motores de jogo do que o split .gltf + .bin formato.
  • Via de travessão for...of mais uma vez . childNodes: evitar a indexação numérica; utilizar o iterável directamente para compatibilidade com os futuros.

Problemas comuns

Sintoma:Causa provávelCorreção
child.entity = mesh não tem efeito sobre as exportações.Entidade atribuída ao nível de nó erradoAcompanhar entity para o nó de folhas, não para um nó do grupo
node.entity é sempre nullSó a verificar. rootNode a si mesmaRecorrer a: node.childNodes; rootNode normalmente não tem entidade
Transformação não refletida no visor GLBglobalTransform não actualizadoglobalTransform é calculado em salvar; set transform.translation Antes de ligares. scene.save()
O GLB produz um sistema de gestão separado. .bin Carrinho lateralbinaryMode Descontos para falseSet (s) saveOpts.binaryMode = true

Ver também:

 Português