Главная Новости Статьи Книги Обзоры Проекты Обо мне
Поиск:

меню
главная
новости
статьи
книги
обзоры
проекты
обо мне
 

 
Parallel-Split Shadow Maps



 Порыскав в интернете, я не нашел ни одной статьи на русском по PSSM. Более того – на зарубежном английском языке – статей оказалось менее чем одна. ГПУ ГЕМС3. Статья увешана картинками и кусками кода. Демо примеров оказалось тоже немного – лично я нашел только 4. Все они оказались сложными в понимании, объясню какие  и почему.

  • Cascaded Shadow Maps – с сайта nVidia (горы и пальмы)
  • DX11 Cascaded SM – с SDK
  • Deferred PSSM – с сайта XNA
  • Skin AMD – с сайта AMD

Итак свой велосипед. Я думаю что читатель уже знает как делать обычные теневые карты, но могу напомнить. Для этого мы рендерим сцену, используя  матрицу вида/проекции для светового источника. Т.е. задают их примерно так:

Float Dist = 50.0f; //Источник удален на 50 от центра сцены
D3DXVECTOR3 LightPos(LightDirection.x*dist+0, LightDirection.y*dist+0, LightDirection.z*dist+0);
D3DXVECTOR3 Lighttarget(0, 0, 0);
D3DXVECTOR3 Lightup(0.0f, 1.0f, 0.0f);                                          
D3DXMatrixLookAtLH(&mLightView, &LightPos, &Lighttarget, &Lightup);

D3DXMatrixOrthoLH( &mLightProj, 50,50, 0.1, 100);

Далее эти матрицы передаются в шейдер который рендерит карту глубины сцены с позиции источника света. Рисуем в текстуру – размер которой мы выбираем сами, исходя из качества тени, к примеру 1024х1024. Чем больше размер, тем точнее будет тень.
      Далее мы просто рендерим сцену с простейшим шейдером :

Вершинный
PS_Z_INPUT output = (PS_Z_INPUT)0;
output.Pos = mul( float4(input.Pos.xyz,1), World ); //World – мировая матрица обьекта
output.Pos = mul( output.Pos, LightVP ); // LightVP = mLightView * mLightProj
output.Depth.xy = output.Pos.zw; //передаем в пиксельный Z и W компоненты

Пиксельный
return(input.Depth.x/input.Depth.y); //Возвращаем Z/W т.е. спроецированную глубину.

После этого мы получаем примерно такую вот текстуру :

Не пугайтесь, это машина на земле, а из нее торчит столб. Вообщем такая вот пробная сцена.
Далее имея «на руках» эту текстуру можно начинать рисовать тень. Для этого мы рисуем все обьекты в основной РендерТаргет, в шейдер передаем эту текстуру, основную матрицу вида mView, основную матрицу проекции mProj, и нашу «световую матрицу» LightVP – она нам потребуется для проецирования карты глубины на каждую точку обьекта.
Шейдеры будут примерно такие :

Вершинный
float4 LP = mul( input.Pos, World );
output.vPosLight = mul( LP, ViewToLightProj ); //переводим позицию из мировой в Light Space

Пиксельный
float4 ShadowTexC = input.vPosLight;

    ShadowTexC.xyz /= ShadowTexC.w;
// Переводим из NDC в текстурное пространство
ShadowTexC.x = +0.5f*ShadowTexC.x + 0.5f;
ShadowTexC.y = -0.5f*ShadowTexC.y + 0.5f;

// глубина в системе NDC
float depth = ShadowTexC.z;

// Тут сравниваем глубину с позицией и если она находится глубже – то точка в тени
float A = txShadowMap.Sample(samSM, ShadowTexC.xy ).r;
float B = depth-SHADOW_EPSILON;
fShadowTerm = A < B ? 0.0f : 1.0f;

//Если точка в тени то fShadowTerm = 0, если точка освещена то fShadowTerm = 1
Output_color*=( fShadowTerm *0.25+0.75);
// если fShadowTerm=0 – то получим небольшое затенение, иначе цвет умножится на 1 и не будет
// изменен.

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

>>Следующая страница

 

 

 

Copyright CSS PSV 2009 Kherson
Hosted by uCoz