- PVSM.RU - https://www.pvsm.ru -

Про Godot, GLSL и WebGL, шейдеры используемые в мини игре

Статья в основном про GLSL-шейдеры, и как я их использовал в этой мини-демке-игре.

Статья разбита по такой очередности:

  • Ссылки и краткое описание.
  • Очень краткое описание игровой логики, и используемых возможностей Godot.
  • Про используемые шейдеры.
  • Еще немного про Godot, и его особенности.
  • WebGL2 работает
  • Мультиплеер


1. Ссылки и описание

Скачать Win/Linux версии можно по ссылка на itch.io [1]

Исходный код всей игры доступен на github-е [2] или gitlab [3].

Игровой процесс:

Минимальный, это не полноценная игра. (звука в игре нет)

Цель игры — продержаться максимальное количество раундов. Раунды начинаются когда HP сферы ноль, и нет роботов в игре.

При уничтожении фигур появляются бонусы, раз за раунд, дают скорость анимации выстрела, урон (только по главной сфере), и высоту прыжка, по цвету синий, красно/зеленый, желтый. Боты также дают бонус но случайно. Персонаж игрока восстанавливает +1HP каждый новый раунд.


2. Логика игры, и используемые ресурсы

Используемые ресурсы:

Blender использовался лишь для уменьшения количества полигонов на моделях, и для создания разрушенных кусков моделей.

Используется модуль futari-addon [4]. (про него ниже еще напишу)

В игре две модели имеют анимации.
Движения персонажа игрока я сделал в Godot, оригинальная модель [5]
Вторая модель это sphere-bot [6] которая имеет качественные анимации.

Все используемые готовые сторонние модели объектов перечислены по ссылке [7].

Логика игры и возможности Godot:

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

Используется всего один Viewport для 3D сцены, и несколько Viewport-ов (низкого разрешения) в которых стоят ортогональные камеры для 2D-Viewport-ов (тоже низкого разрешения) в которых идет обработка Multipass/Feedback шейдеров, о них ниже.

Все текстуры имеют mipmap, и работают даже в браузере. Есть дополнительные настройки графики (Esc — Settings). Например можно сделать любое разрешение для игры, до размера 32x32 пикселя, например я поставил 320x240 разрешение в настройках, запустив игру в браузере, и включил максимальное сглаживание MSAA вот что вышло Про Godot, GLSL и WebGL, шейдеры используемые в мини игре - 1 [8]

Все источники света работают в реальном времени, их 16 штук всего.

Пол и забор это простейшие частицы которые дублируют одну модель множество раз, код тривиален [9].

Анимация разрушаемых блоков считается физическим движком в реальном времени

Физика в Godot довольно ограничена, и начинает сильно уменьшать FPS уже при десятке активных объектов, поэтому отключены все столкновения между разрушенными кусками, и другие, установлены уровни для физики, также стоит ограничение на количество одновременных разрушений, и максимальное число Ботов одновременно (шесть).

Физика инерции и взаимодействия персонажа игрока с динамическими объектами. Она выключена по умолчанию в Godot, я написал минимальное взаимодействие, код в файлах:

bot_hit.gd [10] функция _integrate_forces и все что ей вызывается, это движения противника-бота
player_l.gd [11] во первых функцией move_and_slide отключается бесконечная инерция, и функция process_collision отталкивает объекты.

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

Несколько дублирующихся объектов в одном, и несколько GIProbe, формы и параметры источников света-все так и задумано, сделано для обхода ограничений OpenGL или ограничений в Godot.


3. Используемые шейдеры

Панорама окружения:

В этой игре используется статическая панорама, картинка получена из этого шейдера [12] (с1 с2 цвета, ldir положение)

vec3 sky(vec3 d, vec3 c1, vec3 c2) {
    vec3 ldir = normalize(vec3(0.,0.,-1.));
    vec3 col = mix(c1*100., c2*100., min(abs(d.y)*2. + .5, 1.)) / 255.*.5;
    col *= (1. + vec3(1., .7, .3) / sqrt(length(d - ldir))*2.); //sun
    return clamp(col,vec3(0.),vec3(1.));
}

для получения панорамы убрать комментарий со строке 57 panorama_uv(fragCoord,ro,rd); и поставить комментарий на строку 58

Динамические панорамы для Godot в прошлых демках (ютуб и там ссылки на код) панорама облаков [13] и панорама цикла дня/ночи с движением облаков

Если нужно конвертировать CubeMap в панораму окружения для Godot, я сделал простейший веб конвертер [14].

Совсем простые шейдеры:

Шейдеры для частиц статически определяющие их позицию для анимации или без. Например spawn.shader) [15]

Для дополнительного свечения вокруг объектов, не только шаров, это одна строка gglow.shader [16] (цифры можно менять как надо)

float intensity = pow(0.122 + max(dot(NORMAL, normalize(VIEW)),0.), 010.85);

