Каскадные карты теней

Каскадные карты теней (CSM) — это лучший способ борьбы с одной из наиболее распространенных ошибок при затенение: псевдонимы перспективы. В этой технической статье предполагается, что читатель знаком с сопоставлением теней, рассматривается тема CMS. В частности, код:

  • объясняет сложность CMS;
  • предоставляет сведения о возможных вариантах алгоритмов CSM;
  • описываются два наиболее распространенных метода фильтрации: процентная более тесная фильтрация (PCF) и фильтрация с помощью карт теней дисперсии (VSM);
  • определяет и устраняет некоторые распространенные ошибки, связанные с добавлением фильтрации в CSM; И
  • показывает, как сопоставить CSM с оборудованием Direct3D 10 и Direct3D 11.

Код, используемый в этой статье, можно найти в пакете sdk для DirectX в примерах CascadedShadowMaps11 и VarianceShadows11. Эта статья окажется наиболее полезной после реализации методов, описанных в технической статье Общие методы для улучшения карт глубины тени.

Каскадные карты теней и псевдонимы перспективы

Псевдоним перспективы на карте теней является одной из самых сложных задач, которые необходимо преодолеть. В технической статье Общие методы для улучшения карт глубины тени описан псевдоним перспективы и определены некоторые подходы к устранению проблемы. На практике CMS, как правило, являются лучшим решением и обычно используются в современных играх.

Базовую концепцию CMS легко понять. Для разных областей камеры требуются карты теней с разными разрешениями. Объекты, ближайшие к глазу, требуют более высокого разрешения, чем более удаленные объекты. На самом деле, когда глаз движется очень близко к геометрии, пиксели, ближайшие к глазу, могут требовать такого разрешения, что даже 4096 × 4096 карты теней недостаточно.

Основная идея CMS заключается в секционирование frustum на несколько frusta. Для каждой подруски отображается теневая карта; Затем пиксельный шейдер выполняет выборку с карты, которая наиболее точно соответствует требуемому разрешению (рис. 2).

Рис. 1. Покрытие теневой карты

покрытие теневой карты

На рис. 1 отображается качество (слева направо) от самого высокого к самому низкому. Ряд сеток, представляющих карты теней с представлением frustum (инвертированный конус красного цвета), показывает, как на покрытие пикселей влияет карты теней с различным разрешением. Тени имеют наивысшее качество (белые пиксели) при соотношении 1:1 пикселей в световом пространстве с текселями на карте теней. Псевдоним перспективы происходит в виде больших блочных карт текстур (левое изображение), когда слишком много пикселей сопоставляется с тем же текселем тени. Если теневая карта слишком велика, она находится под выборкой. В этом случае пропускаются тексели, поражаются мерцающие артефакты, что влияет на производительность.

Рис. 2. Качество тени CSM

Качество тени csm

На рисунке 2 показаны вырезы из раздела самого высокого качества на каждой карте теней на рис. 1. Карта теней с наиболее близко расположенными пикселями (на вершине) ближе всего к глазу. Технически это карты одного размера, а белый и серый используются для того, чтобы иллюстрировать успех каскадной карты теней. Белый цвет идеально подходит, так как он показывает хороший охват — соотношение 1:1 для пикселей пространства для глаз и текселей теневой карты.

Для каждого кадра требуются следующие действия.

  1. Разделите frustum на subfrusta.

  2. Вычислите орфографическую проекцию для каждой подруски.

  3. Отрисовка теневой карты для каждой подрисовки.

  4. Отрисовка сцены.

    1. Привязка карт теней и отрисовка.

    2. Вершинный шейдер выполняет следующие действия:

      • Вычисляет координаты текстуры для каждой светлой подруски (если только необходимая координата текстуры не вычисляется в пиксельном шейдере).
      • Преобразует и освещает вершину и т. д.
    3. Пиксельный шейдер выполняет следующие действия:

      • Определяет правильную карту теней.
      • При необходимости преобразует координаты текстуры.
      • Примеры каскада.
      • Зажигает пиксель.

Секционирование frustum

Секционирование frustum — это действие создания субфрусты. Одним из способов разделения frustum является вычисление интервалов от нуля до ста процентов в Z-направлении. Затем каждый интервал представляет ближней плоскости и дальнюю плоскость в процентах от оси Z.

Рис. 3. Произвольное секционирование frustums

представление frustums секционировано произвольно

