Объем тени — это метод, используемый в 3D-компьютерной графике для добавления теней к визуализированной сцене. Впервые он был предложен Фрэнком Кроу в 1977 году [1] как геометрия, описывающая трехмерную форму области, скрытой от источника света. Объем тени делит виртуальный мир на две части: области, которые находятся в тени, и области, которые не находятся в тени.
Реализация теневых объёмов с помощью трафаретного буфера обычно считается одной из наиболее практичных универсальных техник затенения в реальном времени для использования на современном оборудовании для 3D-графики [ требуется ссылка ] . Она была популяризирована видеоигрой Doom 3 , а конкретная вариация техники, используемая в этой игре, стала известна как «Обратная Кармака».
Объемы теней стали популярным инструментом для затенения в реальном времени, наряду с более почтенным картированием теней . Главное преимущество объемов теней заключается в том, что они точны до пикселя (хотя во многих реализациях есть небольшая проблема самозатенения вдоль края силуэта, см. конструкцию ниже), тогда как точность карты теней зависит от выделенной ей текстурной памяти, а также от угла, под которым отбрасываются тени (при некоторых углах точность карты теней неизбежно страдает). Однако этот метод требует создания геометрии теней, что может быть интенсивным для ЦП (в зависимости от реализации). Преимущество карт теней заключается в том, что он часто быстрее, поскольку полигоны объема теней часто очень велики с точки зрения экранного пространства и требуют много времени заполнения (особенно для выпуклых объектов), тогда как карты теней не имеют этого ограничения.
Чтобы построить теневой объем, спроецируйте луч от источника света через каждую вершину в объекте, отбрасывающем тень, в некоторую точку (обычно в бесконечности). Эти проекции вместе образуют объем; любая точка внутри этого объема находится в тени, все, что снаружи, освещено светом.
Для полигональной модели объем обычно формируется путем классификации каждой грани в модели как обращенной к источнику света или обращенной от источника света. Набор всех ребер, которые соединяют обращенную к источнику света грань с отдалённой гранью, образуют силуэт относительно источника света. Ребра, образующие силуэт, выдавливаются от света для построения граней теневого объема. Этот объем должен простираться на весь диапазон видимой сцены; часто размеры теневого объема увеличиваются до бесконечности, чтобы достичь этого (см. оптимизацию ниже). Чтобы сформировать замкнутый объем, передний и задний конец этого выдавливания должны быть покрыты. Эти покрытия называются «крышками». В зависимости от метода, используемого для теневого объема, передний конец может быть покрыт самим объектом, а задний конец иногда может быть опущен (см. проход глубины ниже).
Также существует проблема с тенью, когда грани вдоль края силуэта относительно неглубокие. В этом случае тень, которую объект отбрасывает на себя, будет резкой, раскрывая его многоугольные грани, тогда как обычная модель освещения будет иметь постепенное изменение освещения вдоль грани. Это оставляет грубый артефакт тени около края силуэта, который трудно исправить. Увеличение полигональной плотности минимизирует проблему, но не устраняет ее. Если передняя часть объема тени ограничена, весь объем тени может быть слегка смещен в сторону от света, чтобы удалить любые самопересечения тени в пределах расстояния смещения края силуэта (это решение чаще используется в теневых картах ).
Основные этапы формирования теневого объема:
После Кроу, в 1991 году Тим Хайдманн показал, как использовать буфер трафарета для рендеринга теней с теневыми объемами достаточно быстро для использования в приложениях реального времени. Существует три распространенных варианта этой техники: пропуск глубины , провал глубины и исключающее или , но все они используют один и тот же процесс:
Разница между этими тремя методами заключается в генерации маски на втором этапе. Некоторые из них включают два прохода, а некоторые только один; некоторые требуют меньшей точности в буфере трафарета.
Объемы теней, как правило, покрывают большие части видимой сцены и в результате потребляют ценное время растеризации (время заполнения) на оборудовании 3D-графики. Эта проблема усугубляется сложностью объектов, отбрасывающих тени, поскольку каждый объект может отбрасывать на экран свой собственный объем тени любого потенциального размера. См. оптимизацию ниже для обсуждения методов, используемых для борьбы с проблемой времени заполнения.
Хайдман предположил, что если передние и задние поверхности теней визуализируются в отдельных проходах, то количество передних и задних граней перед объектом можно подсчитать с помощью буфера трафарета. Если поверхность объекта находится в тени, то между ней и глазом будет больше передних теневых поверхностей, чем задних теневых поверхностей. Однако если их количество равно, то поверхность объекта не находится в тени. Генерация маски трафарета работает следующим образом:
После этого все освещенные поверхности будут соответствовать 0 в буфере трафарета, где количество передних и задних поверхностей всех теневых объемов между глазом и этой поверхностью будет одинаковым.
Этот подход имеет проблемы, когда сам глаз находится внутри теневого объема (например, когда источник света движется позади объекта). С этой точки зрения глаз видит заднюю поверхность этого теневого объема прежде всего, и это добавляет смещение −1 ко всему буферу трафарета, эффективно инвертируя тени. Это можно исправить, добавив поверхность «cap» к передней части теневого объема, обращенной к глазу, например, на передней плоскости отсечения . Есть еще одна ситуация, когда глаз может находиться в тени объема, отбрасываемого объектом позади камеры, который также должен быть каким-то образом ограничен, чтобы предотвратить подобную проблему. В большинстве распространенных реализаций, поскольку правильное ограничение для прохода глубины может быть сложно осуществить, метод провала глубины (см. ниже) может быть лицензирован для этих особых ситуаций. В качестве альтернативы можно задать буферу трафарета смещение +1 для каждого теневого объема, внутри которого находится камера, хотя выполнение обнаружения может быть медленным.
Существует еще одна потенциальная проблема, если в буфере трафарета недостаточно бит для размещения количества теней, видимых между глазом и поверхностью объекта, поскольку он использует арифметику насыщения . (Если бы вместо этого они использовали арифметическое переполнение , проблема была бы незначительной.)
Тестирование глубинного прохода также известно как тестирование z-прохода , поскольку буфер глубины часто называют z-буфером.
Около 2000 года несколько человек обнаружили, что метод Хайдмана можно заставить работать для всех положений камеры, поменяв глубину местами. Вместо того, чтобы подсчитывать теневые поверхности перед поверхностью объекта, можно так же легко подсчитать поверхности за ней, с тем же конечным результатом. Это решает проблему глаза, находящегося в тени, поскольку теневые объемы между глазом и объектом не учитываются, но вводит условие, что задний конец теневого объема должен быть закрыт, иначе тени будут отсутствовать там, где объем указывает назад в бесконечность.
Метод провала глубины имеет те же соображения относительно точности буфера трафарета, что и метод прохода глубины. Также, подобно проходу глубины, его иногда называют методом z-провала .
Уильям Билодо и Майкл Сонжи открыли эту технику в октябре 1998 года и представили её на конференции разработчиков Creativity, Creative Labs, в 1999 году. [2] Сим Дитрих представил эту технику на GDC в марте 1999 года и на Creativity в конце 1999 года. [3] [4] Несколько месяцев спустя Уильям Билодо и Майкл Сонжи в том же году подали заявку на патент США на эту технику под названием «Метод рендеринга теней с использованием теневого объёма и трафаретного буфера». [5] Джон Кармак из id Software независимо открыл этот алгоритм в 2000 году во время разработки Doom 3. [ 6]
Любой из вышеперечисленных типов может быть аппроксимирован с помощью вариации «исключающее или» , которая не обрабатывает должным образом пересекающиеся объемы теней, но экономит один проход рендеринга (если не время заполнения) и требует только 1-битный буфер трафарета. Следующие шаги предназначены для версии с проходом глубины: