netlib.narod.ru< Назад | Оглавление | Далее >

Вспомогательные эффекты для марева

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

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

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

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

Все о картах искажений

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

Процесс, лежащий в основе эффекта марева прост. Вы визуализируете сцену в цель визуализации, как делали это в главе 5, «Взгляд через фильтр», и главе 6, «Размываем изображения объектов». Однако когда приходит время копировать пиксели цели визуализации на экран, вы вносите искажения относительно их исходного состояния.

Искажения не подразумевают изменения самих пикселей; они обозначают взятие соседнего пикселя, вместо того, который должен визуализироваться. Делая так, вы имитируете небольшие отклонения световых лучей, вызванные прохождением через нагретый воздух, как показано на рис. 7.3. Это достигается путем использования карт искажений, которые вызывают смещение пикселей при их копировании из виуализируемой текстуры на экран.

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

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

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

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

// Вычисляем искажение путем чтения карты искажений
// и преобразования значения в диапазон от -1 до 1.
// Значение OffsetScale применяется для контроля за
// итоговым диапазоном искажений 
float2 offset = tex3D(Distortion,
                float3(texCoord2.xy,0)).xy;
offset = ((offset * 2.0) - 1.0) * OffsetScale;

 

ПРИМЕЧАНИЕ
Создавая карту искажений помните, что значения из нее будут смещаться и масштабироваться. Это означает, что нулевому смещению в терминах цвета соответствует не 0, а 0.5.

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

float OffsetScale;
sampler Texture0;
sampler Texture1;

float4 ps_main(float2 texCoord: TEXCOORD0) : COLOR
{
    // Читаем и масштабируем искажающее смещение
    float2 offset = tex3D(Texture1,
                    float3(texCoord.x,texCoord.y,0)).xy;
    offset = ((offset * 2.0) - 1.0) * OffsetScale;

    // Смещаем выборку из цели визуализации
    return tex2D(Texture0, texCoord+offset);
}

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

ПРИМЕЧАНИЕ
Как вы, возможно, уже заметили, карты искажений, используемые для создания марева, не следуют законам преломления. Поскольку марево — это сложный эффект, я сосредотачиваюсь на том чтобы убедительно имитировать его, а не на точном воссоздании. Точное воссоздание преломления с использованием закона Снеллиуса вы увидите в главе 11, «Зеркала, зеркала на стене».

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

Добавляем фон к сцене

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

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

Общепринятый подход заключается в создании нескольких снимков под разными углами и их последующим объединением в полный вид вашего окружения. Существует много способов сделать это, и я не буду углубляться в описание общих техник, таких как сферические и параболические карты. У большинства современных видеокарт есть встроенная поддержка техники, называемой кубические карты (cube map), и именно на ней я и остановлюсь.

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

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


Рис. 7.4. Диаграмма, показывающая работу кубической карты окружения

Рис. 7.4. Диаграмма, показывающая работу кубической карты окружения


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

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

ПРИМЕЧАНИЕ
Поскольку кубические карты по сути представляют собой композицию из шести обычных текстур, вам необходимо использовать формат текстур, который поддерживает такое упорядочивание. Во время написания этой книги только принадлежащий Microsoft формат файлов .DDS поддерживал кубические текстуры и позволял объединить шесть обычных текстур и записать их как кубическую карту.

Давайте теперь создадим базовый шейдер, который использует кубическую карту для отображения чайника на фоне окружения. Код этого шейдера вы найдете в файле shader_1.rfx на CD-ROM.

Давайте начнем с базового шейдера, похожего на shader_1.rfx, разработанный в главе 6. Вам потребуется новый проход визуализации для карты окружения. Создайте новый проход, воспользовавшись командой Add Pass из контекстного меню, вызываемого щелчком правой кнопки мыши по узлу эффекта.

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

Теперь у вас есть текстура, и вам необходимо где-то визуализировать ее. Поскольку вы хотите, чтобы она занимала весь экран, независимо от того, куда направлена камера, для этого трюка иделально подойдет большая сфера с центром в точке расположения камеры. Модель такой сферы поставляется вместе с RenderMonkey в файле sphere.3ds. Создайте в вашем узле эффекта новый узел модели и укажите в нем ссылку на требуемый файл модели.

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

Имейте в виду, что хотя сфера имеет конечный размер, вы хотите рассматривать ее будто она бесконечно большая. Для этого при визуализации объекта вам надо отключить Z-буфер, выключив режимы визуализации ZENABLE и ZWRITEENABLE.

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

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

Совместив все вместе получаем следующий код вершинного шейдера:

float4x4 matViewProjection;
float4 vViewPosition;
struct VS_OUTPUT
{
    float4 Pos: POSITION;
    float3 dir: TEXCOORD0;
};

VS_OUTPUT vs_main(float4 Pos: POSITION)
{
    VS_OUTPUT Out;

    // Центрируем окружение относительно камеры и
    // передаем направление взгляда в пиксельный шейдер
    Out.Pos = mul(matViewProjection, float4(Pos.xyz + vViewPosition, 1));
    Out.dir = Pos.xyz;

    return Out;
}

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

sampler Environment;

float4 ps_main(float3 dir: TEXCOORD0) : COLOR
{
    // Выборка и вывод цвета карты окружения
    return texCUBE(Environment, dir);
}

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


Рис. 7.5. Результат работы шейдера, визуализирующего карту окружения и чайник

Рис. 7.5. Результат работы шейдера, визуализирующего карту окружения и чайник


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

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

Заключительная версия этого шаблона шейдера находится на CD-ROM в файле shader_2.rfx.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz