вторник, 8 ноября 2011 г.

Философия квода (quad англ. [transcription] ).

Первое, что важно, в использовании квода - он должен быть простым. То есть вызывать как можно меньше вопросов, в идеале не вызывать совсем. Это обеспечивается архитектурой, построенной на интерфейсах, простыми и понятным именованием констант, переменных, интерфейсов, методов и параметров. Разумеется, объектно-ориентированный подход также упрощает понимание. Код квода получается максимально лаконичным, но тем не менее таким же мощным, как и предполагалось.
Второе, что тоже очень важно, необходима возможность использования очень неочевидных функций, как то: изменение фильтрации текстур или режима обработки минусовых UV координат, свободное текстурирование и прочее.
Довольно занятно, что в большей мере, всё это удалось воплотить в той реализации квода, что есть сейчас. Многое еще предстоит, но основное направление уже задано.
Возможно надо было разделить рендер и системные функции. Более того - пугает, что это возможно придется делать. А это будет значить, что код будет поломан. Поэтому это останется до 2.0
Как я уже однажды писал - шейдеры были одной из фич, которые очень хотелось иметь в 2д движке. К сожалению, большинство движков (особенно под Делфи) не имело поддержки шейдеров, или же нарушало первое или второе правило (описаны выше).
Знание DirectX для квода не нужно абсолютно. Единственная вещь, которая может потребоваться - знание HLSL, для написания шейдеров. Однако, шейдеры не являются обязательными к использованию, так что данным аспектом можно пренебречь.

Сейчас в планах дальнейшее усовершенствование основной части и разработка новых модулей. Частицы, ГУИ, создание и управление окном, спрайтовый движок и прочие радости жизни.

понедельник, 31 октября 2011 г.

Баловался с титрами. Вот что вышло:

Короткий сегодня пост...

среда, 26 октября 2011 г.

Сегодня было принято решение, которое просто таки обязано популяризировать quad. Итак, quad обзаведется базой шейдеров. Как это будет выглядеть:

Monochrome:
Применение:


Quad.RenderToTexture(MyRenderTarget, True);
  // Render your scene here
Quad.RenderToTexture(MyRenderTarget, False);

ShaderMonochrome.SetState(True);
MyRenderTarget.Draw(0, 0, $FFFFFFFF);
ShaderMonochrome.SetState(False);

<Ссылка на бинарный файл шейдера, готовый к использованию>

Код шейдера:
sampler2D DiffuseMap : register(s0);

float4 std_PS(vertexOutput Input) : COLOR {
  float4 Output;

  float4 tex_diff = tex2D(DiffuseMap, Input.TexCoord);
  Output = (tex_diff.r + tex_diff.g + tex_diff.b) / 3;
              
  if (Output.r < 0.2 || Output.r > 0.8) Output.r = 0.0; else Output.r = 1.0;
  if (Output.g < 0.2 || Output.g > 0.8) Output.g = 0.0; else Output.g = 1.0;
  if (Output.b < 0.2 || Output.b > 0.8) Output.b = 0.0; else Output.b = 1.0;

  return Output;
}


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

Более того, если кто-то выразит желание помочь с пополнением базы шейдеров - милости просим!

понедельник, 10 октября 2011 г.

Сегодня открою завесу "тайны", над IGDC69 демо. Очередной howto в деталях.
Для начала мне нужна была некая сцена, которую нарисовал прямоуольниками, спрайтами шариков, и шрифтом вот так:
Ну так это же страшно и брр... Ладно, как нам добиться эффекта посимпотичнее. Думаем, решаем что после мы это все сделаем интерлейсом. Пройдемся полосочками в режиме multiply, получаем:
Теперь можно работать над постпроцессом. Все, что мы сейчас нарисовали, засовываем в рендертаргет. Рендертаргет понадобится для того, чтобы сделать из него еще один, и оставить в том виде, что есть сейчас. 
Открываем еще один рендертаргет, вчетверо меньшего разрешения и рендерим туда с горизонтальным блюром по гауссу содержимое главного рендертаргета, затем делаем с полученным тоже самое по вертикали:

Затем оставляем их впокое, берем первый, главный рендертаргет и проходимся шейдером, добавляя хроматизма, зависящего от расстояния пикселя от центра картинки, а также добавляем (опять таки в зависимости от того же расстояния) серого цвета. Таким образом картинка в центре более контрастная чем по краям, и без разложения цвета на составляющие:

Затем делаем радиальный блюр по гауссу. Также как и в предыдущем проходе, с добавлением хроматизма, делаем это в зависимости от расстояния. Чтобы уложиться в модель шейдеров 2.0, приходится опять делать блюр сначала горизонтальный, затем вертикальный. Ну что, вроде получается уже неплохо?
Теперь финальная сборка. Тут я прибегаю к небольшой хитрости, и жму все изображение по вертикали, чтобы получить черные полоски сверху и снизу. Это придает эффект кино. Сначала рисую вот этот, полученный мной рендертаргет с хроматизмом, затем тот, что получили раньше с добавлением, получая тем самым эффект свечения всего в кадре:

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

воскресенье, 18 сентября 2011 г.

Долго сюда не писал, особо нечего было поведать. Но прошло время, и у квода достаточно много изменений и доработок. Итак, готовлю к публичной порке 0.2.2 версию. Что же изменилось?

QuadFont:
  • Появилась возможность посчитать высоту любого текста.
  • Текст теперь правильно рассчитывает межстрочные интервалы для многострочных текстов.
  • Появился SmartColoring, позволяющий раскрашивать текст, вызывая отрисовку по прежнему одним вызовом. "Red, Lime, Fuchsia" например можно нарисовать передав в отрисовку следующую строку "^$RRed, ^$LLime, ^$FFuchsia".
QuadTexture:
  • Текстура получила ряд методов для получения размеров текстуры, рабочей области текстуры, паттернов.
QuadRender:
  • Возможность одним вызовом создать и загрузить объекты. CreateAndLoadTexture, CreateAndLoadFont, CteateAndInitializeTimer.
  • Возможность задать OnError процедуру.
  • Автоматическая запись в лог ошибок отрисовки.
  • Включение\выключение автоматического расчета TBN для спрайтов.
