?

Log in

No account? Create an account

Записки о геймдеве

149 Итераций !
joker_ru
50 итерация ролика Uncharted в сравнении со 149 (финальной) итерацией.

http://www.ign.com/videos/2011/10/19/uncharted-3-drakes-deception-trailer-progression

Uncharted PreVis
joker_ru
Очень, круто. Предвизуализация геймплея и арт-стиля анчартед.

http://www.ign.com/videos/2011/10/20/uncharted-3-drakes-deception-concept-video

Если в Windows часы сами перевелись.
joker_ru
Нужно применить, вот этот фикс (http://support.microsoft.com/kb/2570791/ru), он учитывает отмену перехода на летнее/зимнее время в России.

Дайте две!!!!! Мой мозг!
joker_ru
Ыыыыыыыыыыыыы!!!!!, других слов просто нет.


update
joker_ru
s.makeev - собака - corp.mail.ru
Tags:

(no subject)
joker_ru


Видео с удаленными сценами из God of War3.

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

Быстрый HDR, используя только LDR текстуры
joker_ru

Итак, нам очень хочется HDR. Но у нас платформа, медленно и плохо работающая с рендертаргетами с бОльшей чем 8 бит на канал глубиной цвета (консоль). Вроде бы логичный выход, делать весь рендер RGBE или любым из его аналогов, но очень не хочется терять альфу. Казалось, что же тут можно придумать?

Будем рассуждать логически, в нашем мире обычные фотоаппараты “мыльницы” - как раз имеют ярко выраженный эффект, который в играх называют HDR. Засвечивают очень яркие области или и полностью затемняют очень темные. При этом если направлять камеру с ярких областей на темные, то отлично видно эффект адаптации “глаза” к освещенности. При этом мыльницы получают с матрицы ну максимум по 12 бит на канал, а старые по 8. Как же они это делают?

Камера постоянно производит матричный замер экспозиции, используя одно или несколько значений с матрицы, оценивая таким образом общую яркость/контрастность кадра. И используя полученное значение, в зависимости от заданного режима съемки производит коррекцию экспозиции в нужную сторону. Таким образом, камера итеративно подбирает нужное значение экспозиции. Это и есть та самая нужная нам, “адаптация глаза к свету”, которую в играх выдают за HDR эффект.

Что же мешает делать нам тоже самое, а не использовать дорогой рендер в рендертаргет с плавающей точкой? Правильно, ничего не мешает - давайте попробуем.

Итак алгоритм следующий:

  • Рисуем в рендертаргет R8G8B8(X8) все что захотим, с одним отличием - перед тем как вернуть финальный цвет из пиксельшейдера умножаем его коэфицент яркости (Exposure Adjustment)
  • После того, как кадр нарисован, производим оценку яркости кадра (основная хитрость как сделать это быстро, об этом ниже)
  • В зависимости от посчитанной яркости кадра изменяем Exposure Adjustment, если кадр слишком темный, повышаем наш множитель. Если слишком светлый, понижаем.
  • Далее, повторяем все заново.

Как видно, алгоритм очень простой. Но нам нужно оценивать яркость отрисованного кадра, для правильного сдвига Exposure Adjustment. Обычно, для оценки яркости кадра используется гистограмма, но мы же хотим сделать быстрый HDR и желательно без использования CPU, а классическая гистограмма для этого не лучший вариант.

Вот мой вариант быстрого экспозамера кадра на GPU:

  • Копируем полученный кадр в квадратную текстуру, меньшего размера чем экран, при этом производим оценку яркости каждого пикселя следующим образом: считаем яркость пикселя и в завсисмости от яркости в разные каналы RGB кладем разные значения. В R канал кладем коэфицент, что пиксель недосвечен, в B канал кладем коэфицент, что пиксель пересвечен, в G канал кладем нормализованный остаток: 1.0 - R - G. Таким образом, полностью черный пиксель превратится во float3(1, 0, 0) а полностью белый во float3(0, 0, 1). Сумма 3-х компонентов RGB всегда нормализованна и равна 1.0. Фактически это оценка данного пикселя 3 функциями dark, medium и light colors (гистограмма с 3 корзинами). Таким способом, мы получили оценку каждого пикселя отдельно, но нам нужна оценка всей картинки вцелом.
  • Входные данные при предыдущем шаге сформированны таким образом, что теперь оценку освещенности для всего кадра, можно сделать очень быстро. Рисуем получившуюся текстуру с коэфицентами, в текстуру с разрешением в два раза меньше (в следующий mip). При этом используем LINEAR фильтрацию текстур и делаем каждую нашу выборку между текселями. GPU при этом автоматически сэмплирует 4 текселя и т.к. мы используем LINEAR фильтрацию фактически проведет нормализацию результата (tex1 + tex2 + tex3 + tex4 * 0.25). Результат: оценка яркостной составляющей блока пикселей 2×2. Повторяем шаг до размера размера текстуры 2×2


  • Теперь у нас есть гистограмма всей картинки (правда всего на 3 корзины) и нам нужно сдвинуть нашу коррекцию экспозиции. Т.к. зачитывать данные от GPU к CPU не хочется (данных хоть и мало, но синхронизация GPU с CPU это вообще всегда медленно), заводим текстуру Exposure Adjustment размером 1×1 пиксель (по идее надо float текстуру заводить, но я попробовал хватает точности и у обычной 8 битной). Данная текстура всегда будет лежать в текстурном кеше GPU и фактически является константой. Эту текстуру и используем как множитель Exposure Adjustment.
  • Теперь у нас есть две текстуры: 1×1 текстура “множитель” для HDR и текстура 2×2 гистограмма разложенная в 3 buckets. Оцениваем какая из часть гистограммы “перекошена” и сдвигаем значение в текстуре в нужную нам сторону - обычный рендер в текстуру, без зачитывания данных в CPU.
  • Результат: в зависимости от яркости кадра мы сдвинули Exposure Adjustment в нужную нам сторону, очень быстро, полностью на GPU и используя только текстуры 8 бит на канал.

Так выглядит текстура с коэфицентами яркости
=================================================

Вот тут, можно скачать демо со всеми исходниками (37.7Мб) - в котором HDR реализован описанным выше способом. Демо работает на PC и на X360 (у кого есть XDK + Devkit могут тоже потестировать). Там совсем простой алгоритм экспо-коррекции (обычный сдвиг), можно подумать и сделать похитрее. Также, развивая идею дальше: коэфицент Exposure Adjustment не обязательно должен быть константным для всего кадра. Мне кажется, если сделать для различных зон экрана разную коррекцию экспозиции (например сеткой 16×16) то будет еще лучше.

Управление: зажав правую кнопку мыши можно крутить головой и летать с помощью WASD.

Заодно, добавил ToneMaping как в Uncharted2,  хотя он и не обязателен, можно просто клемпить получившийся результат.

update: обновил демку, на экран для отладки выводятся результаты анализа картинки и искуственно добавил тормозов для CPU, иначе при FPS > 1000 float дельта тайм себя плохо ведет :)