На практике при пересчете разбиений frustum на кадре края тени будут мерцать. Общепринятой практикой является использование статического набора каскадных интервалов для каждого сценария. В этом сценарии интервал вдоль оси Z используется для описания подфруса, который возникает при секционирование frustum. Определение правильных интервалов размера для конкретной сцены зависит от нескольких факторов.

Ориентация геометрии сцены

Что касается геометрии сцены, ориентация камеры влияет на выбор каскадного интервала. Например, камера, расположенная рядом с землей, такая как заземная камера в футбольном матче, имеет другой статический набор каскадных интервалов, чем камера в небе.

На рисунке 4 показаны различные камеры и соответствующие им секции. Если Z-диапазон сцены очень велик, требуется больше разделяемых плоскостей. Например, если глаз находится очень близко к плоскости земли, но удаленные объекты по-прежнему видны, может потребоваться несколько каскадов. Также полезно разделять границы, чтобы больше разбиений было рядом с глазом (где псевдоним перспективы меняется быстрее всего). Если большая часть геометрии сложена в небольшую секцию (например, вид сверху или симулятор полета) представления frustum, требуется меньше каскадов.

Рис. Для разных конфигураций требуется разбиение frustum

для разных конфигураций требуются разные разбиения frustum

(Слева) Если геометрия имеет высокий динамический диапазон в Z, требуется множество каскадов. (По центру) Если геометрия имеет низкий динамический диапазон в Z, от нескольких frustums мало пользы. (Справа) Если динамический диапазон является средним, требуются только три секции.

Ориентация света и камеры

Матрица проекции каждого каскада плотно облегает соответствующую подфрусту. В конфигурациях, где камера обзора и направления света являются ортогональными, каскады могут быть плотно расположены с небольшим перекрытием. Перекрытие становится больше по мере того, как свет и камера обзора перемещаются в параллельное выравнивание (рис. 5). Когда свет и камера обзора почти параллельны, это называется "дулинг frusta", и это очень сложный сценарий для большинства алгоритмов затенения. Это не редкость, чтобы ограничить свет и камеру, чтобы этот сценарий не происходил. Однако CSM работают гораздо лучше, чем многие другие алгоритмы в этом сценарии.

Рис. 5. Каскадная перекрытие увеличивается по мере того, как направление света становится параллельным направлению камеры

Каскадная перекрытие увеличивается по мере того, как направление света становится параллельным направлению камеры

Во многих реализациях CSM используется frusta фиксированного размера. Пиксельный шейдер может использовать Z-глубину для индексирования в массиве каскадов, когда frustum разделен на интервалы фиксированного размера.

Вычисление привязки View-Frustum

После выбора интервалов frustum подфруста создается с использованием одного из двух: соответствует сцене и соответствует каскаду.

Соответствие сцене

Все frusta можно создать с одной и той же ближней плоскости. Это приводит к перекрытию каскадов. В примере CascadedShadowMaps11 этот метод называется подходящим для сцены.

Подогнать к каскаду

Кроме того, можно создать frusta с фактическим интервалом секционирования, используемым в ближней и дальней плоскостях. Это приводит к более жесткой посадке, но вырождается, чтобы соответствовать сцене в случае дуя frusta. Примеры CascadedShadowMaps11 называют этот метод каскадным.

Эти два метода показаны на рис. 6. Подходят для каскадных отходов меньше разрешения. Проблема с приготовкой к каскаду заключается в том, что орфографическая проекция растет и сжимается в зависимости от ориентации представления frustum. Подход к сцене заполняет орфографическую проекцию по максимальному размеру представления frustum, удаляя артефакты, которые появляются при перемещении камеры просмотра. Общие методы улучшения карт глубины тени рассматривают артефакты, которые появляются при перемещении света в разделе "Перемещение света с шагом размера текселя".

Рис. 6. Соответствие сцене и каскад

соответствие сцене и каскад

Отрисовка теневой карты

Пример CascadedShadowMaps11 отрисовывает теневые карты в один большой буфер. Это связано с тем, что PCF в массивах текстур является функцией Direct3D 10.1. Для каждого каскада создается окно просмотра, которое охватывает раздел буфера глубины, соответствующий этому каскаду. Шейдер пикселей null привязан, так как требуется только глубина. Наконец, для каждого каскада задается правильное окно просмотра и теневая матрица, так как карты глубины отображаются по одному в main теневой буфер.

Отрисовка сцены

