Карта нормалей (normalMap)

Карта нормалей представляет собой текстуру, которая используется для добавления мелких деталей на поверхность 3D-объекта без увеличения количества полигонов. Она изменяет направление нормалей на каждом пикселе модели, создавая эффект неровностей, выступов, трещин и других деталей освещения. В отличие от bump map, normal map хранит данные о направлении нормалей в RGB-каналах, что позволяет получать более точное и реалистичное освещение.


Принцип работы

RGB-каналы карты нормалей кодируют смещение нормали:

  • Красный канал (R) — смещение по оси X.
  • Зелёный канал (G) — смещение по оси Y.
  • Синий канал (B) — смещение по оси Z.

Значения каналов нормализуются в диапазоне [0, 1] и преобразуются в векторы нормалей. Эти векторы затем используются в шейдерах для расчёта освещения: отражения, бликов и теней, создавая иллюзию сложной геометрии на простой поверхности.


Создание и подключение normalMap в Three.js

Three.js поддерживает карты нормалей через материал MeshStandardMaterial или MeshPhongMaterial. Для подключения нормали необходимо:

  1. Импортировать текстуру:
import * as THREE from 'three';

const loader = new THREE.TextureLoader();
const normalTexture = loader.load('textures/brick_normal.jpg');
  1. Создать материал с использованием normalMap:
const material = new THREE.MeshStandardMaterial({
    color: 0xffffff,
    normalMap: normalTexture,
});
  1. Создать геометрию и меш:
const geometry = new THREE.BoxGeometry(1, 1, 1);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

В результате на кубе визуализируется текстура с видимыми неровностями, которые реагируют на источник света.


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

Three.js позволяет контролировать эффект карты нормалей через свойство normalScale материала. Оно представляет собой вектор типа THREE.Vector2, задающий масштаб смещения по осям X и Y:

material.normalScale.set(1, 1); // стандартный масштаб
material.normalScale.set(0.5, 0.5); // уменьшение эффекта
material.normalScale.set(2, 2); // усиление эффекта

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


Особенности использования

  1. Соответствие UV-развертки — карта нормалей должна точно соответствовать UV-развертке модели. Иначе эффекты будут искажены.
  2. Формат текстуры — чаще всего используют PNG или JPG с 24-битной цветовой глубиной. Для оптимизации можно использовать DDS или KTX2 с поддержкой сжатия.
  3. Освещение и нормали — карты нормалей работают только в сочетании с источниками света. Без света визуальный эффект неровностей не проявляется.
  4. Комплексные материалы — нормальные карты можно комбинировать с другими картами: roughnessMap, metalnessMap, aoMap, создавая фотореалистичные поверхности.

Применение normalMap в пользовательских шейдерах

Для расширенного контроля над эффектом можно использовать ShaderMaterial. В фрагментном шейдере нормаль берётся из текстуры и преобразуется в пространство мировых координат для расчёта освещения:

vec3 normalTex = texture2D(normalMap, vUv).rgb;
normalTex = normalize(normalTex * 2.0 - 1.0); // преобразование из [0,1] в [-1,1]
vec3 finalNormal = normalize(vNormal + normalTex * normalScale);

Такой подход позволяет комбинировать несколько карт нормалей, создавать динамические эффекты, изменять неровности в реальном времени.


Оптимизация и производительность

  • Использовать mipmap и корректное minFilter/magFilter для нормальных карт:
normalTexture.minFilter = THREE.LinearMipMapLinearFilter;
normalTexture.magFilter = THREE.LinearFilter;
  • Размер текстуры: чаще достаточно 1024×1024 или 2048×2048. Большие текстуры повышают качество, но сильно увеличивают потребление видеопамяти.
  • Сжатые форматы (KTX2, Basis) позволяют ускорить загрузку и рендеринг на мобильных устройствах.

Практические советы

  • Комбинировать normalMap с bumpMap или displacementMap можно для достижения гибридного эффекта: нормали создают мелкие детали, displacement – крупные рельефы.
  • Экспериментировать с направлением света и углом обзора: эффект нормалей наиболее заметен при косом освещении.
  • Для органических материалов (камень, дерево, кожа) часто применяют нормальные карты высокой детализации с фотограмметрии.

Итоговые параметры для материала с normalMap

const material = new THREE.MeshStandardMaterial({
    map: texture,
    normalMap: normalTexture,
    normalScale: new THREE.Vector2(1, 1),
    roughness: 0.5,
    metalness: 0.1,
});

Эта конфигурация создаёт реалистичное освещение, глубину и мелкие детали без увеличения числа полигонов, что делает normalMap одним из ключевых инструментов оптимизации и реализма в Three.js.