суббота, 30 апреля 2011 г.

Параллельно разбитые Карты теней (shadow maps) на Программируемых GPU–Часть 2

 

Оригинал статьи:

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html

Зависимая от сцены проекция

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

Как мы можем видеть на рисунке 10-6, независимый от сцены Wi может содержать большое количество пустого пространства. Каждый Wi должен только содержать объекты, потенциально приводящие тени в Vi, названные теневыми литейщиками (объектами отбрасывающими тени), проиллюстрируемые в Bc. Поскольку невидимые части объектов не нуждаются в переводе в конечное изображение, мы отдельно храним связанные с тенью объекты внутри (или частично внутри) Vi как теневые получатели, иллюстрируемые в Br. Синтезируя затененное изображение целой сцены, мы интерпретируем только теневые получатели, чтобы улучшить производительность рендеринга. Отметим, что объекты, что никогда не отбрасывают тени (такие как ландшафт) должны быть включены только в получатели.

В зависимом от сцены методе передняя плоскость Wi перемещена, чтобы ограничить каждую Vi или любой отбрасывающий тень предмет, а задняя плоскость Wi перемещена, чтобы коснуться каждой Vi или любого теневого получателя. Оптимизированные ближние и дальние плоскости улучшают точность дискретного квантования глубины. Кроме того, из-за того, что только теневые получатели должны сделать сравнение глубины во время теневого определения, мы корректируем x-и y-границы Wi , чтобы ограничить Vi или любому теневой получатель. Псевдокод для зависимого от сцены метода показан в листинге 10-2. Обратите особое внимание на то, как выбраны границы глубины (min.z и max.z)

Конечная матрица преобразования проекции представления освещения для текущего разбиения все еще lightViewMatrix * lightProjMatrix * cropMatrix.

Пример 10-2. Псевдокод для ыычислительных зависимых от сцены границ
clip_image002
10.2.3 Шаги 3 и 4: Генерация PSSM и синтез теней

Шаги 3 и 4 могут быть выполнены иначе, в зависимости от ваших системных аппаратных средств. Поскольку мы используем множественные теневые карты в PSSMs, могут понадобиться дополнительные пути визуализации, когда мы генерируем теневые карты и синтезируем тени.

Чтобы уменьшить нагрузку на задачи по производству рендеринга, мы можем использовать аппаратно-зависимый подход. В следующем разделе мы представляем три аппаратно-зависимых методики для того, чтобы генерировать PSSMs и синтезировать тени:

· Многопроходный метод (без аппаратного ускорения): Этот метод не использует аппаратное ускорение; многочисленные пути рендеринга требуются для того, чтобы генерировать теневые карты (шаг 3) и для того, чтобы синтезировать тени (шаг 4).

· Частично ускоренный на DirectX 9 аппаратными средствами (например, Windows XP и NVIDIA GeForce 6800 GPU): В этом методе мы удаляем дополнительные пути рендеринга для того, чтобы синтезировать тени сцены.

· Полностью ускоренный на DirectX 10 аппаратных средствах (например, Windows Vista и GeForce 8800 GPU): Здесь мы облегчаем нагрузку дополнительных путей рендеринга для создания теневых карт. Чтобы достигнуть этой цели, мы описываем два различных подхода: имитация геометрического шейдера и создание экземпляров

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

10.3 Аппаратно-зависимые реализации

Чтобы облегчить понимание этих трех аппаратно-зависимых реализации, мы визуализируем конвейеры рендеринга различных реализаций, как показано на рисунке 10-7

clip_image004

Иллюстрация 10-7 Визуализация конвейеров рендеринга

10.3.1 Многопроходный Метод

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

Генерация теневых карт

Как только у нас есть матрица преобразования проекции представления освещения lightViewMatrix * lightProjMatrix * cropMatrix для текущей части разбиения, мы можем визуализировать присоединенную текстуру теневой карты. Процедура такая же, как для стандартного теневого отображения: мы визуализируем все предметы, отбрасывающие тень на буфер глубины. Наша реализация использует 32-разрядный с плавающей точкой (R32F) формат текстуры.

В нашей многопроходной реализации, вместо того, чтобы сохранить PSSMs в нескольких независимых текстурах теневой карты, мы многократно используем единственную текстуру теневой карты в каждом прохождении рендеринга, как показано в листинге10-3.

Пример 10-3. Псевдокод для конвейера рендеринга многопроходного метода
clip_image006
Синтез теней

С помощью PSSMs, сгенерированным на предыдущем шаге, тени теперь могут быть вставлены в сцену. В многопроходном методе мы должны синтезировать тени сразу после рендеринга теневой карты.

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

После этого мы можем визуализировать теневые получатели сцены, производя выборку теневой карты стандартным способом. Это означает, что осуществление многопроходного метода не требует использования шейдеров. На иллюстрация 10-8 сравнение SSM (2Kx2K) и многопроходного PSSM (3; 1Kx1K). Однако, как подразумевает название метода, многократное прохождение рендеринга будет всегда выполняться и для генерации теневых карт и для рендеринга теней сцены.

clip_image008

Иллюстрация 10-8 Сравнение SSM и многопроходного PSSM

10.3.2 Ускорение с технологией DirectX 9

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

