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

  » Variance Shadow Mapping (VSM) | страница 1
Конференция предназначена для общения пилотов. Для удобства она разделена на каналы, каждый из которых посвящен определенной игре. Пожалуйста, открывайте темы только в соответствующих каналах и после того, как убедитесь, что данный вопрос не обсуждался ранее.

Поиск | Правила конференции | Фотоальбом | Регистрация | Список пилотов | Профиль | Войти и проверить личные сообщения | Вход

   Страница 1 из 1
 
Поиск в этой теме:
Канал Игры Мечты: «Variance Shadow Mapping (VSM)»
Dastox
 220 EGP


Рейтинг канала: 2(12)
Репутация: 48
Сообщения: 887
Откуда: Sol 3
Зарегистрирован: 31.08.2007
Может кому пригодится. Улыбка

 Перевод отрывка из книги Sean James '3D Graphics with XNA Game Studio 4.0' (2010)   (кликните здесь для просмотра)

Variance shadow mapping - мягкие тени

Наши тени в текущем виде смотрятся неплохо, но ведут себя не так как те, которые мы видим в реальном мире. Хотя края теней часто бывают четкие, но чаще всего - нет. В пасмурные дни, или когда объекты освещаются рассеянным светом (непрямой источник освещения), тени часто выглядят нечеткими и смазанными. В следующих разделах мы реализуем мягкие тени (soft shadows) с помощью метода называемого Variance Shadow Maps (VSM). Большим преимуществом рассеянных теней является то, что мы можем использовать фильтры для текстуры глубины (we can filter the depth texture) как для обычной текстуры - в данном случае размывая ее - не разрушая при этом результирующие тени.



Этот раздел в основном посвящен реализации VSM, но оригинальная статья и презентация данного метода, также как и другой пример реализации, доступны здесь: http://www.punkuser.net/vsm.

Первым различием между "обычным" проецированием теней и VSM является то, что мы сохраняем глубину и квадрат глубины в самой текстуре глубины. Позже мы используем эти значения для апроксимации теней. Сначала нам потребуется нам надо обновить эффект отрисовки глубинной текстуры (depth texture
rendering effect), чтобы он возвращал оба эти значения:

Код:
return float4(depth, depth * depth, 0, 1);


Теперь когда эффект глубинной текстуры возвращает два значения, нам нужно изменить формат поверхности (surface format), который мы используем. В прошлом мы использовали SurfaceFormat.Single, который является 32-bit'ным форматом, где все 32 бита выделены для красного канала. Это позволяет нам хранить относительно точные значения глубины в красном канале цели отрисовки (render target) - гораздо точнее чем SurfaceFormat.Color например, который отдает только 8 бит красному каналу.

Так как мы теперь храним два значения, мы будем использовать SurfaceFormat.HalfVector2. Это тоже 32-bit'ный формат, в котором 16 бит отведены красному каналу, и 16 бит - зеленому каналу. Это даст меньшую точность по сравнению с тем, что мы использовали, но, поскольку мы размываем карту тени, разница не очень заметна. Это позволит нам оставить требования к памяти низкими, особенно с учетом количества целей отрисовки (render targets), которые у нас набрались.

Код:
shadowDepthTarg = new RenderTarget2D(GraphicsDevice, shadowMapSize, 
    shadowMapSize, false, SurfaceFormat.HalfVector2, 
    DepthFormat.Depth24);


Variance shadow mapping - размывание текстуры глубины

Следующий шаг в технологии VSM - это размывание текстуры глубины, которую мы только что отобразили, используя то, что называется Gaussian blur. Глава 8 рассматривает гауссово размывание гораздо более детально, но ради простоты мы используем заранее вычисленные параметры для размывания. Размывание глубинной текстуры даст нам мягкие тени. Если мы не будем размывать текстуру глубины, то мы получим тени почти идентичные тем, что были получены нами ранее.



Размывние (blurring) это процесс усреднения пикселя и его соседей для каждого пикселя изображения - "сглаживание" изображения в целом. Gaussian blur улучшает эффект используя специфичные смещения пикселей и весы, но это такой же процесс.

Эффект Gaussian blur:
Код:

// Текстура для размывания
texture ScreenTexture;
sampler2D tex = sampler_state {
texture = <ScreenTexture>;
  minfilter = point;
  magfilter = point;
  mipfilter = point;
};
// Заранее вычисленные весы и смещения
float weights[15] = { 0.1061154, 0.1028506, 0.1028506, 0.09364651, 
   0.09364651, 0.0801001, 0.0801001, 0.06436224, 0.06436224, 
   0.04858317, 0.04858317, 0.03445063, 0.03445063, 0.02294906, 
   0.02294906 };
float offsets[15] = { 0, 0.00125, -0.00125, 0.002916667, 
   -0.002916667, 0.004583334, -0.004583334, 0.00625, -0.00625, 
   0.007916667, -0.007916667, 0.009583334, -0.009583334, 0.01125, 
   -0.01125 };
// Горизонтальное размывание изображения
float4 BlurHorizontal(float4 Position : POSITION0, 
    float2 UV : TEXCOORD0) : COLOR0
{
  float4 output = float4(0, 0, 0, 1);
   
  // Сэмплирование из окружающих пикселей используя заранее вычисленные
  // смещения пикселей (pixel offsets) и весы цветов (color weights)
  for (int i = 0; i < 15; i++)
    output += tex2D(tex, UV + float2(offsets[i], 0)) * weights[i];
     
  return output;
}
// Вертикальное размывание изображения
float4 BlurVertical(float4 Position : POSITION0, 
     float2 UV : TEXCOORD0) : COLOR0
{
  float4 output = float4(0, 0, 0, 1);
   
  for (int i = 0; i < 15; i++)
    output += tex2D(tex, UV + float2(0, offsets[i])) * weights[i];
     
  return output;
}
technique Technique1
{
pass Horizontal
  {
     PixelShader = compile ps_2_0 BlurHorizontal();
  }
  pass Vertical
  {
     PixelShader = compile ps_2_0 BlurVertical();
  }
}


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

Чтобы класс PrelightingRenderer выполнил размывание, напотребуется еще несколько экземплярных переменных (instance variables) - SpriteBatch чтобы отобразить карту глубины (draw depth map) в цели отрисовки (into render targets), эффект Gaussian blur и цель отрисовки (render target), в которой мы будем хранить результат горизонтального размывания. Мы проводим вертикальное размывание используя первоначальный буфер глубины (original depth buffer) в качестве цели, сэмплируя сцену размытую горизонтально из этой вторичной цели отрисовки (render target).

Код:
SpriteBatch spriteBatch;
RenderTarget2D shadowBlurTarg;
Effect shadowBlurEffect;


Эти значения должны быть инициализированы в конструкторе:

Код:
spriteBatch = new SpriteBatch(GraphicsDevice);
shadowBlurEffect = Content.Load<Effect>("GaussianBlur");
shadowBlurTarg = new RenderTarget2D(GraphicsDevice, shadowMapSize,
   shadowMapSize, false, SurfaceFormat.Color, DepthFormat.Depth24);


Затем мы создадим функцию, которая выполнит размывание. Обратите внимание, что мы указываем из какой цели отрисовки (render target) проводится сэмплирование, и в какую цель отрисовки (render target) пойдет результат. Также мы указываем какой из методов применять с помощью параметра dir - 0 для горизонтального размывания и 1 для вертикального.

Код:

void blurShadow(RenderTarget2D to, RenderTarget2D from, int dir)
{
  // Указываем целевую цель отрисовки (render target)
  graphicsDevice.SetRenderTarget(to);
  graphicsDevice.Clear(Color.Black);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque);
  // Начинаем эффект Gaussian blur
  shadowBlurEffect.CurrentTechnique.Passes[dir].Apply();
  // Отображаем содержимое исходной цели отрисовки, чтобы они
  // могли быть размыты пиксельным шейдером gaussian blur
  spriteBatch.Draw(from, Vector2.Zero, Color.White);
  spriteBatch.End();
  // Clean up после sprite batch
  graphicsDevice.BlendState = BlendState.Opaque;
  graphicsDevice.DepthStencilState = DepthStencilState.Default;
  // Удаляем цель отрисовки
  graphicsDevice.SetRenderTarget(null);
}


В последнем изменении в классе PrelightingRenderer, нам нужно убедиться, что мы размываем тень в функции Draw(). Обратите внимание, что мы сначала копируем из глубинной цели (depth target) в цель размывания (blur target) размывая при этом горизонтально, а затем копируем обратно из цели размывания в цель глубины размывая при этом вертикально.

Код:

public void Draw()
{
  drawDepthNormalMap();
  drawLightMap();
  if (DoShadowMapping)
  {
    drawShadowDepthMap();
    blurShadow(shadowBlurTarg, shadowDepthTarg, 0);
    blurShadow(shadowDepthTarg, shadowBlurTarg, 1);
  }
  prepareMainPass();
}



Variance shadow mapping - генерирование теней

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

Код:
float2 sampleShadowMap(float2 UV)
{
  if (UV.x < 0 || UV.x > 1 || UV.y < 0 || UV.y > 1)
    return float2(1, 1);
  return tex2D(shadowSampler, UV).rg;
}


Наконец мы можем обновить пиксельный шейдер, чтобы он проводил вычисления для variance shadow mapping. Мы берем сэмпл из текстуры глубины как и обычно чтобы получить значение глубины, которое она содержит, вычисляем расстояние до источника света (light distance) как и обычно внося небольшое смещение (offsetting it with a small bias). После этого мы проводим вычисления теней как было показано в демонстрационном коде VSM:

