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

Глядим на огонь

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

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

Код основан на поставляемом вместе с RenderMonkey примере ParticleSystem.rfx.

Файл примера использует в своих интересах модель, составленную из отельных полигонов, инициализируемых одинаковым образом за исключением их координаты Z, которая изменяется от 0 до 1 для каждого из полигонов. Индивидуальное значение Z для полигона позволяет отличать частицу от других, чтобы анимировать ее индивидуально.

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

float4x4 matViewProjection: register(c0);
float4x4 matView: register(c4);

float    fTime0_X: register(c8);

float4   particleSystemPosition: register(c9);
float    particleSystemShape: register(c10);
float    particleSpread: register(c11);
float    particleSpeed: register(c12);
float    particleSystemHeight: register(c13);
float    particleSize: register(c14);

// Модель системы частиц состоит из сотен квадратов.
// Квадраты представляют собой простые четырехугольники
// от (-1,-1) до (1,1), каждый из которых имеет индивидуальную
// координату Z из диапазона от 0 до 1. Значение z
// применяется для различения частиц

struct VS_OUTPUT {
    float4 Pos:      POSITION;
    float2 texCoord: TEXCOORD0;
    float  color:    TEXCOORD1;
};

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

    // Цикл частиц
    float t = frac(Pos.z + particleSpeed * fTime0_X);
    // Определяем форму системы
    float s = pow(t, particleSystemShape);

    float3 pos;
    // Испускаем частицы псевдослучайным образом
    pos.x = particleSpread * s * cos(62 * Pos.z);
    pos.z = particleSpread * s * sin(163 * Pos.z);
    // Частицы направляются вверх
    pos.y = particleSystemHeight * t;

    // Ориентируем квадраты на зрителя
    // Матрица вида дает нам вектор направления и верхний вектор
    pos += particleSize * (Pos.x * matView[0] + Pos.y * matView[1]);
    // Помещаем систему на место
    pos += particleSystemPosition;

    Out.Pos = mul(matViewProjection, float4(pos, 1));
    Out.texCoord = Pos.xy;
    Out.color = 1 - t;

    return Out;
}

Вместе с ним работает следующий пиксельный шейдер:

float particleShape: register(c0);
sampler Flame: register(s0);

float4 main(float2 texCoord: TEXCOORD0, float color: TEXCOORD1) : COLOR
{
    // Затеняем частицу круглой маской
    float fade = pow(dot(texCoord, texCoord), particleShape);
    return (1 - fade) * tex1D(Flame, color);
}

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

Во-первых вам надо воссоздать множество переменных, которые присутствуют в примере шейдера системы частиц и необходимы для прохода визуализации частиц. Это переменные particleShape, particleSize, particleSystemHeight, particleSpeed, particleSystemShape и particleSpread. Получив эти переменные, вам необходимо выполнить ряд изменений в шейдере для визуализации эффекта марева.

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

texCoord.x = (( pPos.x / pPos.w) + 1) * 0.5;
texCoord.y = ((-pPos.y / pPos.w) + 1) * 0.5;

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

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

float4x4 matViewProjection: register(c0);
float4x4 matView: register(c4);

float    fTime0_X: register(c8);

float4   particleSystemPosition: register(c9);
float    particleSystemShape: register(c10);
float    particleSpread: register(c11);
float    particleSpeed: register(c12);
float    particleSystemHeight: register(c13);
float    particleSize: register(c14);

// Модель системы частиц состоит из сотен квадратов.
// Квадраты представляют собой простые четырехугольники
// от (-1,-1) до (1,1), каждый из которых имеет индивидуальную
// координату Z из диапазона от 0 до 1. Значение z
// применяется для различения частиц

struct VS_OUTPUT {
    float4 Pos:       POSITION;
    float3 texCoord:  TEXCOORD0;
    float2 texCoord2: TEXCOORD1;
};

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

    // Цикл частиц
    float t = frac(Pos.z + particleSpeed * fTime0_X);
    // Определяем форму системы
    float s = pow(t, particleSystemShape);

    float3 pos;
    // Испускаем частицы псевдослучайным образом
    pos.x = particleSpread * s * cos(62 * Pos.z);
    pos.z = particleSpread * s * sin(163 * Pos.z);
    // Частицы направляются вверх
    pos.y = particleSystemHeight * t;

    // Ориентируем квадраты на зрителя
    // Матрица вида дает нам вектор направления и верхний вектор
    pos += particleSize * (Pos.x * matView[0] + Pos.y * matView[1]);
    // Помещаем систему на место
    pos += particleSystemPosition;

    float4 pPos = mul(matViewProjection, float4(pos, 1));

    Out.Pos = pPos;
    Out.texCoord.x = (( pPos.x / pPos.w) + 1) * 0.5;
    Out.texCoord.y = ((-pPos.y / pPos.w) + 1) * 0.5;
    Out.texCoord.z = s;
    Out.texCoord2 = Pos.xy;

    return Out;
}

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

float OffsetScale;
float particleShape;
sampler RT;
sampler Distortion;

float4 main(float3 texCoord: TEXCOORD0,float2 texCoord2: TEXCOORD1) : COLOR
{
    float2 offset = tex3D(Distortion,
                    float3(texCoord2.xy,0)).xy;
    offset = ((offset * 2.0) - 1.0) * OffsetScale;
    float fade = pow(dot(texCoord2, texCoord2), particleShape);
    return float4(tex2D(RT, texCoord.xy + offset).xyz, (1 - fade));
}

Сделав все изменения, вы готовы увидеть результат. Скомпилируйте шейдер, нажав F7, и вы должны получить картинку, похожую на рис. 7.7. Итоговая версия шейдера находится на CD-ROM в файле shader_5.rfx.


Рис. 7.7. Итоговое рабочее пространство и окно предварительного просмотра для эффекта марева на базе системы частиц

Рис. 7.7. Итоговое рабочее пространство и окно предварительного просмотра для эффекта марева на базе системы частиц



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

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