{"id":4009,"url":"\/distributions\/4009\/click?bit=1&hash=6ca492c3f83735606d9aedae9a61ec224ef2083f8beca590c50a2adcfd4adeee","title":"\u041f\u043b\u0430\u0442\u0438\u0442\u0435 \u00ab\u041c\u0438\u0440\u043e\u043c\u00bb? \u041f\u043e\u043b\u0443\u0447\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0430\u0440\u043a\u0438!","buttonText":"\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435","imageUuid":"4ea1e9ad-3a39-54d5-bfbf-ba7bfd1bb941","isPaidAndBannersEnabled":false}

Борьба с Unity в игре Simantik

Поговорим о страшных вещах в Unity, а именно с оптимизацией больших миров и созданием карт со включённым HDRP в Unity.

Скрин из игры

Небольшое предисловие

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

Одной из задач передо мной было получить хоть немного красивую графику, поэтому решил использовать HDRP. Он в свою очередь не позволяет использовать нативные шейдеры на terrain, да и тратить пару лет на карту я не хотел, а деревья с домиками требовали расстановки.

А что за игра?

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

Вначале была карта...

Как было сказано выше, хочу большую карту, а делать её год - не хочу.
HDRP не позволяет расставить деревья и траву стандартным способом (как в Paint поводить кисточкой и они появятся), переносить по одному деревцу из префабов - звучит как пытка. Покупать ассеты, которые имеют функционал быстрой установки объектов - дорого, а я ещё и нынче безработный, лишних денег нет.
Ну раз велосипед не едет, значит сделаем свой!

Идея такая:

  • Делаем много заготовок с домиками, деревьями и тд (тайлов грубо говоря)
  • Пишем свою кисточку
  • Рисуем карту, сменяя типы тайлов подобно цветам палитры
  • Бинго!

Значит заготовил я около 150 штук тайлов (кстати не советую хранить их в одной папке, Unity вылетает), но их же ещё раскидать надо.

Вот небольшая кучка самих тайлов

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

В нём то уже есть палитры с разными типами тайлов, полуавтоматическая расстановка (свой новояз проясню ниже) и сохранение в файлик.

И конечно же зелёный квадратик в роли кисти

Но возникает резонный вопрос: "А что интересного то?"
Тут прописан минимальный анализ высот для каждого из тайлов (домиков, деревьев, травы и тд)
Анализирую высоту при помощи Raycast'ов в 5 точках расположенных в форме квадрата (пятая в центре), а затем смотрим на разницу высоты между точками, в которые попали лучи, просто но эффективно.
На счёт травы, тоже самое только от каждого меша (ищу её по тегу в самом тайле) уходит свой луч, который касается земли и туда уже устанавливает объект травы.

Поделюсь кодом, он простой, но мало ли пригодится:

void Instantiate(RaycastHit hit, GameObject gameObject,float angle) //Метод установки тайла { if (gameObject == null || yMax < hit.point.y || yMin > hit.point.y || !CheckDeltaY(hit)) return; try { GameObject temp = Instantiate(gameObject, hit.point, Quaternion.Euler(0, angle, 0), enviropment.transform) as GameObject; foreach (var i in temp.GetComponentsInChildren<Transform>()) //вот тут начинаем устанавливаем траву и другие детали { if (i.tag != "Detail") continue; if (Physics.Raycast(new Ray(i.position + Vector3.up * 2, Vector3.down), out RaycastHit addHit, 999f, LayerMask.GetMask(terrainLayer))) { i.position = addHit.point; } } } catch { Debug.Log("Instantare Erorr"); } } bool CheckDeltaY(RaycastHit hit) // Метод проверки высот { foreach (var i in new Vector3[] { Vector3.forward, Vector3.right, Vector3.back, Vector3.left }) { if (Physics.Raycast(new Ray(hit.point + Vector3.up * 2 + i * subUnitScale, Vector3.down), out RaycastHit addHit, 999f, LayerMask.GetMask(terrainLayer))) { if (Mathf.Abs(addHit.point.y - hit.point.y) > maxDeltaYPerUnit) return false; } else return false; } return true; } //enviropment - родитель всех наших тайлов //subUnitScale - переменная которая задаёт размер квадрата //maxDeltaYPerUnit - максимально допустимая разность высот