Мы можем создать пиксельный шейдер, чтобы найти и произвести выборку правильной теневой карты для каждого фрагмента. Операция для определения, в каком разбиении содержится фрагмент, проста, потому что плоскости разбиения параллельны плоскости представления. Мы можем просто использовать значение глубины - или, как в нашей реализации, использовать пространство представления z координату фрагмента - чтобы определить правильную теневую карту.

Установка

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

Отметим, что число сэмплеров текстур, поддерживаемых аппаратными средствами, ограничит число теневых карт, которые мы можем использовать. С другой стороны мы может упаковать множественные теневые карты в единственной текстуре; однако, большинство аппаратных средств с DirectX 9 поддерживает восемь сэмплеров текстуры, которых должны быть более чем достаточно.

Также отметим, что мы должны использовать режим адреса текстуры "выделение цвета", потому что иногда теневые карты выбраны вне текстурно-координатного диапазона. Это может произойти, когда мы используем зависимую от сцены проекцию, потому что подпространство освещения Wi не обязательно покрывает всех получателей.

Синтез теней

Когда мы выполняем рендеринг теней сцены, мы используем пользовательский пиксельный и вершинный шейдер, как показано в листинге 10-4. В вершинном шейдере мы преобразовываем каждую вершину как обычно. Однако, мы также вычисляем (1) пространственное представление позиции вершины, потому что мы будем использовать его для того, чтобы определить теневые карты, соединенные с фрагментами; и (2) позиция вершины в пространстве текстур каждой теневой карты. Мы определяем позицию вершины, умножая вершину на textureMatrix. Это тот же самый подход, который мы используем для стандартного теневого отображения, только теперь мы используем его для всех теневых карт. Все преобразованные координаты выводятся в координатно-текстурные регистры пиксельных шейдеров для дальнейшего использования.

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

Пример 10-4. Вершинный и пиксельный шейдеры для синтеза теней с DirectX 9
clip_image010
Производительность

Мы осуществили этот частично ускоренный метод и в DirectX 9 и в OpenGL. В Технологии DirectX 9, мы осуществили более близкую к проценту фильтрацию (PCF) в пиксельном шейдере(приблизительно 25 команд), а с помощью OpenGL мы использовали ускоренный аппаратными средствами PCF (одна машинная команда). И сравнили производительность с многопроходным методом, когда мы увеличивали число объектов в сцене. Во всех испытаниях число разбиений было четыре.

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

clip_image012

Иллюстрация 10-9 Результаты производительности с GeForce 6800 Ultra и GeForce 8800 GTS

10.3.3 Технология DirectX 10 ускорения

Не смотря на то, что рендеринг теней сцены ускорен на аппаратных средствах DirectX 9, множественные рендеринг-проходы все еще требуются для того, чтобы генерировать PSSMs. Другими словами, технология DirectX 9 предоставляет нам частичное ускорение PSSMs. С другой стороны, мы можем ускорить и генерацию PSSMs и рендеинг теней сцены аппаратными средствами DirectX 10.

Особенности Direct3D 10

Конвейер Direct3D 10 предоставляет геометрический шейдер(GS) как новый уровень построения теней в линейке вершинных и пиксельных шейдеров. Геометрические шейдеры выполняются один раз для каждого примитива, принимая на вход вершину примитива, а на выходе ряд новых примитивов. Они также обеспечивают доступ к информации смежности примитивов и имеют набор команд, подобный такому же в вершинном шейдере (включая поддержку осуществления выборки текстуры).

Другой новой особенностью в Direct3D 10 является воспроизводящий целевой массив, который подобен групповым целям рендеринга в Direct3D 9's(MRTs). В то время как MRTs только допускают отдельный вывод пиксельного шейдера для каждой цели рендеринга, воспроизводящий целевой массив (с помощью геометрического шейдера) могут вывести полностью различные конфигурации к каждому объекту рендеринга. Это сделано в выводе GS, где мы можем определить индекс объекта рендеринга для каждого примитива отдельно.

Эти особенности дают возможность нам динамически "клонировать", геометрия в различные объекты рендеринга с различными преобразованиями. Теперь мы можем повысить производительность генерации PSSMs, потому что каждый отбрасывающий тень объект должен быть представлен только один раз.

Установка

Сначала мы должны создать массив текстуры для теневых карт. Как показано в листинге 10-5, мы как обычно используем 32-разрядный формат элемента текстуры с плавающей точкой, но определяем ее как "typeless", потому что она должна будет работать и как буфер глубины и как текстура. Параметр ArraySize будет содержать число разбиений, и таким образом у нас есть одна текстура для каждого. Кроме того, мы должны установить флаги BindFlags, чтобы связывание массива текстур с представлением трафарета глубины и с обзором ресурсов шейдеров.

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

Как показано в листинге 10-6, создание представление ресурса шейдеров довольно простое. Мы записываем размерность представления в двумерный массив текстур и устанавливаем формат элемента текстуры в единственный канал с плавающей точкой. Иначе, мы используем те же самые параметры настройки как при создании массива текстуры.

Представление трафарета глубины создано похожим способом, но формат элемента текстуры должен быть приведен в буферный совместимый формат глубины, как показано в листинге 10-7.

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

Нам все еще необходимо создать шейдеры, которые будут рассмотрены в следующих двух подразделах.

Пример 10-5. Создание массива текстур
clip_image014
Пример 10-6. Создание представления ресурса шейдеров
clip_image016
Пример 10-7. Создание представления ресурсов трафарета глубины
clip_image018

Комментариев нет:

Отправить комментарий