LeCodesdocs

Node

Базовый узел 3D-сцены — пустой трансформ. Mesh, Model, Light и Camera расширяют его, поэтому всё здесь работает и на них. Нативный движок владеет авторитетным трансформом; SDK читает его лениво (физика может переписывать его каждый кадр), и каждый геттер трансформа возвращает свежую копию — см. семантику значений.

Обзор

TypeScript
const pivot = new Node()
pivot.position = [0, 1, -2]
pivot.eulerAngles = [0, 45, 0]          // градусы
pivot.add(Mesh.box({ material: Material.lit({ color: '#38f' }) }))
scene.add(pivot)

setLoop(dt => { pivot.eulerAngles = pivot.eulerAngles.add([0, 90 * dt, 0]) })

Локальный трансформ

TypeScript
node.position = [x, y, z]         // Vec3Like; мировые единицы ≈ метры
node.x = 3                        // скалярные аксессоры: x / y / z
node.quaternion = Quat.fromEuler(0, 90, 0)
node.eulerAngles = [0, 90, 0]     // ГРАДУСЫ
node.scale = 2                    // равномерно или [sx, sy, sz]
node.matrix = Mat4.compose([0, 1, 0], Quat.identity, 1)   // полный локальный TRS

Геттеры возвращают свежие копии Vec3 / Quat / Mat4 — изменение одной никогда не трогает узел:

TypeScript
node.position.x = 3                                    // ✗ тихий no-op (меняет отброшенную копию)
node.x = 3                                             // ✓ сеттер одной оси
const p = node.position; p.y += 1; node.position = p   // ✓ поменять локальную, присвоить обратно

Мировое пространство

TypeScript
node.worldMatrix           // get/set: полный мировой трансформ (установка собирает через родителя)
node.worldPosition         // Vec3 (только чтение)
node.worldQuaternion       // Quat (только чтение)
node.worldEulerAngles      // Vec3, градусы (только чтение)
node.worldScale            // Vec3 (только чтение)
node.forward               // Vec3: ось вперёд узла (−Z) в мировом пространстве (только чтение)

Имя и видимость

TypeScript
node.name = 'door'         // хранится нативно; поиск детей Model сопоставляется по нему
node.visible = false       // скрывает узел (и то, что он рисует)

Иерархия

TypeScript
node.add(...children: Node[]): this                      // сделать детей потомками этого узла
node.setParent(parent: Node | null, worldPositionStays = false): this
node.parent                                              // Node | null
node.children                                            // Node[] (массив-снимок)
node.childCount
node.getChild(index: number): Node | null
node.traverse(callback: (node: Node) => void): void      // этот узел, затем все потомки

С worldPositionStays: true setParent держит узел там, где он в мире (его локальный трансформ пересчитывается); с дефолтным false локальный трансформ сохраняется как есть.

Note

родительство отдельно от членства в сцене — scene.add(node) кладёт узел в набор отрисовки, node.add(child) строит иерархию трансформов. См. Scene.

lookAt

TypeScript
node.lookAt(point: Vec3Like, mode = '-z', ortho = [0, 1, 0]): this
// mode: 'z' | '-z' | 'x' | '-x' | 'y' | '-y' — какая локальная ось смотрит на цель

Ориентирует узел так, чтобы выбранная локальная ось (по умолчанию '-z', ось вперёд) смотрела на точку в мировом пространстве. ortho — подсказка «вверх» для разрешения крена. Масштаб сохраняется.

Аспекты

Возможности прикрепляются как аспекты и чейнятся (см. аспекты):

TypeScript
const ball = Mesh.sphere({ material: Material.lit() })
  .aspect(Shape, { sphere: 0.5 })                 // форма пикинга/коллизии → кликабелен, рейкастится
  .aspect(Physics, { motion: 'dynamic' })         // твёрдое тело → node.physics

См. 3D-физику и формы для Shape, Physics, Trigger, CharacterController.

События

TypeScript
node.addEventListener(channel, callback): void
node.removeEventListener(channel, callback): void
Канал Срабатывает Нужен
click отпускание над узлом аспект Shape (тело-пикер)
touchstart нажатие над узлом; ev.track() начинает перетаскивание аспект Shape
enter / exit контакт физики / перекрытие триггера начались / закончились ((other: Node)) Shape + Physics/Trigger
loopReached зацикленный клип GLB обернулся ((clip: number)) ModelAnimation
completed незацикленный клип GLB завершился ((clip: number)) ModelAnimation
track / untrack AR-якорь получил / потерял трекинг (также node.isTracked) якорь ARScene

Без аспекта Shape узел невидим для тапов — тач увидят только слушатели уровня сцены (с ev.target === null). Объекты событий и перетаскивания ev.track(): События указателя и жесты.

Жизненный цикл

TypeScript
node.destroy(): void      // освобождает нативную сущность; после этого узел непригоден

destroy() — единственный способ разбора, dispose() на узлах нет. Использование уничтоженного узла — неопределённое поведение.

Подводные камни

TypeScript
// ✗ изменение возвращённого значения геттера трансформа
node.position.x += speed * dt      // no-op: геттеры возвращают копии
// ✓
node.x += speed * dt

// ✗ запись трансформа динамического физического тела каждый кадр
setLoop(() => { node.position = target })     // борется с шагом физики
// ✓ управляй телом: node.physics.velocity / applyImpulse (см. physics.md)

Смотрите также