А уже полученные расстановленные объекты, мы просто копируем и ставим в уже в эдиторе (ctrl+c в плей моде, ctrl+v в эдит моде), unity поругается на то что ей не хватает размера кэша, но это не страшно.
Минусы такого метода:

  • Установленные объекты не являются префабами
  • Достаточно случайная карта
  • Неудобно, потому что нужен плей мод (можно в целом и без него, если выполнять скрипты в эдиторе)

Объектов много, а fps мало

Конечный размер игровой зоны 5-6 квадратных километров, с кучей разных объектов, а моя видеокарта начала разогревать воздух до температуры сауны и счёт кадров завис на 15. Не круто....

LOD и Occolusion Culling - использованы, модели - оптимизированы, материалы - собраны в паки, а кадры ниже плинтуса.
Изобретаем следующее решение:

  • Делим всю карту на сетку(матрицу), в каждой ячейке которой храним объекты
  • Включаем объекты только в ближайших к игроку ячейках, а остальные отключаем
  • Проверяем кадры

Крайне простая идея, но дошёл до неё не сразу. Попробую визуализировать выше названный список:

  • Зелёные клеточки - включённые объекты, представим что в центре поля игрок
  • Если игрок ушёл по оси X, то отключаем красные клетки (сторона противоположная движению игрока)
  • А если по оси Y, то синие отключаем (тоже противоположные направлению)

Конечно изначально все объекты должны быть отключены, иначе когда игрок запустит игру ему придётся ждать покуда система отключит все ненужные объекты, и установит позицию игрока

В Unity выглядит как то так:

Самих объектов только не видно, их уже LOD убрал

Грубо говоря отключаем все объекты, которые не находятся в зелёных клетках (использую нативный метод SetActive).

Самое главное что такая система спокойно масштабируется.

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

Минусы

  • Приходиться заморачиваться и делать лишние действия при билде в виде отключения всех объектов
  • Телепортировать персонажа - неудобно

А с кадрами что?

У меня FPS стабилизировался и просадок не наблюдал, попробовал скинуть билд знакомым с разными конфигами ПК итого:

  • На среднем Ryzen с GTX 1050ti - стабильные 60
  • На встроенном Intel iris G7 - такая же картина
  • На стареньком проце от AMD и не менее старенькой GTX 950, 20-30 кадров, но потому что у неё не хватило видео памяти, а нормальных настроек в момент теста - я не сделал

Без такой системы моя RTX 3060 выдавала 15-20 кадров, поэтому смею утверждать что всё работает хорошо

На небольшие локации, такое решение будет рудементарно, поэтому рекомендую только для больших карт

Ещё скрин из игры

Спасибо за удивлённое время!

Если вас заинтересовала игрушка, то вот Группа ВК и Steam, всем буду рад!
P.S. Если понравились мои костыли, то в будущем составлю статью про другие виды извращений (велосипедов) в играх

0
24 комментария
Написать комментарий...
Caduceus

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

Ответить
Развернуть ветку
Romenics

Эм, боюсь спросить, что же такое геймплей для какого нибудь walking simulator, с повествованием через открытый мир.
Ну окей, ты тратишь 10 минут на написание интеракции с объектами, дальше что?
То что такие игры не для всех, и лично я их тоже не очень понимаю, это уже другой разговор.
Но даже если мы говорим о survival играх, то тестирование систем один черт идет параллельно с задачей заставить работать большой мир.

Ответить
Развернуть ветку
Caduceus

Когда есть команда - запросто. Вот только речь изначально про игру, которую делает один человек без денег, уйдя с работы. Понимать надо масштабы. Даже огромный, но процедурный мир, - уже будет скучен. Одиночки могут выстрелить ТОЛЬКО геймплеем.

Ответить
Развернуть ветку
Romenics

Буквально, сделано человеком ушедшим с работы без денег в соло.
(Ну ладно я помогал программировать все это)
Но даже так, ваше утверждение не верно.
https://store.steampowered.com/app/1262460/Zompiercer/

Ответить
Развернуть ветку
Dizer

и что заработали на этом? Если это не секрет и не стыдно назвать сумму?)

Ответить
Развернуть ветку
Romenics

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

Ответить
Развернуть ветку
Darth Soth

А Tunic? Там один с половиной чел пилил много лет ее и получилось весьма мило. Геймплей достаточно стандартный

Ответить
Развернуть ветку
Parfen

Нууу. Если игра задумывается изначально, как опенворлд, то вобщем-то пофиг. Это ключевая фича, технология. Перестановка мест слагаемых.

Ответить
Развернуть ветку
Caduceus