Про Godot, GLSL и WebGL, шейдеры используемые в мини игре - 2 [17] Про Godot, GLSL и WebGL, шейдеры используемые в мини игре - 3 [18]

Показ текста-цифр в 3D, как я понял в Godot нет средств для этого (без создания дополнительного FBO (viewport)) поэтому простой шейдер печатающий цифры из текстуры (чтобы был mipmapping), код шейдера [19]

Элементы UI:

Делать нестандартную форму панелей UI для меня проще всего на шейдерах, возможно это совсем не правильно. Правильный способ показан тут на примере [20](в разделе про UI).
В этой игре простейшая анимация фона меню [21], и индикатор-HP [22]. Выше, в ссылке на видео панорамы дня/ночи, сделано также, там полосы по бокам и вся анимация на шейдере.

Про модуль futari-addon:

Он работает практически также как этот шейдер [23] для 2D-частиц на видео [24] (смотреть с 1:41).

На видео строится 2D-SDF карта всех полигонов один раз на старте и полученная текстура просто отправляется частицам, частицы сами строят normal в текущей позиции и меняют движение.

futari-addon делает практически тоже самое, только вместо 2D карты-текстуры передаются координаты 3D сфер и плоскостей которые обрабатываются по условию в шейдере частиц, поэтому свободно можно менять их положение и другие параметры.

Плюс ветер (в моем 2D-примере ветер добавить очень просто, как еще одну текстуру с +- значениями к скорости, и частицы просто добавляют значение скорости из этой карты по своему положению).

Модуль futari-addon очень хорош, использовал его вместо создания своей системы для частиц.

Эффект щита:

Частицы которым передаются координаты удара по сфере и положение игрока, и угасание используя буфер transform feedback. Код шейдера в файле en_m.shader [25]

Щит у Ботов:

Про Godot, GLSL и WebGL, шейдеры используемые в мини игре - 4 [26] Про Godot, GLSL и WebGL, шейдеры используемые в мини игре - 5 [26]
Шейдер по типу трехмерного шума sheild.shader [27] по сути все работает благодаря функции flow оригинал тут [28]
Задний фон определяется gl_FrontFacing, и закрашивается в более темный и зеленый, а не синий.
Реакция на удар-просто передается таймер события удара.


Шейдеры читающие свой прошлый кадр, или Feedback/Multipass шейдеры:

Почти все эффекты сделаны используя эту логику.
Один из шейдеров из игры [29].
В качестве источника я поставил ортогональную камеру которая снимает на маленькое расстояние объекты в определенной группе (не обрабатывая всю сцену)
Про Godot, GLSL и WebGL, шейдеры используемые в мини игре - 6 [30].

Эффект поля льда:

Шейдер указан выше, в проекте файл ice_feedback.shader [31], и fragment шейдер для плоскости который создает иллюзию глубины пола используя простой depth цикл:

while(current_depth < depth){
    ofs -= delta;
    depth = textureLod(texture_depth, ofs,0.0).r;
    current_depth += layer_depth;
}

Эффект поля частиц:

Шейдер тот-же, координата y (высота) частиц по яркости цвета буфера кадра от шейдера, цвет также по яркости цвета (шейдер частиц я не сохранял отдельно, он в проекте в объекте floor/visible_/floor3/grass/grass).

Динамическая анимация флага:

В Godot есть SoftBody для анимации ткани, но это CPU, поэтому я не использовал. Я использовал уже готовый код ссылка на оригинал [32]. Этот флаг отталкивается от трех шаров сбоку и голова персонажа четвертый шар.
Логика multipass-шейдера, как в примере выше, только с тремя осями, код multipass шейдера (1)flag.shader [33], шейдер рисующий флаг просто показывает текстуру с меняет геометрию плоскости (2)flag.shader [34].

Появление фигур:

У фигур нет UV, поэтому triplanar-texture-mapping для наложения текстуры, и разрезание по треугольникам (vertex), весь код в cchess.shader [35]

Анимация hitbox-а (красная рамка) который наносит урон персонажу игрока, и след от рамки (частицы очевидно):

Используется всего лишь уже указанный шейдер gglow.shader [16].

Для частиц используется всего две текстуры, круг и квадрат.


4. Про Godot, и его особенности

Godot очень хорош и прост (не для новичка). Мне Godot очень понравился своими возможностями.

Багов очень много, документация Godot не полная и порой вводит в заблуждение из за ошибок и не указания критических моментов (не очевидных для меня), чтоб понять которые приходилось весь исходный код Godot многократно перечитывать (код не большой и хорошо написан).
Это лишь мое впечатление, может быть ошибочное, никого не хочу ввести в заблуждение.

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

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

Лаги — есть большая проблема с управлением, это 100% на стороне Godot, я не исправлял это. (управление заклинивает во время компиляции шейдеров и лагов FPS (например в браузере)), также другие лаги связанные с особенностями 3D-рендера в Godot, я сделал обход части из них, но они всеравно есть/могут быть.


