Динамическое добавление и удаление объектов

Three.js предоставляет мощный механизм для динамического добавления, удаления и управления 3D-объектами в сцене. Основой является сцена (THREE.Scene), которая хранит все объекты, освещение и камеры. Любой объект, унаследованный от THREE.Object3D (например, THREE.Mesh, THREE.Group), может быть добавлен или удалён из сцены в любое время.

Добавление объектов

Для добавления объекта используется метод scene.add(obj). Пример создания и добавления куба:

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);

scene.add(cube);

Ключевые моменты:

  • Любой объект, который добавляется в сцену, автоматически участвует в рендеринге.
  • Можно добавлять объекты как отдельно, так и в группы (THREE.Group), что удобно для управления множеством объектов одновременно.
  • Добавление объектов динамически не требует пересоздания сцены или рендера заново — достаточно вызвать renderer.render(scene, camera).

Удаление объектов

Удаление объекта выполняется через scene.remove(obj). Однако для корректного управления памятью важно также очищать геометрию и материалы:

scene.remove(cube);
cube.geometry.dispose();
cube.material.dispose();

Почему это важно: WebGL использует GPU-память для хранения геометрии и текстур. Если не вызвать dispose(), память не освобождается, что может привести к падению производительности при длительной работе приложения.

Динамическое обновление объектов

Объекты могут изменять своё состояние на лету:

  • Позиция: obj.position.set(x, y, z)
  • Вращение: obj.rotation.x += 0.01
  • Масштаб: obj.scale.set(sx, sy, sz)
  • Материал: можно менять цвет, прозрачность или текстуру

Пример анимации куба:

function animate() {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
}
animate();

Использование групп для управления множеством объектов

THREE.Group позволяет объединять объекты и управлять ими как единым целым. Это особенно полезно при создании динамических сцен с большим количеством элементов:

const group = new THREE.Group();

for (let i = 0; i < 10; i++) {
    const sphere = new THREE.Mesh(
        new THREE.SphereGeometry(0.5, 16, 16),
        new THREE.MeshStandardMaterial({ color: Math.random() * 0xffffff })
    );
    sphere.position.set(i, 0, 0);
    group.add(sphere);
}

scene.add(group);

Удаление всех объектов группы:

group.children.forEach(child => {
    child.geometry.dispose();
    child.material.dispose();
});
scene.remove(group);

Оптимизация динамических сцен

  1. Повторное использование геометрии и материалов. Если несколько объектов используют одинаковую геометрию, её можно создать один раз и назначать разным мешам. Это уменьшает нагрузку на GPU.
  2. Удаление невидимых объектов. Если объект больше не нужен, удаление с последующим dispose() предотвращает утечки памяти.
  3. Ленивая загрузка ресурсов. Текстуры, модели и шейдеры лучше загружать по мере необходимости, а не все сразу.
  4. Управление группами. Использование THREE.Group позволяет манипулировать множеством объектов одновременно, что упрощает анимацию и удаление.

Примеры динамических сценариев

  • Появление объектов по событию: добавление новых элементов при клике или коллизии.
  • Удаление объектов при достижении определённого состояния: например, исчезновение частиц после завершения анимации.
  • Перемещение объектов между группами: это позволяет менять логику сцены без пересоздания объектов.

Работа с массивами объектов

Для динамического управления большим количеством элементов удобно хранить их в массиве:

const cubes = [];

for (let i = 0; i < 50; i++) {
    const cube = new THREE.Mesh(
        new THREE.BoxGeometry(1, 1, 1),
        new THREE.MeshStandardMaterial({ color: Math.random() * 0xffffff })
    );
    cube.position.set(Math.random() * 10, Math.random() * 10, Math.random() * 10);
    scene.add(cube);
    cubes.push(cube);
}

// Удаление всех кубов
cubes.forEach(c => {
    scene.remove(c);
    c.geometry.dispose();
    c.material.dispose();
});
cubes.length = 0;

Взаимодействие с физикой и событиями

Динамическое добавление объектов тесно связано с системами коллизий и взаимодействия:

  • Подключение Raycaster позволяет обнаруживать объекты, добавленные на лету.
  • Интеграция с физическими движками (например, Cannon.js или Ammo.js) требует синхронизации состояния объекта в Three.js и физическом движке при добавлении или удалении.

Итоговое понимание

Динамическое управление объектами в Three.js — это базовый инструмент для создания интерактивных 3D-сцен. Оно требует внимания к управлению памятью, правильного использования геометрии и материалов, а также структуры сцены через группы и массивы. Эффективное применение этих подходов позволяет создавать сложные сцены с сотнями и тысячами объектов без снижения производительности.