Я знаю крутые маленькие игры, базирующихся на крутом геймплее, сделанные одним человеком. Я знаю крутые маленькие игры, базирующиеся на крутом геймплее, сделанные большими командами. Но я не знаю НИ ОДНОЙ нормальной игры с большим миром, сделанных одним человеком

Ответить
Развернуть ветку
Parfen

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

Ответить
Развернуть ветку
Cadovvl

Ну как сказать. Вот в какой-нибудь Готике 2 или Морровинде мир был достаточно открытый. Забираешься в Минентале на гору окруженную орками, находишь пещеру черт знает где, а там на тебя орет мужик: "Ну куда я еще должен забраться, чтобы вы, люди, от меня отвязались".
И, возможно, мне кажется, но раньше, значительная часть (в процентном соотношении) громких тайтлов была именно с настоящим открытым миром.

Смотрим на современные громкие тайтлы. Всякие ластофазы, годофворы, прочие анчартеды, попросту линейные. В Хорайзон заявлется открытый мир, но на самом деле в новых "открытых" локациях делать нечего: монстров там ты до определенного уровня не убьешь, а другого интерактива в игре просто нет. Та же проблема с последними асасинами, в которые я играл и, по слухам, с последующими тоже. Вроде как с фаркраем почти такая же история. Диаблы открытым миром и не планировались, крайзисы, томбрейдеры - линейные, про DMC вообще молчу.
Итого, последние "честные" открытые миры - довольно редкое явление. Skyrim (2011), Fallout 4 (2015), Ведьмак(2015), RDR 2 (2018), Cyberpunk (2077). Возможно, человек-насекомое, но пока только установил, не было времени поиграть.

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

А все то, что теряет интерес больших студий становится достоянием инди сегмента.

Ответить
Развернуть ветку
Night

Майнкрафт?

Ответить
Развернуть ветку
Caduceus

там не "огромный мир", там инструмент, чтоб огромный мир строил сам игрок. Собственно это и есть геймплей. Автор майнкрафта огромные миры не строил

Ответить
Развернуть ветку
Romenics

Так а какой геймлей то?
Майнкрафт это буквально технология про генерацию мира, что там тестировать то, помимо мира?
Крафт?

Ответить
Развернуть ветку
andreymust19

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

Ответить
Развернуть ветку
Sega Mega Drive 2

Так и не понял причем тут Unity, и зачем тут HDRP?

Ответить
Развернуть ветку
Romenics

Так и не понял зачем hdrp. Он в чистой сцене ест 4мс просто так. При том что качество картинки буквально тоже самое что закинуть ассеты от amplify.
И совершенно не понятно как это исправлять.

Ответить
Развернуть ветку
Sal Baba

Согласен, HDRP для опенворлда очень не оптимизирован. Я бы посоветовал автору для Built-in хороших бесплатных шейдеров найти и ассеты растительности( на крайняк можно самому пару-тройку деревьев создать и лоды для них, на скечфабе куча бесплатных деревьев), зато гладкие 100+ кадров на древних системах при плотной растительности. На крайняк URP попробовать, но никак не тормозящий HDRP.

Ответить
Развернуть ветку
Arazect's Stuff
Instantare

Кстати, ты в курсе, что можно инстантиировать объекты так, чтобы линки на префабы оставались?)

https://docs.unity3d.com/ScriptReference/PrefabUtility.InstantiatePrefab.html

Ответить
Развернуть ветку
wichidt

Можно код системы?

Ответить
Развернуть ветку
dyst0p

Ты, конечно, молодец, но можно было бы начать с изучения статей на тему создания опенворлдов) Чанкам сто лет в обед уже

Ответить
Развернуть ветку
Nikita Novokreshchenov

Резюмирую: "Юнити - неоптимизированное говно, в котором невозможно сделать нормальную игру а нет, подождите, это просто я был не в курсе, как настоящие разрабы делают игры, и пошел изобретать свой велосипед"

Ответить
Развернуть ветку
Zubius

Просто любопытно какие пики в профайлере выдает нативный SetActive при подгрузке новой линии клеток

Ответить
Развернуть ветку
Илья Уланин

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

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

Тоже 2 раза приступал к созданию таких игр. Первый раз я решил это сделать после пары месяцев изучения Unity. И понял что не осилю.

Второй раз уже получилось реализовать минимальный функционал. Но без большого открытого мира. Возможно его и не будет.

Ответить
Развернуть ветку
Читать все 24 комментария
null