Буфер, содержащий тени, теперь привязан к шейдеру пикселей. Существует два метода выбора каскада, реализованного в примере CascadedShadowMaps11. Эти два метода объясняются с помощью кода шейдера.

Каскадный выбор Interval-Based

Рис. 7. Каскадный выбор на основе интервала

Каскадный выбор на основе интервала

При выборе на основе интервала (рис. 7) вершинный шейдер вычисляет положение вершины в мировом пространстве.

Output.vDepth = mul( Input.vPosition, m_mWorldView ).z;

Пиксельный шейдер получает интерполированную глубину.

fCurrentPixelDepth = Input.vDepth;

Каскадный выбор на основе интервалов использует сравнение векторов и точечное произведение для определения правильной cacade. CASCADE_COUNT_FLAG указывает количество каскадов. M_fCascadeFrustumsEyeSpaceDepths_data ограничивает секции представления frustum. После сравнения fComparison содержит значение 1, где текущий пиксель больше барьера, и значение 0, если текущий каскад меньше. Точечное произведение суммирует эти значения в индекс массива.

        float4 vCurrentPixelDepth = Input.vDepth;
        float4 fComparison = ( vCurrentPixelDepth > m_fCascadeFrustumsEyeSpaceDepths_data[0]);
        float fIndex = dot(
        float4( CASCADE_COUNT_FLAG > 0,
        CASCADE_COUNT_FLAG > 1,
        CASCADE_COUNT_FLAG > 2,
        CASCADE_COUNT_FLAG > 3)
        , fComparison );

        fIndex = min( fIndex, CASCADE_COUNT_FLAG );
        iCurrentCascadeIndex = (int)fIndex;

После выбора каскада координата текстуры должна быть преобразована в правильный каскад.

vShadowTexCoord = mul( InterpolatedPosition, m_mShadow[iCascadeIndex] );

Затем эта координата текстуры используется для выборки текстуры с координатами X и Y. Координата Z используется для окончательного сравнения глубины.

Каскадный выбор Map-Based

Выбор на основе карты (рис. 8) проверяет четыре стороны каскадов, чтобы найти самую тесную карту, которая охватывает конкретный пиксель. Вместо вычисления позиции в мировом пространстве вершинный шейдер вычисляет позицию пространства просмотра для каждого каскада. Пиксельный шейдер выполняет итерацию по каскадам, чтобы масштабировать и сдвигать координаты текстуры, чтобы они индексируют текущий каскад. Затем координата текстуры проверяется на соответствие границам текстуры. Когда значения X и Y координаты текстуры попадают в каскад, они используются для выборки текстуры. Координата Z используется для окончательного сравнения глубины.

Рис. 8. Каскадный выбор на основе карты

Каскадный выбор на основе карты

выбор Interval-Based и Map-Based

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

Выбор на основе карты использует каскад более эффективно, если теневые карты не выравниваются идеально (см. рис. 8).

Сочетание каскадов

Модули VSM (описанные далее в этой статье) и методы фильтрации, такие как PCF, можно использовать с CMS с низким разрешением для создания мягких теней. К сожалению, это приводит к видимому шову (рис. 9) между каскадным слоями, так как разрешение не совпадает. Решение заключается в создании полосы между теневыми картами, где выполняется проверка тени для обоих каскадов. Затем шейдер линейно интерполирует два значения на основе расположения пикселя в полосе смешения. Примеры CascadedShadowMaps11 и VarianceShadows11 предоставляют ползунок графического пользовательского интерфейса, который можно использовать для увеличения и уменьшения этого диапазона размытия. Шейдер выполняет динамическую ветвь, чтобы подавляющее большинство пикселей считывалось только из текущего каскада.

Рис. 9. Каскадные швы

каскадные швы

(Слева) Видимый шов можно увидеть там, где каскады перекрываются. (Справа) При смешения каскадов шов не возникает.

Фильтрация теневых карт

PCF

Фильтрация обычных теневых карт не создает мягкие, размытые тени. Оборудование фильтрации размывает значения глубины, а затем сравнивает эти размытые значения с текселем светлого пространства. Жесткий край, полученный в результате пройденного или неудачного теста, по-прежнему существует. Размытие карт теней служит только для ошибочного перемещения жесткого края. PCF включает фильтрацию по теневым картам. Общая идея PCF заключается в том, чтобы вычислить процент пикселя в тени на основе количества подвыборок, прошедших проверку глубины, над общим числом подвыборок.