Также  имеются многочисленные мелкие фиксы, о каждом из которых писать не хочется. Но работа проведена большая. В ближайшие пару дней всё появится. Заранее прошу прощения, если что-то забыл упомянуть.

    четверг, 1 сентября 2011 г.

    Новость сегодня короткая. Обновился до 0.2.1. Добавил десяток методов, провел рефакторинг и чистку исходников, поубивал потенциальные баги.

    quadengine021.rar

    среда, 10 августа 2011 г.

    Помоему тау лучше...

    пятница, 29 июля 2011 г.


    Void story получит музыкальное сопровождение от Poets of the Fall. Саундтрек игры пополнится сразу двумя песнями группы. Это уже не первый раз, когда песни группы звучат в играх. Так песня Late Goodbye играла в титрах Max Payne 2, Lift прозвучала в титрах 3DMark 2003, a War стала заглавной темой для Alan Wake.

    понедельник, 25 июля 2011 г.



    Да, да... Это реалтайм. Да, она крутится. Да, в перспективе. Да, светится. Нет, это не фотошоп. Фотошоп был тут:

    пятница, 22 июля 2011 г.


    Powered by quad-engine

    среда, 20 июля 2011 г.

    Сегодня запись посвящена созданию 2д освещению. А именно рейтрейсингу теней. Оговорюсь сразу, Идею я практически полностью повзаимствовал (за исключением моих доработок) у Catalin Zima. Так как идея приглянулась, а алгоритм расписан, я приступил к созданию. Однако, у автора статьи были толи ошибки в описании, местами недоговорки, поэтому пришлось повозиться.
    Итак. Как сказано у автора сначала надо отрендерить альфаканалы в пустой рендертаргет для получения ЧБ изображения. Сразу же следует первая оговорка. Центр рендертаргета это источник света. Так что если у Вас источник не ровно по центру, рендерить в рендертаргет надо все со смещением. Это важно!
    Хорошо, дальше надо все это безобразие немного раскрасить. Точнее сказать надо погасить интенсивность "стенок" от центра к краю. Для наглядности в красном цвете
     Дальше начинается очень интересная часть процесса. Дело в том, что левую и правую часть изображения надо "развернуть"! Суть в том, чтобы представить картинку в виде песочных часов >< а далее растянуть треугольники до прямоугольников. И тоже самое сделать в вертикальной составляющей. Полученные результаты дадут нам каждый луч идущий из центра картинки до края, но все эти лучи будут параллельны и лежать на одной картинке. В разных цветовых каналах соотвественно. Получаем что-то вроде этого:
     После идет уменьшение картинки по горизонтали. Уменьшаем вдвое каждый раз, пока не получим картинку шириной 2 пикселя. На каждом шаге мы ищем минимальное значение пикселя (в понятии алгоритма минимальное зачение пикселя значит наиближайший к центру пиксель. Помните, мы градиентом уменьшали интенсивность?)
    Стоит оговориться что тут обязательно надо отключить фильтрацию текстур на этом шаге, иначе вместо результата будет все ооочень плохо.
    Как только мы получили наше изображение с шириной в 2 пикселя, мы знаем для каждого луча ближайшую преграду относительно центра.

    Получение освещенной области теперь будем считать легко: берем расстояние от центра до текущего пикселя и сравниваем со значением дистанции взятым из соотвествующего пикселя в двупиксельной текстуре. Если расстояние меньше - область освещена, если нет - темная.
     
    Все вышесказанное можно почитать в блоге автора, ссылку на который я дал раньше. Такой свет нас не устраивает, поэтому мы пройдемся размытием по гауссу.
    И, еще раз по вертикали. Зачем тут синий? Чем синее точка, тем сильнее надо размыть (дальность от источника света).
    Теперь эту область можно наложить через multiply на свою картинку. Это мы сделаем в финальном шаге. Так как мой пример что-то вроде пакмана, я через мультиплай добавлю "еду" для пакмана :)
    Чтобы эффект был эффектнее, добавим нормалмеппинг на "пол". Рендереим саму сцену:
    Рендерим стенки и точки-еду на пол:

    И финал: Накладываем маску со светом через multiply:


    Вопросов данная методика может породить больше чем ответов, поэтому не стесняйтесь спрашивать. На все отвечу.

    Как это выглядит "в жизни"

    вторник, 19 июля 2011 г.

    Итак, немного об эволюции шейдера POM. 

    Первые тесты шейдера дали приятную картинку, однако чрезмерный спекуляр и жесткие тени все сильно портили, делая скалы пластиковыми и мокрыми.
    Чтобы этого избежать, спекуляр был уменьшен до 15%, и был введен ambient источник света, дающий даже в тенях 10% яркость пикселей. Дополнительно был проведен тест с рисованием теней на поверхности. Так больше стало похоже на день:

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


    Так как вода не плоская, необходимо добавить рябь. Мокрая — блики. Отражающая — отражения облаков.
    Дальше идет настройка. Отражения делаем темнее, прозрачность воды меньше, блики немного убираем и пр:
    Продолжаем детализировать воду. Теперь сделаем отражения в воде не плоскими, а такими, какими они и должны быть при соотвествующих волнах. Добавим воде свой цвет, увеличим влияние глубины на цвет воды:
    Ой, значение цвета однородно для всей поверхности воды. Непорядок. Где толща воды больше, и вода должна быть темнее и отражать больше. У берегов же отражать надо меньше, а дна видеть больше. Правим:

    Ну и на закуску с немного сюрреалистичным ржавым ландшафтом:
    Скоро...

    воскресенье, 15 мая 2011 г.

    Безвозвратно двигаемся в сторону второй альфа-версии. Что же будет нового:
    • Создание окошка и управление им средствами IQuadWindow интерфейса.
    • Спрайтовый движок и интерфейс IQuadSprite. Разумеется с проверкой столкновений, анимациями и отбрасыванием невидимых спрайтов из отрисовки.
    • Надстройка над IQuadShader для удобной реализации многопроходных поспроцесс фильтров.
    • Раскрашивание выводимого через IQuadFont текста посредством тегов.
    • Наконец-то IQuadParticles для реализации системы частиц.
    Это навскидку. Что-то уже есть, что-то частично.

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

    вторник, 3 мая 2011 г.

    Сегодня никаких эффектов и новых фич. Сегодня анонс немного иного рода. Сегодня под маркой Quad-games  стартуют (точнее сказать анонсируются) две игры, постоенные на quad-engine. Это Rusty War и Void Story.

    Rusty Wat представляет из себя классическую двумерную стратегию в реальном времени в стиле Dune и Comand&Conquer.

    Void story — научно-фантастический скроллер. Не настолько олдскульный, как Rusty war, но также способный «пробить» на ностальгию уже бывалых игроков.

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

    воскресенье, 10 апреля 2011 г.

    Смотрел TRON:legacy и зацепил меня эффект в титрах фильма. Чем описывать, лучше покажу:

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

     Впечатлил он меня именно с точки зрения реализовать в реалтайме самому. Что я и сделал:




     Скриншот неравносильный и эффект усилен, но думаю, оценить можно.

    пятница, 8 апреля 2011 г.

    Версия quadfont доведена до вменяемого состояния. Утилита теперь поддерживает большие шрифты, сама подбирает размер текстуры и имеет более дружественный интерфейс:

    среда, 9 марта 2011 г.

    Сегодня всё кратко — открылась wiki по quad-engine. Справка, по большому счету.
    http://quad-engine.com/wiki/

    А также форумом.
    http://quad-engine.com/bb/

    среда, 2 марта 2011 г.

    Good news everyone!
    Продолжается экспансия в сторону интерфейсов. Перевод почти закончен и все работает просто отлично. Наисправлял много мелочей. Там затюнил, здесь подрихтовал. В частности добавил возможность запуска в полноэкранном режиме на любом из имеющихся в системе мониторов. В процессе доделывание автоопределения размеров изображения до загрузки. Текстурный блок вот-вот научится загружать DXT1, DXT3 и DXT5 форматы файла DDS. Вообщем 0.1.4 не за горами :)

    среда, 16 февраля 2011 г.

    quad engine 0.1.3
    Закончен перевод базовых классов на интерфейсы. Создан заголовочный файл. Как только все работы по переводу будут завершены, quad можно будет использовать в любом языке программирования, поддерживающем интерфейсы. К сожалению, жертвой интерфейсам стала необходимость запечь весь quad в dll. Хотя, на текущий размер скромен — 280Кб. В масштабах современных разработок размер более чем скромный, не так ли?
    К счастью, подход имеет больше плюсов, чем минусов. И еще один из таких плюсов — ООП подход.
    На текущий момент реализованы 4 базовых интерфейса: IQuadRender, IQuadTexture, IQuadFont и IQuadShader. Боюсь, что до завершения переделки движка на интерфейсы, новостей не будет. Также надеюсь что переделка не займет много времени.

    вторник, 8 февраля 2011 г.

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

    program Project1;

    uses
      Windows, QuadWindow, QuadRender, QuadLog;

    var
      qr : TQuadRender;
      ql : TQuadLog;

    procedure Main;
    begin
      qr.BeginRender;
      qr.Clear(0);
      qr.Rectangle(0, 0, 10, 10, Random($FFFFFFFF));
      qr.EndRender;
    end;

    begin
      CreateWindow;

      ql := TQuadLog.Create;

      qr := TQuadRender.Create;
      qr.Initialize(h_Wnd, 640, 480, ql);

      OnIdle := Main;
      EnterMainCycle;
    end.



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

    пятница, 4 февраля 2011 г.

    Как ковалось железо, или "параллакс меппинг и использование изнутри".

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

    Шаг1:
    В рендертаргет (в примере равный размеру окна) рендерится диффузная карта местности.

    Шаг2:
    В тот же рендертаргет через multiply рендерятся "тени" от объектов. Пока они плоские, также как и сама карта диффуза, но она исказится чуть позже.
    Шаг3:
    Во второй рендертаргет рендерится карта высот для всего ландшафта.
    Шаг4:
    В третий рендертаргет рендерится карта нормалей для всего ландшафта.
      
    Шаг5:
    Тут начинается все самое интересное. Сразу забыл оговориться, что три рендертаргета используемых в предыдущих шагах это три текстуры в трех разных стейтах и ипользуются они одновременно.
    Эти три текстуры прогоняются через шейдер (о нём позже), который создает эффект "вдавливания" текстуры. Но так как в особо сильно вдавленных местах информация о текстуре заканчивается, мы получаем неприятные артефакты вокруг результата, в зависимости от степени вдавленности (в нашем случае максимальное вдавливание равно 128 пикселям). К сожалению, избавиться от эффекта невозможно, однако можно немножко считерить. 
    Вариантов решения проблемы два. Первый — научить шейдер не вдавливать текстуру, а выдавливать. Второй — затекстурировать полигон так, чтобы текстурные координаты были не 0,0 - 1,1, а что-то вроде 0.1,0.1 - 0.9,0.9 или же просто увеличить полигон за пределы экрана в каждую сторону на 128 пикселей. Я избрал метод вдавливания так как при вдавленном методе не искажаются самые высокие участки, которые больше всего и видны игроку. Поэтому использовал второй метод решения проблемы.
    Собственно что получится без коррекции  при попытки "вдавить":
     Когда текстурные координаты поправлены и артефактов нет, получаем то, что хотели, но чуточку побольше размером. А так как мы в диффузный рендертаргет нарисовали и тени — получаем еще и тени, причем с учетом искажения по рельефу:
    Шаг 6:
    Осталось дорисовать сами объекты поверх ландшафта, делая это привычным методом. Тут уже никаких секретов нет.

    Шейдер:
    Шейдер заслуживает отдельной статьи так как достаточно объемен. Сначала в программе высчитывается TBN для вершин (в quad-engine делается автоматом), далее TBN, матрица проекции и позиция источника света передаются в вершинный шейдер. Вершинный шейдер переводит все полученные параметры в тангент-спейс полигона и дальнейшая работа уже идет с ним. На выхлопе для каждого пикселя вектор света и вектор вида.
    Пиксельный шейдер. Из карты высот берется значение высоты и учитывая вектор вида в данной точке ищется пересечение луча вида с плоскостью с учетом поправки на высоту (взятую из карты высот). Далее идет 8 итераций на корректировку текстурных координат, точнее на поиск более близкого значения к желаемому. После нахождения производится ленейная интерполяция в пределах 1\8 глубины (для этого и делается 8 проходов). Таким образом получается достаточно точное значение, которое и берется как реальные текстурные координаты. Пиксель из этих текстурных координат уже и выводится. Также по этим текстурным координатам берется вектор из карты нормалей и производится затенение картинки, согласно расположению источника света (в примере ровно по центру экрана). Добавляется спекуляр и эмбиент по вкусу и результат готов.

    Подробно с кодом почитать о Parallax mapping можно вот здесь.

    четверг, 3 февраля 2011 г.

    Всем доброго вечера. Сегодня спешу представить сильно доработанную, но пока не финальную версию параллакс мэппинга в исполнении quad. 
    Идея возникла следующая. Что, если фон состоит из тайлов ( в примере из 6 по 512х512 ) и они скроллируются? Должен возникнуть эффект параллакса. То что выше — двигается быстрее, то что ниже — медленнее. К тому же более высокие части ландшафта должны перекрывать более низкие при соотвествующих углах зрения. 
    Более того, что если над этим ландшафтом летит самолёт и он должен отбрасывать честную тень на ландшафт с учетом изменения формы (высоты) ландшафта? Разумеется, тень должна "плыть" по ландшафту. Искажаться. Вуаля:
    В данном демо источник света установлен ровно по центру экрана, а уровень спекуляра минимален для всей сцены (около 15%). Используется 3 карты — диффузная, нормали и карта высот. Рендеринг осуществляется в 4 прохода. Комбинирование всех диффузных карт (сюда же входит и "плывущий" логотип), комбинирование карт высот, комбинирование карт нормалей и финальный рендер с наложением шейдера.
    Для гибкой настройки по скорости выполнения предусмотрена возможность менять размеры рердертаргета и получать прирост в скорости в до 4х раз при скромном размере рендертаргета. (в демонстрации размер рендертаргета соотвествует размеру окна).
    Скачать пример (670Кб)

    пятница, 28 января 2011 г.

    Доброго дня всем. Пришло время очередного гениального изобретения. Разумеется, все уже изобрели до меня. Я лишь использовал. Итак, Parallax steep (occlusion) mapping:
    Для запуска необходима поддержка шейдеров версии 3.0.
    Что имеется - честное попиксельное освещение, блики, изменение "геометрии" по карте высот. 
    Качаем, смотрим:

    четверг, 20 января 2011 г.

    Доработал эффект bloom (3 прохода). Много расписывать не буду, лучше покажу:

    вторник, 11 января 2011 г.

    Последнее нововведение — QuadLog. Лог, позволяет как писать в него самому, так и передав любому quad классу писать в него автоматически. Мелочь, да. Давно надо было сделать — тоже да. Но в нормальный вид удалось привести только на днях.

    Результат выглядит примерно следующим образом:

    17:33:13 : Quad Engine v0.1.1
    17:33:13 : QuadRender Initialization
    17:33:13 : Resolution: 1024x768
    17:33:14 : Driver: ati2dvag.dll
    17:33:14 : Description: ASUS EAH4350 series
    17:33:14 : Device: \\.\DISPLAY1
    17:33:14 : Multisample: Off
    17:33:14 : Fullscreen: Off
    17:33:14 : Vsync: Off
    17:29:46 : Vertex processing: Software
    17:29:46 : Thread model: Multithreaded
    17:29:46 : Max VB count: 594
    17:29:46 : Max Texture size: 8192x8192
    17:29:46 : Max Anisotropy: 16


    Использование, как и в случае с остальными quad модулями безумно простое.