среда, 29 февраля 2012 г.

Идет полным ходом переработка QuadShade, так как утилита в текущем виде довольно убога. Первая версия была написана с использованием собственного редактора текста. Тут надо признаться, что начинал я его писать очень давно и амбиций тогда было очень много, не в пример знаниям и опыту. В результате чего редактор получился кастрированным даже по отношению к обычному TMemo, однако с раскраской синтаксиса. Поняв, что с этим работать тяжко, он был сменен на SynEdit, однако и он преподнес кучу сюрпризов. Начиная с того, что не работает делит, заканчивая тем, что и раскраску-то не совсем можно настроить как хочется. В итоге и он меня разочаровал.
Несколько дней назад я прошерстил интернет в поисках достойной замены, но для делфи так и не нашел подходящего компонента (что странно, согласитесь, для делфи компонент-то хватает). Результатом всех поисков и некоторого кол-ва раздумий стало решение написать свой компонент. Изобрести очередной велосипед. Чем я благополучно и занялся.
Надо отметить, что код в шейдерах, как правило, довольно маленький, поэтому такие особенности как схлопывающиеся куски кода я даже и не ставил себе в задачи. Прошло три, может четыре дня разработки, сейчас это выглядит так:
На скриншоте можно лицезреть следующие особенности:
  • Нумерация строк
  • Подсветка измененных строк (желтая) и сохраненных (зеленая)
  • Свои полосы прокрутки (увеличиваются в толщине, когда к ним подводишь курсор)
  • Изменяемый размер шрифта (на скришоте 11й)
  • Подсветка переменных с одинаковыми названиями
  • Подсветка текущей строки
  • Отчерк на 80символах
  • Автоподсказка по набираемым функциям и зарезервированным словам
  • Опциональная тень под шрифтом (на скриншоте включена)
А также то, что невозможно с него увидеть:
  • Корректная обработка табуляций (изменяемый размер)
  • Копирование, вырезание, вставка текста
  • Адекватная реакция на page up/down, home, end
  • Выделение текста как мышкой, так и с клавиатуры
  • Поддержка колесика мышки
Разумеется не могу не отметить, что писал его с нуля и за основу взял TCustomControl. 

понедельник, 27 февраля 2012 г.


Доброго дня всем!
Сегодня я, как и обещал, расскажу о такой вещи как DuDv map. Немного погуглив я понял, что информации на этот счет почти нет, хотя сами по себе эти карты используются повсеместно. В чём же проблема?
Да, собственно, ни в чем. Единственной проблемой этих карт является изготовление. И эти карты не получили такого распостранения как карты нормалей или карты высот. Однако, получить их можно из карты нормалей, которую в свою очередь можно получить из карты высот. И, разумеется, её можно нарисовать самому. Как мы и поступили в игре blast-off:
 Что это такое и с чем это едят? Карта  смещений (dudv это сокращение от deltaU deltaV, тоесть дельта текстурных координат) представляет собой правила, по которым пиксель будет смещен. Каждой точке на финальном изображении будет сопоставлено значение из карты смещений, тем самым мы будем знать откуда брать результирующий цвет для этой точки.
Например оливковый цвет (0.5 красного и 0.5 зеленого) говорит нам о том, что точка берется ровно из того же места, где она и есть (без смещений координат). 
Вообще суть и вычисления крайне похожи на карту нормалей. В зеленой составляющей лежит значение от 0 до 1.0, 0.5 при этом является отсуствием искажений, 0.0 - полное искажение в минус по Y оси, 1.0, соотвественно, полное искажение в плюс. Насколько оно большое, разумеется, Решаете вы. В красной составляющей цвета лежит абсолютно тоже самое, только для горизонтальной составляющей. 
Таким образом R искажет U, а G искажет V.
На приведенной сверху текстуре карта строилась так, чтобы все пиксели внутри видимого шарика (его видно на текстуре как разноцветное пятно) брались из окружающей шарик текстуры. Этим мы добились как бы отражений на шарике. Хотя, в большинстве случаев эти карты используются совсем для иной цели, а именно для создания карт преломлений, скажем от стекла, воды, искажений пространства от взрывов.