Оборудование Direct3D 10 и Direct3D 11 может выполнять PCF. Входные данные для выборки PCF состоят из координат текстуры и значения глубины сравнения. Для простоты PCF описывается фильтром с четырьмя касаниями. Средство выборки текстур считывает текстуру четыре раза, аналогично стандартному фильтру. Однако возвращаемый результат представляет собой процент пикселей, прошедших проверку глубины. На рисунке 10 показано, как пиксель, который проходит один из четырех тестов глубины, находится в тени на 25 процентов. Фактическое возвращаемое значение представляет собой линейную интерполяцию, основанную на координатах подтекселя текстуры, считываемых для получения гладкого градиента. Без этой линейной интерполяции pcf с четырьмя касаниями сможет вернуть только пять значений: { 0,0, 0,25, 0,5, 0,75, 1,0 }.

Рис. Отфильтрованное изображение PCF с 25 процентами выделенного пикселя

Отфильтрованное изображение PCF с 25 процентами выделенного пикселя

Также можно использовать PCF без поддержки оборудования или расширить PCF на ядра большего размера. Некоторые методы даже выборка с взвешанным ядром. Для этого создайте ядро (например, gaussian) для сетки N × N. Весовые коэффициенты должны сложиться до 1. Затем текстура используется N2 раз. Каждый пример масштабируется с соответствующими весами в ядре. Этот подход используется в примере CascadedShadowMaps11.

Смещение глубины

Смещение глубины становится еще более важным при использовании больших ядер PCF. Допустимо только сравнивать глубину светового пространства пикселя с пикселем, с который он сопоставляется на карте глубины. Соседи текселя карты глубины ссылаются на другое положение. Эта глубина, скорее всего, будет похожа, но может сильно отличаться в зависимости от сцены. На рисунке 11 показаны возникающие артефакты. Одна глубина сравнивается с тремя соседними текселями на карте теней. Один из тестов глубины ошибочно завершается ошибкой, так как его глубина не коррелирует с вычисляемой глубиной светового пространства текущей геометрии. Рекомендуемое решение этой проблемы — использовать большее смещение. Слишком большое смещение, однако, может привести к Питеру Паннингу. Вычисление жесткой ближней и дальней плоскости помогает уменьшить последствия использования смещения.

Рис. 11. Ошибочное самотенение

ошибочное самотенение

Ошибочное затенение возникает в результате сравнения пикселей в глубине светового пространства с текселями на карте теней, которые не коррелируют. Глубина в световом пространстве коррелирует с теневым текселем 2 на карте глубины. Тексель 1 больше, чем глубина светового пространства, в то время как 2 равно, а 3 меньше. Тексели 2 и 3 проходят проверку глубины, а Тексель 1 — сбой.

Вычисление смещения глубины Per-Texel с помощью DDX и DDY для больших PCF

Вычисление смещения глубины текселя с помощью ddx и ddy для больших PCF — это метод, который вычисляет правильное смещение глубины (при условии, что поверхность является плоскостной) для соседнего текселя карты тени.

Этот метод соответствует глубине сравнения плоскости с использованием производной информации. Так как этот метод является сложным с точки зрения вычислений, его следует использовать только в том случае, если у GPU есть резервные вычислительные циклы. Если используются очень большие ядра, это может быть единственным способом, который позволяет удалить артефакты самозатенения, не вызывая Питера Паннинга.

На рисунке 12 показана проблема. Глубина в световом пространстве известна тем текселем, который сравнивается. Глубины светового пространства, соответствующие соседним текселям на карте глубин, неизвестны.

Рис. 12. Схема сцены и глубины

схема сцены и глубины

Отрисоченная сцена отображается слева, а карта глубины с примером блока текселя отображается справа. Тексель пространства для глаз сопоставляется с пикселем с меткой D в центре блока. Это сравнение является точным. Правильная глубина в пространстве глаз, коррелирует с пикселями, которые сосед D неизвестен. Сопоставление соседних текселей в пространстве глаз возможно только в том случае, если предполагается, что пиксель относится к тому же треугольнику, что и D.

Глубина известна за тексель, которая коррелирует с положением светового пространства. Глубина неизвестна для соседних текселей на карте глубин.

На высоком уровне этот метод использует операции ddx и ddy HLSL для поиска производной от положения светового пространства. Это нетривиальное, так как производные операции возвращают градиент глубины светового пространства относительно пространства экрана. Чтобы преобразовать это значение в градиент глубины светового пространства по отношению к светлому пространству, необходимо вычислить матрицу преобразования.

