Вычисление нормалей: computeVertexNormals

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


Основные концепции нормалей

  • Нормаль поверхности — это вектор, перпендикулярный плоскости полигона, который указывает направление “наружу” объекта.
  • Нормаль вершины — усреднённый вектор нормалей всех полигонами, которые касаются данной вершины. Используется для сглаживания освещения на объекте.
  • Сглаживание (Smooth shading) достигается именно за счёт вычисления вершинных нормалей вместо нормалей граней (Face normals), что позволяет свету плавно переходить между полигонами.

Синтаксис и применение

Метод вызывается на объекте геометрии:

geometry.computeVertexNormals();
  • geometry — объект типа THREE.BufferGeometry или устаревший THREE.Geometry.
  • После вызова этого метода каждая вершина геометрии получает нормаль, которая учитывает соседние грани.

Пример использования:

const geometry = new THREE.BoxGeometry(1, 1, 1);

// Если были изменения вершин:
geometry.attributes.position.array[0] += 0.1; 

// Пересчёт нормалей после изменения формы:
geometry.computeVertexNormals();

Метод полезен при динамических моделях, когда вершины изменяются в реальном времени. Без пересчёта нормалей освещение будет выглядеть некорректно, с артефактами и резкими переходами света.


Математика вычисления

Процесс вычисления нормалей для вершины состоит из следующих шагов:

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

    [ = (_1 - _0) (_2 - _0)]

    где (_0, _1, _2) — вершины треугольника.

  2. Агрегация нормалей для вершин Каждая вершина получает сумму нормалей всех граней, к которым она принадлежит.

  3. Нормализация После суммирования нормаль нормализуется до единичной длины:

    [ *{vertex} = ]

Эта операция создаёт эффект гладкого перехода света между гранями.


Особенности и нюансы

  • Треугольники и полигоны: метод работает только для треугольных полигонов. Если геометрия содержит полигоны с более чем 3 вершинами, Three.js автоматически триангулирует их перед вычислением.
  • Изменение вершин: после любого изменения позиции вершин, масштабирования или деформации требуется повторно вызывать computeVertexNormals.
  • Геометрии с индексами: при использовании BufferGeometry с index нормали вычисляются корректно для повторяющихся вершин, учитывая их объединение по индексу.
  • Грубые поверхности (Flat shading): если требуется плоское освещение, метод можно не вызывать, или использовать geometry.computeFaceNormals() с установкой material.flatShading = true.

Практические рекомендации

  • Для динамических моделей с деформациями и морфингом рекомендуется вызывать computeVertexNormals каждый раз после модификации геометрии.
  • При импорте моделей из форматов, где нормали могут отсутствовать (например, OBJ без нормалей), метод обеспечивает корректное освещение без ручного задания нормалей.
  • При оптимизации производительности стоит учитывать, что метод вычисляет нормали для всех вершин, что может быть дорого для больших геометрий. В некоторых случаях имеет смысл использовать geometry.attributes.normal.needsUpdate = true после частичных изменений.

Примеры с визуализацией

Сглаженная сфера:

const geometry = new THREE.SphereGeometry(1, 32, 32);
geometry.computeVertexNormals();
const material = new THREE.MeshStandardMaterial({ color: 0x0077ff });
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

Плоский куб с плоскими нормалями:

const geometry = new THREE.BoxGeometry(1, 1, 1);
geometry.computeVertexNormals(); // при flatShading это не обязательно
const material = new THREE.MeshStandardMaterial({ color: 0xff7700, flatShading: true });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

Взаимодействие с освещением

  • DirectionalLight, PointLight, SpotLight используют нормали для расчёта диффузного и спекулярного отражения.
  • Без правильных нормалей объекты будут отображаться с неправильной яркостью и тенями, особенно на изогнутых поверхностях.
  • Использование computeVertexNormals делает освещение плавным и реалистичным, устраняя визуальные артефакты.

В Three.js computeVertexNormals является основным инструментом для подготовки геометрий к корректному освещению и обеспечению реалистичного визуального восприятия объектов. Правильное использование метода позволяет сочетать динамические изменения модели с качественным отображением света и теней.