воскресенье, 26 февраля 2012 г.

Счастливый день для всех нас, я наконец-то обновил версию до 0.3.0, и выложил её в свободный доступ на сайт. Теперь, собственно, могут качать и пользоваться не только избранные, а все желающие.
Гладкого кода!

понедельник, 20 февраля 2012 г.

 

            - С пробуждением, Энис Райт. Личный номер: 247538-62. – Приятный женский голос искусственного интеллекта корабля поприветствовал меня, а также еще четырёх членов экипажа. Камеры открылись и мы медленно, как бы лениво, вышагнули из них. Отсек, а точнее даже модуль корабля, где располагались криокамеры, был поистине огромным. Ряды камер, в каждой полулежал-полустоял человек. Через каждые пять камер находилась переборка, и свет был включён только в нашем отсеке. В остальных свет был настолько незначительным, что казалось будто камер бесконечное множество, так как дальние из них попросту терялись во мраке.
            Была наша очередь просыпаться. В криосне нельзя находиться слишком долго, с каждым днём шанс летального исхода увеличиваестся, поэтому ИИ будит по 5 человек каждые три дня, так, чтобы все 600 членов экипажа просыпались 1 раз в год. Мне предстояло еще порядка семнадцати пробуждений, тогда как шесть были уже позади. Основным, что волновало подавляющее большинство, были новости. Спин-передатчики работали на колоссальные расстояния, поэтому даже находясь между двумя галактиками приём был уверенный. Учёные из центра межгалактического полёта позаботились о том, чтобы с нами не терять связь, так что новости мы узнавали практически моментально. Единственное, что мешало узнавать их быстро – сон. Так что, некоторые узнавали их с задержкой до тридцати четырех лет реального (или одного года корабельного) времени.

(C) Void story, 2012

четверг, 16 февраля 2012 г.

Motion blur, или смазывание при движении. Получается автоматом в кино из-за большой выдержки плёнки, отлично имитируется пакетами трехмерной графики и обработки видео, но так сложна и заковыриста для реализации в играх.

При разработке игры blast-off, а точнее её прототипа, возникла необходимость использовать этот эффект. Да, я сказал "необходимость". Необходимость потому, что при больших скоростях задний план начинал настолько жутко мерцать (от быстрого движения), что глаза моментально уставали и игру хотелось закрыть.

Перед тем, как прийти к финальному на тот момент варианту было испробовано несколько вариантов, как теоретически, так и практически. О них дальше:

Давайте рассмотрим всё на примерах. Назовите мне игры с честным motion blur. Ну же, смелее. Дело в том, что их нет. Ну или почти нет. В любом случае честный motion blur будет слишком труднозатратен или будет нечестным. В чём же проблемы и почему его не делают честным? Каковы принципы смазывания.

Первое, что приходит в голову, это складывать несколько кадров воедино, рендеря картинку со смещением. Первая идея, зачастую, еще проще. Брать последние 3-5 кадров и с частичной прозрачностью накладывать друг на друга. Подход даёт самый честный motion blur, однако имеет огромнейший недостаток. Скорость.
Взять предыдущие кадры мы не можем, любой кто пробовал, поймёт почему подход провален: те кадры уже были, мы получим не смазывание при движении, а шлейф, к тому же создающий ощущение заторможенности происходящего. А это идет в разрез с тем, что хотим получить мы, а именно смазывание при движении. Результат будет выглядеть как-то так:


Печальное зрелище. При 60 кадрах мы получаем шлейф в почти 1\10 секунды. При некоторой доработке метода, мы можем решить, что можно сразу отрендерить эти 3-5 кадра, с учетом движения объектов между кадрами и получить честное смазывание и отсутствие шлейфа. И это будет правда. Но результатом такой реализации на практике станет падение кадросекунд в соответствующие 3-5 раз. В Blast-off мы не могли так жертвовать скоростью, поскольку нетбуки не давали при нашем уровне графики больше 50-60кадров, а слабенькие ноутбуки более 170 кадров в секунду. Полагаться на мощность компьютеров, выдающих более 1000-1500 кадров в секунду не хотелось, так как играть в подобные игры люди любят и, украдкой, в рабочее время на работе. На рабочих лошадках при этом ничего лучше интегрированного виде от Intel не стоит.