Объяснение кода шейдера

Сведения о остальной части алгоритма предоставляются в качестве объяснения кода шейдера, выполняющего эту операцию. Этот код можно найти в примере CascadedShadowMaps11. На рисунке 13 показано, как текстура светового пространства сопоставляет координаты с картой глубины и как производные в X и Y можно использовать для создания матрицы преобразования.

Рис. 13. Матрица экранного пространства в светлое пространство

матрица экранного пространства в светлое пространство

Для создания этой матрицы используются производные от положения светового пространства в X и Y.

Первым шагом является вычисление производной от положения светового пространства.

          float3 vShadowTexDDX = ddx (vShadowMapTextureCoordViewSpace);
          float3 vShadowTexDDY = ddy (vShadowMapTextureCoordViewSpace);

Графические процессоры класса Direct3D 11 вычисляют эти производные, параллельно выполняя 2 × 2 четырехугольника пикселей и вычитая координаты текстуры из соседа в X для ddx и от соседа в Y для ddy. Эти две производные составляют строки матрицы 2 × 2. В текущем виде эту матрицу можно использовать для преобразования соседних пикселей экранного пространства в наклоны светового пространства. Однако требуется обратная часть этой матрицы. Необходима матрица, которая преобразует соседние пиксели светлого пространства в наклоны пространства экрана.

          float2x2 matScreentoShadow = float2x2( vShadowTexDDX.xy, vShadowTexDDY.xy );
          float fInvDeterminant = 1.0f / fDeterminant;

          float2x2 matShadowToScreen = float2x2 (
          matScreentoShadow._22 * fInvDeterminant,
          matScreentoShadow._12 * -fInvDeterminant,
          matScreentoShadow._21 * -fInvDeterminant,
          matScreentoShadow._11 * fInvDeterminant );

Рис. 14. От светлого до экранного пространства

от светлого до экранного пространства

Затем эта матрица используется для преобразования двух текселей выше и справа от текущего текселя. Эти соседи представлены в виде смещения от текущего текселя.

          float2 vRightShadowTexelLocation = float2( m_fTexelSize, 0.0f );
          float2 vUpShadowTexelLocation = float2( 0.0f, m_fTexelSize );
          float2 vRightTexelDepthRatio = mul( vRightShadowTexelLocation,
          matShadowToScreen );
          float2 vUpTexelDepthRatio = mul( vUpShadowTexelLocation,
          matShadowToScreen );

Коэффициент, создаваемый матрицей, окончательно умножается на производные от глубины, чтобы вычислить смещения глубины для соседних пикселей.

            float fUpTexelDepthDelta =
            vUpTexelDepthRatio.x * vShadowTexDDX.z
            + vUpTexelDepthRatio.y * vShadowTexDDY.z;
            float fRightTexelDepthDelta =
            vRightTexelDepthRatio.x * vShadowTexDDX.z
            + vRightTexelDepthRatio.y * vShadowTexDDY.z;

Теперь эти весовые коэффициенты можно использовать в цикле PCF для добавления смещения к позиции.

    for( int x = m_iPCFBlurForLoopStart; x < m_iPCFBlurForLoopEnd; ++x ) 
    {
        for( int y = m_iPCFBlurForLoopStart; y < m_iPCFBlurForLoopEnd; ++y )
            {
            if ( USE_DERIVATIVES_FOR_DEPTH_OFFSET_FLAG )
            {
            depthcompare += fRightTexelDepthDelta * ( (float) x ) +
            fUpTexelDepthDelta * ( (float) y );
            }
            // Compare the transformed pixel depth to the depth read
            // from the map.
            fPercentLit += g_txShadow.SampleCmpLevelZero( g_samShadow,
            float2(
            vShadowTexCoord.x + ( ( (float) x ) * m_fNativeTexelSizeInX ) ,
            vShadowTexCoord.y + ( ( (float) y ) * m_fTexelSize )
            ),
            depthcompare
            );
            }
     }

PCF и CSM

PCF не работает с массивами текстур в Direct3D 10. Для использования PCF все каскады хранятся в одном большом атласе текстур.

Смещение Derivative-Based