5. WebGL2 работает только в Linux

Не запускайте игру по ссылке, если у вас Windows. Ссылка на WebGL2/WASM версию. [36]

Работает только в Chrome 76+ и Firefox (Linux).

Про Виндовс отправлен багрепорт (ссылка) [37], если это баг браузера то гугл реагирует через 2 месяца. Но судя по всему это баг в ANGLE, а это wontfix почти наверняка.
Багрепорт уже закрыть, и ANGLE также править никто не будет. Значит на Windows в браузере не заработает.

По ходу этого проекта был исправлен один баг в Chrome благодаря чему заработал transform-feedback и моя прошлая демка (выше видео с панорамой дня/ночи), которая до этого не работала.


6. Мультиплеер

Это TODO. Обновлю эту часть как будет сделано.

Будет добавлен мультиплеер на двух игроков, для обычных версий (вне барузера) (в ближайшую неделю/две).

И как только выйдет Godot 3.2 с поддержкой WebRTC будет добавлена поддержка WebRTC, мультиплеер в браузере будет работать (пусть хоть только в Linux, хоть так).

Автор: atri1

Источник [38]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/opengl/330478

Ссылки в тексте:

[1] ссылка на itch.io: https://danilw.itch.io/e-ani

[2] github-е: https://github.com/danilw/e-ani

[3] gitlab: https://gitlab.com/danilw/e-ani

[4] futari-addon: https://gitlab.com/polymorphcool/futari-addon

[5] оригинальная модель: https://sketchfab.com/3d-models/rock-golem-acca392dee2a45ffb7038d7a7f073956

[6] sphere-bot: https://sketchfab.com/3d-models/sphere-bot-6c3a32958c2d43cdbf12a7109616bdbe

[7] перечислены по ссылке: https://github.com/danilw/e-ani/blob/master/USED_ASSETS_LINKS.md

[8] Image: https://i.imgur.com/gVFSw9N.png

[9] код тривиален: https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/vertex/floor_s.shader

[10] bot_hit.gd: https://github.com/danilw/e-ani/blob/master/e_ani_v1/scene1/scripts/game_logic/bot_hit.gd

[11] player_l.gd: https://github.com/danilw/e-ani/blob/master/e_ani_v1/scene1/scripts/game_logic/player_l.gd

[12] этого шейдера: https://www.shadertoy.com/view/WtXXR7

[13] панорама облаков: https://youtu.be/IQ-yw19xBQ8

[14] простейший веб конвертер: https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html

[15] spawn.shader): https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/vertex/spwan.shader

[16] gglow.shader: https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/material_fragment/gglow.shader

[17] Image: https://habrastorage.org/webt/db/rc/wk/dbrcwkd2m5cxmhmqiqxuqwjkzpw.png

[18] Image: https://habrastorage.org/webt/mz/iv/oj/mzivojirqk0kxj-dh43jdxqaeh0.png

[19] код шейдера: https://www.shadertoy.com/view/tsdGzN

[20] тут на примере: http://www.adriancourreges.com/blog/2015/06/23/supreme-commander-graphics-study/

[21] простейшая анимация фона меню: https://www.shadertoy.com/view/wlsXW2

[22] индикатор-HP: https://www.shadertoy.com/view/wljXDm

[23] этот шейдер: https://github.com/danilw/Godot-particles-collision/blob/master/v1/particles_v1/particles.shader

[24] видео: https://youtu.be/hycdANeMXaE?t=101

[25] en_m.shader: https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/vertex/en_m.shader

[26] Image: https://habrastorage.org/webt/yc/sl/-n/ycsl-nfdq_rwwqga0kdfo_zlbuw.png

[27] sheild.shader: https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/material_fragment/sheild.shader

[28] оригинал тут: https://www.shadertoy.com/view/XdfXRj

[29] Один из шейдеров из игры: https://www.shadertoy.com/view/WtfXRl

[30] Image: https://habrastorage.org/webt/r9/26/00/r92600j2rr8do4cqb94iiriy8dc.png

[31] ice_feedback.shader: https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/feedback/ice_feedback.shader

[32] ссылка на оригинал: https://www.shadertoy.com/view/MldXWX

[33] flag.shader: https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/vertex/flag.shader

[34] flag.shader: https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/material_fragment/flag.shader

[35] cchess.shader: https://github.com/danilw/e-ani/blob/master/e_ani_v1/shaders/material_fragment/cchess.shader

[36] Ссылка на WebGL2/WASM версию.: https://danilw.itch.io/e-ani-webgl?password=doit

[37] отправлен багрепорт (ссылка): https://github.com/godotengine/godot/issues/32189

[38] Источник: https://habr.com/ru/post/467779/?utm_campaign=467779&utm_source=habrahabr&utm_medium=rss