Мы пошли по пути наименьшего сопротивления. Решив, что самым смазываемым эффектом является, фактически, только фон, было решено смазать для начала только фон. Сделать это совсем несложно постпроцессом. Выглядит код шейдера так:

  float4 Output; 
  for (int i = 1; i < NumSamples; ++i)
  {
    float4 currentColor = tex2D(DiffuseMap, texcoord);
    texcoord -= Vec;
    Output += currentColor;
  }
  Return Output / NumSamples;

Где Vec - вектор движения фона, а NumSamples это количество псевдокадров для смазывания (в нашем случае 13. Эффект получается совсем не прожорливый и выглядит так:
Проблемой такого подхода являются динамические объекты, двигающиеся отдельно от фона. Если их поместить в тот же конвеер, что и фон, они смажутся, если же рисовать поверх, то будут слишком четкими. Тут тоже можно считерить. Отрендерив всю сцену дважы в два разных буфера, в рендертаргет как есть и во второй рендертаргет только альфой, закодировав цветом смещение. В красный смещение по Х, в зеленый по У (это называется DuDv map и о ней я расскажу в дальнейших постах). Результатом (для двигающихся объектов) будет такая картинка:

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

Выводом из всех проведенных экспериментов можно сделать следующее. Постпроцессинг не может дать качественного и правильного motion blur. В то же время честные методы не могут дать приличной скорости работы. Возможно, что комбинирование этих двух методов поможет. Тоесть 2 картинки - прошлый и текущий кадр (практически не съест скорости в меру того, что предыдущий кадр всеравно уже отрендерен), сгенерировать DuDv карту смещений для объектов и уже на основе этих трех исходных изображений генерировать более честный эффект смазывания.

Тут я осмелюсь разочаровать читателя, так как ни скриншотов, ни кода для данной реализации пока еще у меня нет, но как только я его опробую, обязательно отпишусь в блоге.

воскресенье, 12 февраля 2012 г.

Всем доброго дня.
Сегодня, как я и обещал, веду свой рассказ о новой системе отрисовки шрифтов в quad-engine. Система пока еще не внедрена, но уже протестирована и будет встроена в следующей же публичной версии. Ничего нового придумано не было, это всего лишь метод distance field. Однако, как показала практика, многие о нем не знают и даже не догадываются. Самое занятное в этом методе, то, что для его реализации вовсе ненужны шейдеры, этот метод можно реализовать обычным альфа-тестированием, не теряя при этом скорости ни капли.
Давайте перейдем к тому, как это работает.

Самое сложное в отрисовке глифов методом distance field это генерация исходной текстуры. Для этого берется глиф высокого разрешения, например:
Далее выбирается размер текстуры, который будет сгенерирован для этого глифа, разумеется существенно меньшего размера. И для каждой точки исходного изображения в текстуре берется эквивалентная точка. Для нее по исходному изображению считается дистанция до ближайшей точки другого цвета (тоесть границы) и записывается в текстуру следующим образом:
Если у нас прозрачный цвет (тут белый), то дистанция до черного шифруется как 0..128, где 128 это нулевая дистанция, тоесть ребро.
Если прозрачность ненулевая, (тут черный). то чем дальше до белого пикселя, тем больше значение в пределах от 128..255
В итоге мы получаем такую текстурку:

Маленькая и скромненькая, но она позволит нарисовать нам глиф, схожий по размерам с исходным и не о с очень большими искажениями. Загружаем текстурку и рендерим ее, скажем, с 400% увеличением (и билинейной фильтрацией). Получаем, ожидаемо, что-то вроде этого:
Печальное зрелище. Такой картинкой много текста не отрендеришь. Оговорюсь что это отображение альфаканала. РГБ канал содержит чисто белый цвет. Далее мы включаем альфа-тестирование, где устанавливаем значение 0.5 (или 128), тоесть от картинки осечется всё, что меньше 128 по альфе. Тут нам поможет аппаратная особенность билинейной фильтрации, а именно то, что видеокарта интерполирует все значения, и делает нам градиенты, тем самым как бы восстанавливая часть утерянных значений.
Результатом такой отрисовки будет такая картинка:
Тут надо отметить, что в моем случае вывод идет через простейший шейдер, что позволило мне сделать по контуру глифа антиалиасинг. Еще раз напомню, что это отрендеренно из той мелкой текстурки с увеличением в 400%.
При увеличениях до 200% искажений и неровностей по контуру глифа нет вообще, так что шрифт можно использовать в довольно большом диапазоне увеличений, не задумываясь о том, что он "поплывёт" и размутнится.

Данная технология разработана и используется компанией Valve в игре Team Fortress 2. Больше подробностей (на английском) можно прочитать в приведенной выше ссылке. В частности, с помощью такого подхода к глифам можно добавлять антиалиасинг, обводку, свечение, тени и прочее.

суббота, 11 февраля 2012 г.

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

// ???-?? ??????? ?????? ? ????? ??? ????? ????????
Первое место по праву. Нет, с кодировкой там всё в порядке. Но расшифровать удается только первые два слова. "кто-то"? "что-то"? "где-то"? 

//для читабельности :) 

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

//А ещё стояла задача тупо и жестко хардкодить!!! так что вот такой вот огород :)!!!
Вот тут правда огород. Хардкода на 250+ строчек. Хороший такой метод, длинный :)