Добавление производных смещений для CMS сопряжено с некоторыми проблемами. Это связано с производным вычислением в элементе управления расходящихся потоков. Проблема возникает из-за фундаментального способа работы GPU. Графические процессоры Direct3D11 работают на 2 × 2 квадроциклах пикселей. Для выполнения производного gpu обычно вычитают копию переменной текущего пикселя из копии соседнего пикселя той же переменной. Способ этого зависит от GPU к GPU. Координаты текстуры определяются каскадным выбором на основе карты или интервала. Некоторые пиксели в квадроцикле пикселей выбирают каскад, отличный от остальных пикселей. Это приводит к видимым швам между теневыми картами, так как производные смещения теперь совершенно неверны. Решение заключается в том, чтобы выполнить производную по координатам текстуры пространства освещения. Эти координаты одинаковы для каждого каскада.

Заполнение для ядер PCF

Индекс ядер PCF за пределами каскадной секции, если теневой буфер не заполнен. Решение заключается в том, чтобы заполнить внешний обод каскада на половину размера ядра PCF. Это должно быть реализовано в шейдере, который выбирает каскад, и в матрице проекции, которая должна отображать каскад достаточно большой, чтобы граница сохранялась.

Карты теней дисперсии

VSM (дополнительные сведения см. в разделе Карты теней дисперсии Доннелли и Лаурицена) позволяют фильтровать карты с прямой тенью. При использовании VSM можно использовать все возможности оборудования для фильтрации текстур. Можно использовать трилинейную и анизотропную фильтрацию (рис. 15). Кроме того, модули VSM могут быть размыты непосредственно через свертки. Модули VSM имеют некоторые недостатки; необходимо хранить два канала данных глубины (глубина и глубина в квадрате). Когда тени перекрываются, световые кровотечения распространены. Однако они хорошо работают с более низкими разрешениями и могут сочетаться с CSM.

Рис. 15. Анизотропная фильтрация

анизотропная фильтрация

Подробные сведения об алгоритмах

VsM работают путем отрисовки глубины и глубины в квадрате на двухканевой теневой карте. Затем эту двухканальную карту тени можно размыть и отфильтровать так же, как обычную текстуру. Затем алгоритм использует неравенство Чебычева в пиксельном шейдере для оценки доли области пикселя, которая пройдет проверку глубины.

Пиксельный шейдер получает значения глубины и глубины в квадрате.

        float  fAvgZ  = mapDepth.x; // Filtered z
        float  fAvgZ2 = mapDepth.y; // Filtered z-squared

Выполняется сравнение глубины.

        if ( fDepth <= fAvgZ )
        {
        fPercentLit = 1;
        }

Если сравнение глубины завершается сбоем, оценивается процент освещенного пикселя. Дисперсия вычисляется как среднее значение квадратов минус квадратов среднего.

        float variance = ( fAvgZ2 ) − ( fAvgZ * fAvgZ );
        variance = min( 1.0f, max( 0.0f, variance + 0.00001f ) );

Значение fPercentLit оценивается по неравенству Чебычева.

        float mean           = fAvgZ;
        float d              = fDepth - mean;
        float fPercentLit    = variance / ( variance + d*d );

Легкое кровотечение

Самым большим недостатком VSMs является легкое кровотечение (рис. 16). Светлое кровотечение возникает, когда несколько теневых закружают друг друга по краям. Модули VSM затеняют края теней на основе различий глубины. Когда тени перекрывают друг друга, в центре области, которая должна быть затеняема, существует разница в глубине. Это проблема с использованием алгоритма VSM.

Рис. 16. Легкое кровотечение VSM

vsm легкое кровотечение

Частичное решение проблемы заключается в том, чтобы поднять fPercentLit в степень. Это приводит к снижению размытия, что может привести к артефактам, где разница в глубине невелика. Иногда существует магическая ценность, которая устраняет проблему.

fPercentLit = pow( p_max, MAGIC_NUMBER );

Альтернативой повышению процента освещенного на питание является предотвращение конфигураций, в которых тени перекрываются. Даже конфигурации с высокой степенью настройки тени имеют несколько ограничений на освещение, камеру и геометрию. Легкое кровотечение также уменьшается с помощью текстур с более высоким разрешением.

Карты теней с многослойной дисперсией (LVSM) решают проблему за счет разбиения frustum на слои, перпендикулярные свету. Количество необходимых карт будет довольно большим, если также используются CSM.

Кроме того, Эндрю Лауритсен(Andrew Lauritzen), соавтор статьи по VSM и автор статьи о LVSM, обсудил объединение экспоненциальных карт теней (ESM) с VSMs для противодействия смешению света на форуме Beyond3D.

