Тени на плоскости: MeshShadowMaterial и плоские тени

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

Для генерации теней в Three.js необходимо учитывать несколько компонентов:

  • Источник света, который поддерживает тени (DirectionalLight, SpotLight, PointLight).
  • Объекты, отбрасывающие тень (castShadow = true).
  • Поверхности, принимающие тень (receiveShadow = true).
  • Настройки рендерера (renderer.shadowMap.enabled = true).

MeshShadowMaterial

MeshShadowMaterial — это специальный материал, который предназначен для отображения только тени объекта. Он не рендерит сам объект, а визуализирует его тень на поверхности. Такой материал особенно полезен для плоских теней, когда нет необходимости показывать объем объекта, но нужна реалистичная тень.

Основные свойства:

  • opacity — регулирует прозрачность тени. Значение от 0 до 1.
  • transparent — обязательно устанавливается в true, если нужно видеть полупрозрачные тени.
  • color — цвет тени (обычно тёмно-серый или чёрный).

Пример создания MeshShadowMaterial:

const shadowMaterial = new THREE.MeshShadowMaterial({
    opacity: 0.5,
    transparent: true
});
const plane = new THREE.Mesh(
    new THREE.PlaneGeometry(10, 10),
    shadowMaterial
);
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true;
scene.add(plane);

В этом примере плоскость будет принимать тень от объектов, но сама по себе будет визуально невидимой за пределами тени.

Плоские тени

Плоские тени создаются с использованием PlaneGeometry и MeshShadowMaterial. В отличие от стандартного теневого рендеринга, плоская тень не учитывает объём объекта, а проецирует его силуэт на поверхность. Это снижает нагрузку на рендеринг и позволяет добиться эффекта “ground contact shadow”, который часто используется в архитектурной визуализации и игрогенерации.

Настройка источника света:

Для корректного отображения теней необходимо:

const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 5);
light.castShadow = true;

light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024;

light.shadow.camera.near = 0.5;
light.shadow.camera.far = 50;
light.shadow.camera.left = -10;
light.shadow.camera.right = 10;
light.shadow.camera.top = 10;
light.shadow.camera.bottom = -10;

scene.add(light);
  • castShadow = true позволяет свету отбрасывать тень.
  • Размер карты теней (mapSize) влияет на качество и резкость тени.
  • Настройка камеры света задаёт область, в которой будет рассчитываться тень.

Объекты, отбрасывающие тень:

const cube = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshStandardMaterial({ color: 0xff0000 })
);
cube.castShadow = true;
scene.add(cube);
  • castShadow = true активирует генерацию тени для объекта.
  • Любой объект с этим флагом будет проецировать тень на плоскость, использующую MeshShadowMaterial.

Примеры комбинаций

  1. Полупрозрачная тень Установка opacity = 0.3 создаёт эффект лёгкой, мягкой тени, которая не делает сцену слишком мрачной. Это часто используется для анимации персонажей, когда нужно, чтобы тень была заметной, но не отвлекала.

  2. Цветные тени Установка свойства color позволяет изменять оттенок тени. Например, для сцены с вечерним освещением можно использовать тёплые оттенки коричневого или тёмно-оранжевого, чтобы тень соответствовала общей атмосфере.

  3. Анимационные тени Плоская тень корректно реагирует на движение объекта. Достаточно обновлять позицию объекта в анимационном цикле, и тень автоматически смещается на плоскости.

function animate() {
    requestAnimationFrame(animate);
    cube.position.x = Math.sin(Date.now() * 0.001) * 2;
    renderer.render(scene, camera);
}
animate();

Особенности и оптимизация

  • MeshShadowMaterial эффективен для сцен с большим количеством объектов, где важно снизить нагрузку на рендеринг. Плоская тень требует меньше вычислений, чем полноценный теневой рендеринг.
  • Тени могут казаться “мягкими” за счёт настройки light.shadow.radius и фильтрации в карте теней.
  • Для реалистичности плоскую тень часто комбинируют с ambient occlusion, чтобы тень не выглядела слишком плоской и графичной.
  • Рекомендуется использовать карты теней с достаточным разрешением, но не чрезмерно высоким, чтобы избежать падений FPS на слабых устройствах.

Взаимодействие с другими материалами

MeshShadowMaterial можно комбинировать с любыми материалами, которые принимают тени. Например, при использовании MeshStandardMaterial или MeshPhysicalMaterial объекты будут корректно отбрасывать тень на плоскость, а плоскость с MeshShadowMaterial будет аккуратно визуализировать силуэт без лишней геометрии.