Данный пост размещен в моем личном блоге SergeyMakeev.com.

Ура! Сайт официально запущен
joker_ru

Ура! сайт нашей игры наконец то запущен!

http://www.CaptainBloodGame.com/
Всем добро пожаловать!


Данный пост размещен в моем личном блоге SergeyMakeev.com.

Наша игра
joker_ru

Превью нашей игры на GameTrailers


Данный пост размещен в моем личном блоге SergeyMakeev.com.

Волшебный блендинг
joker_ru

Давненько ничего не писал в блог, буду исправляться потихоньку.

В системах частиц и всяких спецэффектах часто нужно рисовать с различным блендингом,
классически это add blend и alpha blend.

Обычно рисуют сортированные (по эмиттерам или по частицам) партиклы с alpha blend, а потом поверх кладут частицы с add blend (их уже можно не сортировать).

Но, художникам иногда очень хочется нарисовать партикл с add blend, а поверх него с alpha blend.

И уж точно программистам всегда хочется рисовать все частицы за один batch, независимо от их блендинга.

Итак, немного простой математики:
Формула блендинга destColor = sourcePixel * srcBlend + screenPixel * dstBlend;

Для add blend задают srcBlend и dstBlend как one, получая:

//blend function
destColor = sourcePixel + screenPixel;
_Winnie C++ Colorizer

Для alpha blend задают srcBlend как srcAlpha и dstBlend как invSrcAlpha, получая:

//blend function
destColor = sourcePixel * srcAlpha  + screenPixel * invSrcAlpha;
_Winnie C++ Colorizer

Так как же совместить эти два режима блендинга в одном ?

Задаем srcBlend как one и dstBlend как invSrcAlpha, получаем:

//blend function
destColor = sourcePixel + screenPixel * invSrcAlpha;
_Winnie C++ Colorizer

Теперь, следите за руками :) несколько манипуляций в pixel shader:

//0.0 это Add blend
//1.0 это Alpha blend
float addOrBlend = 0.0; 

float4 ps_test( PS_INPUT pix ) : COLOR0
{
   float4 texel = tex2D(baseMap, pix.texCoord0);
   texel.rgb = texel.rgb * texel.a;
   texel.a = texel.a * addOrBlend;
   return texel;
}
_Winnie C++ Colorizer

Посмотрим, что же получилось и самое главное, как.

Итак наша формула блендинга destColor = sourcePixel + screenPixel * invSrcAlpha;
при значении addOrBlend = 0.0; получаем (с учетом математики в pixel shader):

//blend function
destColor = sourcePixel * srcAlpha  + screenPixel;
_Winnie C++ Colorizer

при значении addOrBlend = 1.0; получаем (с учетом математики в pixel shader):

//blend function
destColor = sourcePixel * srcAlpha  + screenPixel * invSrcAlpha;
_Winnie C++ Colorizer

Как видно, add blend получается не совсем “чистый”, цвет текстуры умножается на альфу, но это дает нам возможность плавно менять addOrBlend соответственно плавно изменяя режим блендинга.

Если вдруг нужно только бинарное значение и хочется “чистый” блендинг, можно немного изменить наш шейдер: texel.rgb = texel.rgb * lerp (texel.a, 1.0, addOrBlend);

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

Надеюсь это пригодится и в вашем проекте.


Данный пост размещен в моем личном блоге SergeyMakeev.com.