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

Рисуем в альбом для набросков

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

В RenderMonkey визуализация во временную текстуру может быть выполнена с помощью целевой визуализации (render target). Целевая визуализация — это предлагаемая различными API визуализации технология, которая позволяет вам перенаправить выходные данные аппаратуры визуализации в выбранную текстуру. Полученная текстура затем может использоваться для других эффектов, таких как затенение или размытие движущихся объектов. Вообще-то, это практически не имеет значения для графического оборудования, поскольку обычно визуализация выполняется в скрытую текстуру, находящуюся в памяти, которая показывается пользователю только после завершения визуализации. Использование целевой визуализации просто сообщает графическому оборудованию перенаправить выходные данные в указанную вами текстуру.

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

Я начну с базового, выводящего два чайника шейдера, разработанного в главе 4, «Ваши первые шейдеры», который для разнообразия был модифицирован, чтобы выводить чайник и слона, и усовершенствую его для визуализации в целевую текстуру по вашему выбору. Выполнив это, я покажу процесс, который вы можете использовать, чтобы визуализировать полученную при целевой визуализации текстуру назад в обычный экранный буфер. Реальный процесс в DirectX или OpenGL будет несколько сложнее, поскольку RenderMonkey заботится за вас о некоторых деталях. Обратите внимание, что выводящий чайники шейдер, с которого мы начинаем, находится на CD-ROM в папке с исходным кодом к данной главе в файле shader_1.rfx.

Начнем с загрузки отображающего два чайника шейдера, который был разработан в разделе «Смотрим дважды» главы 4. Я воспользуюсь этим шейдером чтобы показать вам как использовать целевую визуализацию и как применять фильтры к результатам визуализации. После того, как вы откроете рабочее пространство, раскройте узел группы эффектов, а затем раскройте узел эффекта. Вы можете добавить цель визуализации к узлу эффекта щелкнув по нему правой кнопкой мыши и выбрав в контекстном меню команду Add Texture | Add Renderable Texture. В результате будет добавлен новый узел с названием renderTexture, который, при желании, можно переименовать.

Создание узла renderTexture просто создает для вас новую текстуру. Однако, эта текстура отличается от обычных, потому что она не импортируется из файла и управляется автоматически RenderMonkey. Если вы дважды щелкнете по новому узлу renderTexture, будет открыто диалоговое окно свойств renderTexture. Как видно на рис. 5.1, в этом окне находятся несколько параметров, которые вы можете использовать для управления размером и форматом цели визуализации. Это необходимо потому что текстура создается за вас, и вам необходимы средства управления ее параметрами, чтобы они соответствовали вашим потребностям.


Рис. 5.1. Диалоговое окно параметров цели визуализации в RenderMonkey

Рис. 5.1. Диалоговое окно параметров цели визуализации в RenderMonkey


Первая часть диалогового окна на рис. 5.1 управляет шириной и высотой текстуры. Это позволяет вам вручную задать размеры вашей цели визуализации. Обратите внимание на флажок Use viewport dimensions под текстовыми полями с размером текстуры. Он сообщает RenderMonkey, что необходимо принудительно устанавливать размеры текстуры для целевой визуализации равными размеру окна просмотра. Это полезно в ряде случаев, например в фильтрах экранных эффектов, которые мы будем разрабатывать в этой главе, когда каждый пиксель цели визуализации должен соответствовать одному пикселю окна предварительного просмотра, чтобы предотвратить искажения при визуализации. Убедитесь, что этот флажок установлен. Мы почти всегда будем оставлять этот флажок установленным, за исключением некоторых эффектов, когда разрешение цели визуализации не должно соответствовать итоговому разрешению визуализации.

ПРИМЕЧАНИЕ
В диалоговом окне свойств цели визуализации есть флажок Auto-Generate Mip Map, который по умолчанию установлен. К сожалению, не все видеокарты поддерживают эту возможность, особенно если вы работаете с неквадратными текстурами и текстурами, размер которых не равен степени двойки. Обычно хорошо отключить эту возможность, если вы не уверены, что ваше оборудование поддерживает ее.

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

Теперь у вас есть цель визуализации и необходимо сообщить RenderMonkey, что надо использовать ее. Чтобы сделать это, добавьте узел цели визуализации к каждому проходу визуализации, который должен выполнять визуализацию в целевую текстуру. В рассматриваемом шейдере вы должны проделать это действие для обоих проходов, визуализирующих объекты вашей сцены. Чтобы добавить узел Render Target щелкните правой кнопкой мыши по узлу прохода и выберите команду Add Render Target из меню. К проходу будет добавлен узел с именем RenderTarget0. Если щелкнуть по этому узлу правой кнопкой мыши, в появившемся меню будет команда Reference Node, которая позволяет указать, какую именно текстуру вы хотите использовать для визуализации; это позволяет при необходимости использовать в вашем эффекте несколько целей визуализации. После того, как вы создали ссылку на цель визуализации, дважды щелкните левой кнопкой мыши по только что созданному узлу Render Target. Будет выведено диалоговое окно, показанное на рис. 5.2.


Рис. 5.2. Диалоговое окно Render Target Reference

Рис. 5.2. Диалоговое окно Render Target Reference


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

ПРИМЕЧАНИЕ
Когда вы создаете цель визуализации, RenderMonkey также создает соответствующий буфер глубины для текстуры. Это позволяет каждой цели визуализации работать с собственной буферизацией глубины не влияя на другие цели визуализации.

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

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


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

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


Чтобы описанный процесс работал, ваш геометрический объект должен быть простым прямоугольником, созданным так, чтобы его координаты соответствовали углам экрана в экранном пространстве: (–1, –1, 0), (1, –1, 0), (–1, 1, 0) и (1, 1, 0). Такой геометрический объект поставляется вместе с RenderMonkey в файле ScreenAlignedQuad.3ds. Поскольку для данной модели координаты заданы в экранном пространстве, вам не требуется применять к ним матрицу проекции; вы просто перенаправляете координаты в пиксельный шейдер.

Координаты текстуры

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

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


Рис. 5.4. Как получаются координаты текстуры и как визуализируются пиксели

Рис. 5.4. Как получаются координаты текстуры и как визуализируются пиксели


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


Рис. 5.5. Как сместить пиксели цели визуализации для правильного наложения

Рис. 5.5. Как сместить пиксели цели визуализации для правильного наложения


Теперь, когда основы рассмотрены, пришло время мне показать как выполнить операцию копирования текстуры в RenderMonkey. Сперва вам необходимо добавить геометрию, необходимую для проецируемого на экран прямоугольника. Щелкните правой кнопкой мыши по узлу эффекта и выберите в меню команду Add Model. Дважды щелкните по новому узлу и выберите файл ScreenAlignedQuad.3ds, расположенный на CD-ROM в каталоге с исходным кодом для данной главы. Затем добавьте к вашей группе эффектов новый проход визуализации, щелкнув правой кнопкой мыши по узлу эффекта и выбрав в меню команду Add Pass.

Когда новый узел прохода создан, установите ссылку на модель, указывающую на вашу модель ScreenAlignedQuad, и ссылку на карту отображения потоковых данных для использования общего узла Stream Mapping данного рабочего пространства. Следующая вещь, которую необходимо установить, — это объект текстуры, указывающий на текстуру цели визуализации, чтобы она могла быть использована в этом проходе. Для этого щелкните правой кнопкой мыши по узлу прохода и выберите в контекстном меню команду Add Texture Object. Установите параметры этого объекта текстуры, щелкнув правой кнопкой мыши по его узлу, выбрав команду Add Texture Reference и введя ссылку, указывающую на вашу визуализируемую текстуру.

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

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

// Координаты текстуры устанавливаются так, 
// чтобы текстура полностью заполняла весь экран
Out.texCoord.x = 0.5 * (1 + Pos.x);
Out.texCoord.y = 0.5 * (1 - Pos.y);

Как обсуждалось ранее, способ, которым пиксели читаются из текстуры, и способ, которым они записываются визуализатором, не совпадают. Для коррекции этой особенности вы должны сместить текстуру на половину пикселя. В рассматриваемом случае, поскольку ширина и высота цели визуализации соответствуют размерам окна предварительного просмотра, можно воспользоваться встроенными переменными fInverseViewportWidth и fInverseViewportHeight для требуемого смещения текстуры. Эти встроенные переменные должны быть добавлены к вашему рабочему пространству через вызываемое щелчком правой кнопки мыши меню путем выбора команды Add Variable | Float | Predefined и последующего выбора требуемой встроенной переменной из списка. Также помните, что необходимо добавить объявление этих переменных к коду шейдера, чтобы вы потом могли использовать их значения. Комбинируя обычное масштабирование и смещение с корректирующим смещением для текстуры, получаем следующий код:

// Координаты текстуры устанавливаются так, 
// чтобы текстура полностью заполняла весь экран
Out.texCoord.x = 0.5 * (1 + Pos.x - fInverseViewportWidth);
Out.texCoord.y = 0.5 * (1 - Pos.y - fInverseViewportHeight);

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

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

float4x4 matViewProjection;
float fInverseViewportWidth;
float fInverseViewportHeight;
struct VS_OUTPUT
{
    float4 Pos: POSITION;
    float2 texCoord: TEXCOORD0;
};

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

    // Просто передаем координаты, не преобразуя их
    Out.Pos = float4(Pos.xy, 0, 1);

    // Координаты текстуры устанавливаются так, 
    // чтобы текстура полностью заполняла весь экран
    Out.texCoord.x = 0.5 * (1 + Pos.x - fInverseViewportWidth);
    Out.texCoord.y = 0.5 * (1 - Pos.y - fInverseViewportHeight);

    return Out;
}

Показываем цель визуализации

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

sampler Texture0;
float4 ps_main(float2 texCoord: TEXCOORD0) : COLOR
{
    // Просто читаем временную текстуру и передаем
    // полученный цвет на выход без его обработки
    return tex2D(Texture0, texCoord);
}

На рис. 5.6 показано итоговое рабочее пространство и окно предварительного просмотра для данного эффекта. Полный код шейдеров для данного эффекта находится в файле shader_2.rfx на CD-ROM.


Рис. 5.6. Итоговое рабочее пространство и окно предварительного просмотра для вашего исходного шейдера для экранных эффектов

Рис. 5.6. Итоговое рабочее пространство и окно предварительного просмотра для вашего исходного шейдера для экранных эффектов


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


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

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