|
|
Порыскав в интернете, я не нашел ни одной статьи на русском по 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
|
|