Добавляем Motion Blur.

 

Содержание:

1. Введение.
2. Технология.
3. Создание нового Render Target.
4. Основной кодинг.
5. Однопользовательский режим.
6. Файлы материалов.
7. Окончанее.

1. Введение.

В более поздних вегрсиях Гаррис Мода вы могли заметить новый эффект, размытие изображения, при движении объекта (Motion Blur). Метод описываемый в данном туториале не использует шедеров и поэтому будет работать на большинстве видеокарт.

2. Технология.

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

3. создание нового Render Target.

Открываем файл src/cl_dll/rendertexture.cpp, и сверху добавляем:

#include "materialsystem/materialsystemutil.h"

Снизу пишим следующее:

static CTextureReference s_pMotionBlurTex0;

ITexture *GetMotionBlurTex0( void )
{

if( !s_pMotionBlurTex0 )
{

s_pMotionBlurTex0.InitRenderTarget( 256, 256, RT_SIZE_FULL_FRAME_BUFFER, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE );

Assert( !IsErrorTexture( s_pMotionBlurTex0 ) );

}

return s_pMotionBlurTex0;

}

Эту функцию мы будем использовать для получения указателя на Render Target. Числа "256" для нас бессмысленны, т.к. они перекрываются RT_SIZE_FULL_FRAME_BUFFER, который заставляет текстуру принимать размер буфера кадров.

Так, теперь идем в файл src/cl_dll/rendertexture.h и добавляем туда:

ITexture *GetMotionBlurTex0( void );

Это позволит использовать нашу функцию.

4. Основной кодинг.

Прежде всего давайте добавим консольные команды которые мы собираемся использовать. Я их делаю для удобства настройки Motion Blur прямо в игре. Этот код впринципе универсален, что можно заметить из CViewRender::RenderView( const CViewSetup &view, bool drawViewModel ) находящейся в файле view_scene.cpp

// Включение/Выключение эффекта motion blur
ConVar pp_motionblur("pp_motionblur", "1", 0, "Motion Blur");
// Выставление значения Motion Blur Alpha при добавлении буфера кадров (Frame Buffer) в наш буфер.
ConVar pp_motionblur_addalpha("pp_motionblur_addalpha", "0.1", 0, "Motion Blur Alpha");
// Выставление значения Motion Blur Alpha при добавление нашего буфера в буфер кадров.
ConVar pp_motionblur_drawalpha("pp_motionblur_drawalpha", "1", 0, "Motion Blur Draw Alpha");
// Задержка между захватом и добавлением кадра. Чем меньше время, тем быстрее обновляется кадр.
ConVar pp_motionblur_time("pp_motionblur_time", "0.05", 0, "The amount of time to wait until updating the FB");

Не буду ничего пояснять, всё прекрасно видно из кода.

void CViewRender::DoMotionBlur( void )
{

 

if ( pp_motionblur.GetInt() == 0 ) return;

static float fNextDrawTime = 0.0f;

bool found;
IMaterialVar* mv = NULL; IMaterial *pMatScreen = NULL;
ITexture *pMotionBlur = NULL;
ITexture *pOriginalTexture = NULL;

// Получение материала из главног буфера
pMatScreen = materials->FindMaterial( "frontbuffer", TEXTURE_GROUP_OTHER, true );
// Получение render target
pMotionBlur = GetMotionBlurTex0();
// сохранение render target
ITexture *pOriginalRenderTarget = materials->GetRenderTarget();

// Установка камеры
int oldX, oldY, oldW, oldH;
materials->GetViewport( oldX, oldY, oldW, oldH );

materials->MatrixMode( MATERIAL_PROJECTION );
materials->PushMatrix();
materials->LoadIdentity();

materials->MatrixMode( MATERIAL_VIEW );
materials->PushMatrix();
materials->LoadIdentity();

if( gpGlobals->curtime >= fNextDrawTime )
{

   

UpdateScreenEffectTexture( 0 );

// Установка alpha для любого значения консоли
mv = pMatScreen->FindVar( "$alpha", &found, false );
if (found)
{

     

if ( fNextDrawTime == 0 )
{
mv->SetFloatValue( 1.0f );
}
else
{
mv->SetFloatValue( pp_motionblur_addalpha.GetFloat() ); }

   

}

materials->SetRenderTarget( pMotionBlur );
materials->DrawScreenSpaceQuad( pMatScreen );

// установка времяни прорисовки
fNextDrawTime = gpGlobals->curtime + pp_motionblur_time.GetFloat();

 

}

// Установка alpha
mv = pMatScreen->FindVar( "$alpha", &found, false );
if (found)
{

    mv->SetFloatValue( pp_motionblur_drawalpha.GetFloat() );
 

}

// Захват текстуры в наш буфер
mv = pMatScreen->FindVar( "$basetexture", &found, false );
if (found)
{

    pOriginalTexture = mv->GetTextureValue();
mv->SetTextureValue( pMotionBlur );
 

}

materials->SetRenderTarget( pOriginalRenderTarget );
materials->DrawScreenSpaceQuad( pMatScreen );

// Sставим текстуру на место
to _rt_FullFrameFB
if (found)
{

    mv->SetTextureValue( pOriginalTexture );
 

}

materials->DepthRange( 0.0f, 1.0f );
materials->MatrixMode( MATERIAL_PROJECTION );
materials->PopMatrix();
materials->MatrixMode( MATERIAL_VIEW );
materials->PopMatrix

}

Надеюсь что всё правильно.

Теперь в функции CViewRender::RenderView( const CViewSetup &view, bool drawViewModel ) находящейся в файле view_scene.cpp, добавляем следующую строчку:

DoMotionBlur();

Прямо перед:

// Draw the 2D graphics

Ну и наконец добавляем строчку:

void CViewRender::DoMotionBlur( void );

В самаом конце файла viewrender.h

5. Однопользоветельский режим

Если вы работаете над сингл модом, то вы возможно заметели что буфер не обновляется при смене карты или смерти игрока, это происходит потому что при смене карты переменная gpGlobals->curtime принимает значение 0.0 но, fNextDrawTime удерживает её значение.

И так, выполняем проверку:

if ( fNextDrawTime < gpGlobals->curtime )

Если вы играли 30 минут на карте, то после её смены Motion Blur начнет работать 30 минут на новой карте. Теперь обнуляем значение fNextDrawTime с помошью проверки:

 

if ( fNextDrawTime - gpGlobals->curtime > 1.0f)

{

  fNextDrawTime = 0.0f;
}

Данный код находится ниже

if( gpGlobals->curtime >= fNextDrawTime )

6. Файлы материалов

Нужно добавить файл материалов с названием frontbuffer.vmt в папку материалов, возможно использование уже существующего. Вот так выглядит мой:

"UnlitGeneric"
{

 

"$basetexture" "_rt_FullFrameFB"

"$ignorez"

1
}
   

 

7. Окончание

Я решил написать этот туториал потому что мне задавалось множество вопросов по этой теме. Надеюсь он кому-нибуть поможет.

Garry Newman.

Материал взят с сайта http://developer.valvesoftware.com
Перевод выполнил Strateg


Hosted by uCoz