Как я делал лидар-сканер на Unreal Engine
Всем привет! Меня зовут Даниил, я делаю игры :D
В этом посте я бы хотел рассказать об одном своем небольшом эксперименте, в котором я попытался реализовать механику лидар-сканера в Unreal Engine. С самого начала я не планировал доводить этот проект до полноценного релиза (и, собственно говоря, не довел). Скорее мне просто было интересно изучить принцип реализации такой системы, после того как я поиграл в игру Lidar.exe от kenforest:
Ну а если вам интересно ознакомиться с моими проектами, сделать это можно тут:
Ну что-ж, меньше слов - больше дела!
Да кто такой этот ваш лидар
Лидар-сканер это реально существующее устройство, которое использует лазерный свет для получения расстояния до объектов. Оно испускает лазерные импульсы и измеряет время, которое им требуется, чтобы вернуться после отражения от объекта. Используется эта система в географии, при создании беспилотных автомобилей (и не только) и 3D-моделировании.
Эта система так же хороша, когда нужно исследовать пространства или помещения, с ограниченным освещением (или без освещения вовсе).
Начало работы
В первую очередь, хотелось бы уточнить, что несмотря на то, что проект не планировался как полноценная игра, а скорее эксперимент, делать очередной лидар-хоррор от первого лица (коих уже повыходило довольно много) желания особого не было. Поэтому я решил что игрок будет управлять FPV-дроном.
Я по-быстрому реализовал простой аркадный контроллер дрона, который основывается на использовании Floating Pawn Component.
Ничего сложного тут нет, двигаемся дальше.
После этого я сделал простенькую модель дрона в Blender, а риг для лопастей создал с помощью старого плагина UE4 Vehicle Rigging Addon (который откопал на просторах интернета)
Ну и финальный результат
Далее предстояло самое сложное - реализация самого сканера.
Hierarchical Instanced Static Mesh (далее HISM)
Этот компонент в Unreal Engine позволяет более производительно отрисовывать большое количество статик-мешей в один draw call, что делает возможным создание огромного количества наших "точек" без особого ущерба производительности. Это не единственный (и возможно, не самый лучший) способ, но об этом позже.
В качестве "точки" я использовал сильно уменьшенный стандартный Plane из Engine Content. Для меша обязательно нужно отключить физику и обработку столкновений (это нам не нужно, да и + к производительности). Кроме этого, необходимо настроить Cull Distance, чтобы не отрисовывать точки, находящиеся слишком далеко.
Однако, чтобы сделать "пропадание" точек менее резким, я создал вот такой простенький материал, который плавно затемняет объект, по мере удаления его от камеры:
Это позволило имитировать туман. Ну и так как все действие происходит в темноте, без единого источника света, материал должен быть Unlit, чтобы мы могли видеть наши точки. Изначально для отслеживания визуала я просто рендерил брошенные лучи через Debug, но позже заменил на Cable Actor.
Само бросание лучей происходит с помощью обычного Line Trace, который бросает луч несколько раз за кадр (если лидар активирован) со случайным угловым отклонением.
Больше цветов
Далее мне захотелось реализовать возможность окрашивать разные объекты в разные цвета. я вывел несколько тегов, в первую очередь, для объектов, которые вообще нельзя раскрасить, и отдельные теги для отдельных цветов, за каждый из которых отвечает отдельный HISM. Да, не самое удобное и масштабируемое решение, но пусть будет.
Что мы имеем? Система работает, и работает довольно неплохо. Но есть один важный момент. Вернемся к проблемам такого подхода.
Да, HISM позволяет отрисовывать большое количество точек без сильного ущерба для производительности (явно лучше чем создавать каждую точку в виде отдельного Static Mesh), но все же, при слишком большом количестве точек, просадки неизбежно начнутся.
А есть ли другой способ?
Конечно! Отрисовывать точки можно с помощью Niagara-эмиттера, работающего на GPU. Реализовать такое довольно просто. Нам нужен эмиттер, имеющий Spawn Rate = 0 и принимающий на вход массив точек, которые нужно отрисовать. Да, это все еще не позволит отрисовывать бесконечно-огромное количество точек, но допустимое количество явно увеличится, по сравнению с HISM.
Помимо способов с HISM и Niagara, реализовать лидар можно и шейдерным путем, но так как в шейдерной магии я все еще не особо силен, в эту сторону пока что копать не стал (однако, планирую в будущем обязательно разобраться).
Что по итогу
Хотя этот прототип и не дошел до полноценной игры, я все же получил довольно полезный опыт и научился многим фишкам, которые в дальнейшем смогу использовать в будущих проектах. Надеюсь пост получился интересным.
Всем добра :D