Код:

float shadow = 1;

if (DoShadowMapping)
{
  float2 shadowTexCoord = postProjToScreen(input.ShadowScreenPosition)
    + halfPixel();
  float realDepth = input.ShadowScreenPosition.z / ShadowFarPlane
    - ShadowBias;
  if (realDepth < 1)
  {
    // Variance shadow mapping code below from the variance shadow
    // mapping demo code @ http://www.punkuser.net/vsm/
    // Сэмплируем из текстуры глубины
    float2 moments = sampleShadowMap(shadowTexCoord);
    // Проверка находимся ли мы в тени
    float lit_factor = (realDepth <= moments.x);
   
    // Variance shadow mapping
    float E_x2 = moments.y;
float Ex_2 = moments.x * moments.x;
    float variance = min(max(E_x2 - Ex_2, 0.0) +
               1.0f / 10000.0f, 1.0);
    float m_d = (moments.x - realDepth);
    float p = variance / (variance + m_d * m_d);
    shadow = clamp(max(lit_factor, p), ShadowMult, 1.0f);
  }
}
return float4(basicTexture * DiffuseColor * light * shadow, 1);




Summary

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




P.S. Т.к. оригинал защищен авторскими правами, готов удалить пост по первому требованию. Если что - стучитесь в личку.
_________________
... и тогда я стал превращать людей в деревья.

Последний раз редактировалось: Dastox (10:39 21-07-2011), всего редактировалось 1 раз
    Добавлено: 19:52 20-07-2011   
Варсик
 545 EGP


Рейтинг канала: 4(81)
Репутация: 117
Сообщения: 4041
Откуда: Москва
Зарегистрирован: 22.12.2002
Киньте название того документа, из которого вы все это тырите.
_________________
WARNING: By reading this post you accept that this post is genius.
    Добавлено: 09:32 21-07-2011   
Guest
 2075 EGP


Модератор
Рейтинг канала: 5(167)
Репутация: 376
Сообщения: 27975
Откуда: Моск.
Зарегистрирован: 12.10.2004
Warstone :
Киньте название того документа, из которого вы все это тырите.
Dastox :
Sean James '3D Graphics with XNA Game Studio 4.0' (2010)

Иллюстрации добавь.
_________________
Трещит земля как пустой орех
Как щепка трещит броня
    Добавлено: 10:15 21-07-2011   
Dastox
 220 EGP


Рейтинг канала: 2(12)
Репутация: 48
Сообщения: 887
Откуда: Sol 3
Зарегистрирован: 31.08.2007
Guest :
Иллюстрации добавь.

добавил
_________________
... и тогда я стал превращать людей в деревья.
    Добавлено: 10:40 21-07-2011   
Jerry Rezet
 581 EGP


Рейтинг канала: 5(113)
Репутация: 86
Сообщения: 3365
Откуда: Санкт-Петербург.
Зарегистрирован: 01.04.2005
Dastox :
P.S. Т.к. оригинал защищен авторскими правами, готов удалить пост по первому требованию. Если что - стучитесь в личку.
Перевод тоже можно защитить правами. Улыбка
_________________
- Вы не представляете, как вам повезло, что я здесь. Вы об этом еще пожалеете. [c]
    Добавлено: 16:57 26-07-2011   
Dastox
 220 EGP


Рейтинг канала: 2(12)
Репутация: 48
Сообщения: 887
Откуда: Sol 3
Зарегистрирован: 31.08.2007
Не тот случай. Улыбка

Этот перевод делался только для того, чтобы программер "в теме" мог его прочитать. Поэтому переводил быстро и не проверял. Для более широкой аудитории пришлось бы тщательно поработать напильником (врубиться в тему, прочитать книжку целиком, узнать существующую терминологию или подобрать свою и т.д. и т.п.).
_________________
... и тогда я стал превращать людей в деревья.
    Добавлено: 22:06 26-07-2011   
Канал Игры Мечты: «Variance Shadow Mapping (VSM)»
 
  
Показать: 
Предыдущая тема | Следующая тема |
К списку каналов | Наверх страницы
Цитата не в тему: Они все плохие, особенно дуч, а летаю с ними потому, что все остальные еще хуже... один я только хороший. (dogmaut)

  » Variance Shadow Mapping (VSM) | страница 1
Каналы: Новости | Elite | Elite: Dangerous | Freelancer | Star Citizen | X-Tension/X-BTF | X2: The Threat | X3: Reunion | X3: Terran Conflict | X Rebirth | X4: Foundations | EVE Online | Orbiter | Kerbal Space Program | Evochron | VoidExpanse | Космические Миры | Онлайновые игры | Другие игры | Цифровая дистрибуция | play.elite-games.ru | ЗВ 2: Гражданская война | Творчество | Железо | Игра Мечты | Сайт
   Дизайн Elite Games V5 beta.18