VsMs с CSM

Пример VarianceShadow11 объединяет VSM и CSM. Сочетание довольно простое. Пример выполняет те же действия, что и в примере CascadedShadowMaps11. Так как PCF не используется, тени размыты в двухпрохоротном отделяемом свертке. Отсутствие PCF также позволяет образцу использовать массивы текстур вместо атласа текстур. PCF на массивах текстур является функцией Direct3D 10.1.

Градиенты с CMS

Использование градиентов с CMS может создать шов вдоль границы между двумя каскадами, как показано на рисунке 17. В примере инструкции используются производные между пикселями для вычисления сведений, таких как уровень MIP-карты, необходимый фильтру. Это вызывает проблемы, в частности, при выборе MIP-карты или анизотропной фильтрации. Если пиксели в четырехугольнике принимают различные ветви в шейдере, производные, вычисляемые оборудованием GPU, недопустимы. Это приводит к зазубровке шва вдоль карты теней.

Рис. 17. Швы на каскадных границах из-за анизотропной фильтрации с расходующимися потоками

швы на границах каскада из-за анизотропной фильтрации с дивергентным контролем потока

Эта задача решается путем вычисления производных от положения в пространстве светового представления; координата пространства для просмотра света не зависит от выбранного каскада. Вычисляемые производные можно масштабировать по масштабируемой части матрицы текстуры проекции до правильного уровня MIP-карты.

        float3 vShadowTexCoordDDX = ddx( vShadowMapTextureCoordViewSpace );
        vShadowTexCoordDDX *= m_vCascadeScale[iCascade].xyz;
        float3 vShadowTexCoordDDY = ddy( vShadowMapTextureCoordViewSpace );
        vShadowTexCoordDDY *= m_vCascadeScale[iCascade].xyz;

        mapDepth += g_txShadow.SampleGrad( g_samShadow, vShadowTexCoord.xyz,
        vShadowTexCoordDDX, vShadowTexCoordDDY );

Сравнение VSM со стандартными тенями с PCF

Как VSM, так и PCF пытаются приблизить долю области пикселей, которая пройдет проверку глубины. Модули VSM работают с оборудованием фильтрации и могут быть размыты с помощью разделяемых ядер. Ядра сверток с разделителями гораздо дешевле реализовать, чем полное ядро. Кроме того, VSM сравнивают одну глубину светового пространства с одним значением на карте глубины светового пространства. Это означает, что модули VSM не имеют те же проблемы смещения, что и PCF. Технически VSM имеют глубину выборки в большей области, а также выполняют статистический анализ. Это менее точно, чем PCF. На практике vsm очень хорошо выполняют смешивание, что приводит к меньшей необходимости смещения. Как описано выше, недостатком номер один для VSMs является легкое кровотечение.

VSM и PCF представляют собой компромисс между вычислительной мощностью GPU и пропускной способностью текстур GPU. Для вычисления дисперсии требуется больше математических вычислений. PCF требует больше пропускной способности памяти текстуры. Большие ядра PCF могут быстро стать узкими местами из-за пропускной способности текстуры. Поскольку вычислительная мощность GPU растет быстрее, чем пропускная способность GPU, виртуальные машины VSM становятся более практичными из двух алгоритмов. Модули VSM также лучше выглядят с картами теней с более низким разрешением благодаря наложению и фильтрации.

Сводка

CMS предлагают решение проблемы псевдонима перспективы. Существует несколько возможных конфигураций для получения необходимой визуальной точности для заголовка. PCF и VSM широко используются и должны сочетаться с CSM для сокращения псевдонимов.

Ссылки

Доннелли, В. и Лауриткен, А. Дисперсии теневых карт. В SI3D '06: Материалы симпозиума 2006 года по интерактивной трехмерной графике и играм. 2006. стр. 161–165. Нью-йорк, нью-йорк, США: ACM Press.

Лаурицен, Эндрю и Маккул, Майкл. Многоуровневые карты теней дисперсии. Материалы графического интерфейса 2008, 28–30 мая 2008 года, Виндзор, Онтарио, Канада.

Engel, Woflgang F. Section 4. Каскадные карты теней. ShaderX5 , Advanced Rendering Techniques, Wolfgang F. Engel, Ed. Чарльз Ривер Медиа, Бостон, Массачусетс. 2006. стр. 197–206.