Songs of Conquest: Билборды для параллакса

Songs of Conquest: Билборды для параллакса

Многие спрашивали меня о технологии, стоящей за 2.5D билбордами нашей игры, поэтому я посчитал, что пора написать об этом пост.

2.5D билборд
Скриншот из нашего трейлера при запуске

Вначале…

Почти сразу в нашей разработке 2.5D стало очевидно, что билбординг может быстро привести к огромным потерям производительности. Нам были нужны тысячи анимированных билбордов, образующих горные цепи, леса и равнины. В самых первых подходах мы пытались использовать регулярные спрайты с прикрепленными Monobehavior, обновляющими их ротацию. Это работало довольно хорошо, пока угол камеры не изменился. Но как вы, наверное, видели в трейлере, мы хотели иметь возможность увеличивать и уменьшать масштаб при изменении поворота камеры.

На сцену выходит картография…

Ясно, что подход придется изменить, поэтому родилась картография. Так мы в конечном итоге назвали систему, отвечающую за создание и рисование ландшафтов (земля, скалы, деревья, горы, трава, вода и т.д.). Мы также внедрили новый легкий конвейер рендеринга Unity, чтобы получить от рендеринга еще больше производительности.

Чтобы решить проблему с билбордингом, мы обратились к шейдерным приближениям. Мы просто перемещаем вершины «спрайтов» таким образом, будто бы они вращаются. С первого взгляда это работает очень хорошо, но мы быстро столкнулись с проблемой перевода между мировым пространством и пространством объектов, так как хотели, чтобы основание объектов всегда оставалось неподвижным и прикрепленным к земле. В итоге запечатали эту информацию в y-компонент второго uv-канала билборд «спрайтов» (или сеток).

билбординг гор и деревьев
Скриншот из нашего редактора, рисующий предварительно запеченный y-компонент второго uv-канала. Обратите внимание, что основание объектов полностью черное, и как объекты по мере увеличения высоты становятся все ярче и ярче. Чем белее часть объекта, тем больше он смещается, а темнота указывает на ту часть сетки, которую мы вообще не смещаем.

Запечь данную информацию оказалось очень просто, все показано ниже.

void BillboardFixer(Mesh mesh)
{
    var vertices = mesh.vertices;
    var uvs = new List(mesh.vertexCount);

    for (var i = 0; i < mesh.vertexCount; ++i)
    {
        var uv = vertices[i];
        uvs.Add(uv);
    }

    mesh.SetUVs(1, uvs);
}

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

Shader.SetGlobalVector(
  "_Billboard",
  Camera.main.transform.rotation.eulerAngles * (Mathf.PI / 180f)
);
подграф для симуляции билбординга
Подграф для изменения положения вершин и симуляции билбординга.

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

шейдер которому скармливают подграф
«Окончательный» шейдер, который использует подграф билбординга

Заключение

Данное решение в значительной степени адаптировано к нашему конкретному случаю, поскольку билборды вращаются только по оси X. Ограничение, которое очень хорошо подходит для нашей игры. Этот подход также хорошо сочетается с другими, и как правило, он очень быстрый, но достаточно точный для наших нужд. Но надо сказать, что мы решили не использовать его для персонажей и зданий (чего-то действительно динамичного), поскольку любое повышение производительности быстро перевешивается сложностью системы.

Источник: https://www.lavapotion.com/blog/2019/9/9/the-shader-approach-to-billboarding

Понравилась статья? Поделиться с друзьями:
Автор natalya
Переводит для Вас самые интересные статьи про разработку игр. По образованию физик-программист. Техническими переводами начала подрабатывать еще на старших курсах и постепенно это переросло в основное занятие. Интересуется гуманитарными технологиями, пробует себя в журналистике.
  1. Александр :

    Исправьте
    List<Vector3>(mesh.vertexCount);
    на
    List(mesh.vertexCount);

  2. Александр :

    Упс… Что-то на сайте пошло не так с комментарием. В общем в первом примере кода, строка 4 должно быть var uvs = new List (треугольная скобочка открывается) Vector3 (треугольная скобочка закрывается) (mesh.vertexCount);

  3. Александр :

    Та же проблема с знаком “меньше” в цикле на 6-й строке

  4. Спасибо большое, это движок сайта преобразовал угловые скобки в html коды, я поправил! В комментариях дизайн “поплыл”… в ближайшие пару недель займемся исправлением

  5. Алексей :

    Здорово! Выглядит точь в точь как герои :)
    Ув. разработчики, просьба, если это возможно – поделитесь
    шейдером смешивания текстур разной местности,
    буду безмерно благодарен!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *