Pull to refresh

Occlusion Culling и LOD для Unity Indie

Reading time2 min
Views16K
Доброго времени суток! В качестве хобби ковыряю движок Unity. Хобби явно некоммерческое, поэтому особой нужды в Pro-версии не испытываю. Pro, конечно же, посурьезнее Indie, но для разработки, например, под Android/iOS возможностей второй вполне хватает. За исключением одной – оптимизации и связанного инструментария.

Раскидистая клюква, созданная силами движка имеет полторы — две тысячи треугольников. Высокополигональный замок/машинка заставляют картинку в среднем телефоне шизофренически подергиваться, а красивый шейдер для воды — надолго застыть в позе роденовского мыслителя. Ясно, что при появлении в кадре пары — тройки таких объектов, все будет жутко глючить и тормозить.

В Pro есть крайне нужная штука, называется Occlusion Culling. Кратко – отрисовываются только объекты, попадающие в поле зрения камеры (скриншоты под катом). Посмотрел опять на стоимость Pro, почесал затылок, обиделся и ушел сначала искать, а потом и писать костыли.

Без OcclusionCulling:

image

С OcclusionCulling:

image

Неплохой пример того, что умные люди уже придумали: Simple LOD Manager. Суть в том, что при приближении к объектам низкополигональная модель (куб) заменяется высокополигональной (например, детализированное здание). Конечно, использовать цикл в Update() не есть хорошо, но идея достойна уважения.

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

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

public var distance = 100f;  
private var meshRnd: MeshRenderer;
private var _collider: BoxCollider;
 
function Awake() 
	{
		meshRnd = gameObject.GetComponentInParent(MeshRenderer);

		_collider = gameObject.AddComponent(BoxCollider);
		_collider.isTrigger = true;
		_collider.size = Vector3(distance, distance, distance);
	}
	
function OnTriggerEnter (player : Collider) 
	{
		if(player.tag=="Player") meshRnd.enabled = true;
	}

function OnTriggerExit (player: Collider) 
	{
		if(player.tag=="Player") meshRnd.enabled = false;
	}

Ловим компонент MeshRenderer объекта, который отвечает за прорисовку самой модели. Создаем коллайдер — в этом случае box, c ребром distance — и делаем его триггером. Если кто — то с тэгом Player вламывается в коллайдер, он срабатывает и отрисовывает модель.

Дистанцию удобнее всего подбирать в режиме Window > Layouts > 2 by 3.

Перед запуском деактивируйте MeshRenderer объекта, на который вешается скрипт.

Удачи.
Tags:
Hubs:
Total votes 24: ↑16 and ↓8+8
Comments2

Articles