//   // Импорт-экспорт документов
//   // Неизвестно, где используется, поэтому скроем
Без комментариев.

  // через четыре года
  // здесь будет город сад ...
Там ничего не работало ;)

'Попробуйте выполнить запрос в другое время (или через пару минут)'  
А вот это гениальное сообщение выдается пользователю. В другое время, или через несколько минут... ага, или никогда.

if _Settings = nil then
begin
  ShowMessage('Ошибка - Пропал объект _Settings! К разработчикам');
  Exit;
end;
Этот код примерно тоже самое делает. Самой крутой вывод ошибок.
Надо сказать, что системе уже много много лет, и разработчиков там поковырялось, надо полагать, достаточно. Поэтому иногда встречаются такие забавные места:

{
 IAP - 20030417
 Временно.
}
Нет, я, в принципе, не против временного. Вы на дату посмотрите...
И еще немного временного кода:

Showmessage('сейчас только возвращаю статус в первичную обработку без контролей! потом будет по-человечески');
Да, это сообщение для пользователя!

// Удалить!!! т.е. Вернуть на место=снять комментарий 
Увы, не смог помочь тому разработчику, не телепат.

//временное (?) :) 
Тут вообще похоже на переписку двух или трех разработчиков.

// !!! Или лучше по-другому??? !!!
// Да точно, лучше по-другому!
И тут переписка :) 

// Что новенького...
Ммм... 

// это для того, чтобы повторно не запрашивать данные на одну и ту же запись (западло искать, почему иногда такое бывает)
Ага, правда, фиг его знает :)

{TODO: ???} 
Да уш, я сам непонял.

Самое занятное, что, наверняка, это далеко не всё, что там есть. Каждую неделю находится что-то новенькое.

четверг, 9 февраля 2012 г.

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

Начну, пожалуй, с того, что похвалюсь победой на IGDC. Победили в 77м конкурсе джампера с работой Blast-off. Писалась игра менее десяти вечеров\ночей, писалась, естественно на кводе. Результат получился более чем хороший.


Скачать можно тут. Весит это чудо 3.6МБайта.

В ближайшее время хочется написать посты о постпроцесс шейдерах, в частности использованных в игре, хочется написать о грядущем изменении в системе рендера шрифтов и многих других вещах. Оставайтесь на связи, обновления будут появляться чаще.