Объем тени - это техника, используемая в 3D компьютерной графике для добавления теней к визуализированной сцене. Впервые они были предложены Фрэнком Кроу в 1977 году как геометрия, описывающая трехмерную форму области, закрытой от источника света. Теневой объем делит виртуальный мир на две части: области, которые находятся в тени, и области, которые не находятся.
Реализация теневых объемов буфера трафарета обычно считается одним из наиболее практичных методов затенения в реальном времени общего назначения для использования на современном оборудовании для трехмерной графики. Он был популяризирован с помощью видеоигры Doom 3, а особый вариант техники, использованной в этой игре, стал известен как Обратный Кармака.
Объемы теней стали популярный инструмент для затенения в реальном времени, наряду с более уважаемым shadow mapping. Основное преимущество теневых объемов заключается в том, что они точны до пикселя (хотя многие реализации имеют небольшую проблему самозатенения по краю силуэта, см. конструкцию ниже), тогда как точность карты теней зависит от выделенная ему память текстуры, а также угол, под которым отбрасываются тени (под некоторыми углами неизбежно страдает точность карты теней). Однако метод теневого объема требует создания теневой геометрии, которая может потребовать больших ресурсов процессора (в зависимости от реализации). Преимущество отображения теней в том, что оно часто выполняется быстрее, потому что многоугольники теневого объема часто очень велики с точки зрения экранного пространства и требуют много времени для заполнения (особенно для выпуклых объектов), тогда как карты теней не имеют этого ограничения.
Чтобы построить теневой объем, спроецируйте луч от источника света через каждую вершину объекта, отбрасывающего тень, на некоторая точка (обычно на бесконечности). Эти проекции вместе образуют объем; любая точка внутри этого объема находится в тени, все снаружи освещено светом.
Для многоугольной модели объем обычно формируется путем классификации каждой грани модели как обращенной к источнику света или обращенной от источника света. Набор всех краев, которые соединяют направленную сторону с удаленной гранью, образуют силуэт по отношению к источнику света. Края, образующие силуэт, выдавлены в сторону от света, чтобы создать грани теневого объема. Этот объем должен распространяться на всю видимую сцену; часто размеры теневого объема увеличиваются до бесконечности для достижения этой цели (см. оптимизация ниже). Чтобы сформировать замкнутый объем, передний и задний конец этого выдавливания должны быть покрыты. Эти покрытия называются «колпаками». В зависимости от метода, используемого для теневого объема, передняя часть может быть покрыта самим объектом, а задняя часть может иногда отсутствовать (см. проход глубины ниже).
Также существует проблема с тенью, когда грани по краю силуэта относительно неглубокие. В этом случае тень, которую объект отбрасывает на себя, будет резкой, открывая его многоугольные грани, тогда как обычная модель освещения будет иметь постепенное изменение освещения вдоль грани. Это оставляет грубый артефакт тени возле края силуэта, который трудно исправить. Увеличение плотности полигонов минимизирует проблему, но не устраняет ее. Если передняя часть теневого объема закрыта, весь теневой объем может быть немного смещен от источника света, чтобы удалить любые самопересечения теней в пределах расстояния смещения края силуэта (это решение чаще используется в наложении теней ).
Основные шаги для формирования теневого объема:
После Crow в 1991 году было показано, как использовать буфер трафарета для достаточно быстрой визуализации теней с теневыми объемами для использования в приложениях реального времени. Существует три распространенных варианта этого метода: проход глубины, отказ глубины и исключающее ИЛИ, но все они используют один и тот же процесс:
Разница между этими тремя методами возникает при генерации маски на втором этапе. Некоторые включают в себя два прохода, а некоторые - только один; некоторые требуют меньшей точности в буфере трафарета.
Теневые объемы, как правило, покрывают большие части видимой сцены и, как следствие, отнимают ценное время растеризации (время заполнения) на оборудовании для трехмерной графики. Эта проблема усугубляется сложностью объектов, отбрасывающих тень, поскольку каждый объект может отбрасывать на экран свой собственный объем тени любого потенциального размера. См. оптимизацию ниже для обсуждения методов, используемых для решения проблемы времени заполнения.
Хайдманн предположил, что если передние и задние поверхности теней визуализировались в отдельных проходах, количество передних и задних поверхностей перед объектом можно было подсчитать, используя буфер трафарета. Если поверхность объекта находится в тени, между ним и глазом будет больше теневых поверхностей, обращенных вперед, чем поверхностей теней, обращенных назад. Однако, если их количество равно, поверхность объекта не находится в тени. Генерация маски трафарета работает следующим образом:
После этого все освещенные поверхности будут соответствовать 0 в буфере трафарета, где числа передней и задней поверхностей всех теневых объемов между глазом и этой поверхностью равны.
У этого подхода есть проблемы, когда глаз сам находится внутри теневого объема (например, когда источник света движется за объектом). С этой точки зрения глаз видит обратную сторону этого теневого объема прежде всего, и это добавляет смещение -1 ко всему буферу трафарета, эффективно инвертируя тени. Это можно исправить, добавив поверхность «шапочку» к передней части теневого объема, обращенной к глазу, например, на передней плоскости отсечения. Существует еще одна ситуация, когда глаз может находиться в тени объема, отбрасываемого объектом за камерой, который также необходимо каким-то образом закрыть, чтобы предотвратить аналогичную проблему. В большинстве распространенных реализаций, поскольку правильное ограничение прохода по глубине может быть затруднено, для этих особых ситуаций может быть лицензирован метод сбоя глубины (см. Ниже). В качестве альтернативы можно дать буферу трафарета смещение +1 для каждого теневого объема, внутри которого находится камера, хотя обнаружение может быть медленным.
Существует еще одна потенциальная проблема, если в буфере трафарета не хватает битов для размещения количества теней, видимых между глазом и поверхностью объекта, потому что он использует арифметику насыщения. (Если бы вместо этого они использовали арифметическое переполнение, проблема была бы несущественной.)
Тестирование прохода глубины также известно как тестирование z-прохода, поскольку буфер глубины является часто называют z-буфером.
Примерно в 2000 году несколько человек обнаружили, что метод Хайдмана можно заставить работать для всех положений камеры, изменив глубину на обратную. Вместо подсчета теневых поверхностей перед поверхностью объекта, можно так же легко подсчитать поверхности за ним с тем же конечным результатом. Это решает проблему того, что глаз находится в тени, поскольку объемы теней между глазом и объектом не учитываются, но вводит условие, что задний конец объема тени должен быть ограничен, иначе тени будут отсутствовать там, где указывает объем. назад в бесконечность.
Метод отказа глубины учитывает те же соображения относительно точности буфера трафарета, что и метод прохода глубины. Кроме того, аналогично проходу глубины, его иногда называют методом z-fail .
Уильям Билодо и Майкл Сонги открыли эту технику в октябре 1998 года и представили ее на конференции разработчиков Creative Labs в 1999 году. Представили эту технику на обоих GDC в марте 1999 года. и в Creativity в конце 1999 года. Несколько месяцев спустя Уильям Билодо и Майкл Сонги в том же году подали заявку на патент США на этот метод, US 6384822, озаглавленный «Метод визуализации теней. с использованием теневого тома и буфера трафарета », выпущенного в 2002 году и истекшего в октябре 2019 года. Джон Кармак из id Software независимо обнаружил алгоритм в 2000 году во время разработки Doom 3.
Любой из вышеперечисленных типов может быть аппроксимирован вариацией Exclusive-or, которая не работает должным образом с пересекающимися теневыми объемами, но сохраняет один проход рендеринга ( если не время заполнения) и требует только 1-битного буфера трафарета. Следующие шаги относятся к версии с проходом глубины: