Эта статья повествует на примере движка Unity о способах, позволяющих выжать из ВР-игры максимум – и в плане производительности, и в плане визуального качества, и в плане функциональности гейм-дизайна. Тут рассказывается о проблемах, характерных для ВР, но они имеют много общего и с оптимизацией обыкновенных игр, т.к. затрагивают такие темы, как количество полигонов, уровни детализации, команды отрисовки и т.д.

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

Важно знать историю проекта, какой вы оптимизируете. Для этого полезно пообщаться с дизайнерами, программистами и художниками, разузнать об их методах – это поможет вам постичь, как лучше подойти к оптимизации каждой модели. Если вы соображаете, каким образом была собран объект, вы можете его разобрать, а затем и отыскать способ сделать его более эффективным.

В качестве введения

Желая виртуальная реальность открывает перед разработчиками целый ширь возможностей, графика во многих ВР-проектах выглядит так, будто ее мастерили несколько десятков лет назад. Поэтому я попробую рассказать о трудностях, возникающих при оптимизации ВР-проектов, о том, как с этими трудностями управиться, а также об оптимизационных технологиях, которые появятся в ближайшем грядущем. Это будет глубоким погружением в тему производительности, с обилием технической зауми (в частности, будет рассказано о автоматизированных системах для оптимизации ассетов). Потому читатель должен хорошо разбираться в работе игровых движков и быть заинтересован в том, чтобы выжать из своих систем самый максимум. Это не типовой набор приемов по игровой оптимизации – об этом было написано уже не раз. Вместо этого мы сфокусируемся на темах «Нам необходимо оптимизировать эту тысячу ассетов, но людей категорически не хватает» или «Мы оптимизировали все, что могли, но фреймрейт по-прежнему пробивает дно».

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

В натуральный момент плохая производительность в ВР главным образом связана с тремя предметами – лагами/задержками, фреймрейтом и многоэкранным рендерингом. Давайте рассмотрим любую из них поподробней.

Лаги и задержки

Каждая ВР-система (будь то Vive, Rift или PSVR) оснащена станциями, чьи вычислительные ресурсы используются, во-первых, для обработки этих о расположении/вращении игрока и игровых устройств в 3-мерном пространстве, и во-вторых, для расчета прогнозов (с частотой 90 раз в секунду или даже пуще) о том, где игрок или игровые девайсы будут находиться в будущем. К образцу, если человек идет вперед, эти станции будут находить, что человек будет по-прежнему идти вперед. На это тоже требуются вычислительные ресурсы, какие не бесконечны.

Другая проблема – в скорости отслеживания. Во-первых, она выделяется у разных ВР-систем, а во-вторых, у одних ВР-систем она более масштабируема, чем у иных. Данные, потерянные из-за несовпадения скорости отслеживания и фреймрейта, компенсируются за счет прогнозов. Базовые станции Vive обновляются любые 4 мс, а на Rift обновление привязано к фреймрейту, но в любом случае при фреймрейте 90 к/сек объект, подвигающийся быстрее заданной скорости, будет лагать, и этих лагов можно избежать, лишь если ВР-шлем высчитывает прогноз.

Есть и проблемы, специфические для конкретных ВР-систем. К примеру, у Vive возникают трудности из-за репроецирования и композитинга функций вроде «Chaperone», а на обработку этих, генерируемых OSVR, по сообщениям некоторых пользователей, уходят цельные ядра.

Как быть разработчику?

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

Фреймрейт

Теперь подавайте перейдем от «тяжелых ранений» (т.е. от задержкек и лагов) к «поверхностным ранам» (т.е. к проблемам с фреймрейтом). У большинства обыкновенных ААА-игр фреймрейт составляет в пределах 30-60 к/сек – вроде бы немного, да? Всего-то на треть скорее. Но на самом деле проблема очень серьезна. Конечно, у большинства ВР-систем случайный крах фреймрейта можно компенсировать за счет репроецирования, но при сильной нагрузке не помогает и оно. Потому важно, чтобы у вас всегда оставался запас вычислительных ресурсов – особенно при использовании Vive. Если ваш проект рассчитан на 90 к/сек и не имеет такого резерва, то на какой-нибудь навороченной сцене фреймрейт может запросто обрушиться до 45 к/сек. Во избежание этого свой проект нужно подогнать под 100-110 к/сек, чтобы у вас наверняка достало производительности на того 45-голового босса, с которым игроку предстоит воевать на протяжении 10 минут.

Есть еще один фактор, какой очень часто остается незамеченным – ресурсы, которые расходуются на вычисления, выполняемые драйвером. Для разработчиков игра – это что-то вроде шампуня. Процессор отсылает эти видеопроцессору, а тот показывает их на экране. Намылить, смыть и повторить Х раз в секунду и… бум! Игра готова. Но эти махонькие надбавки наслаиваются друг на друга, что в конце концов воздействует и на производительность. Картинка ниже демонстрирует ситуацию, при которой на драйвер уходят непомерные 35% всех вычислительных ресурсов, затрачиваемых на выполнение ВР-проекта.

Как быть разработчику?

Чем рослее фреймрейт, тем эффективней должна быть оптимизация. К примеру, что прикасается игр, то для них запас производительности должен быть очень большим. На переднем кромке борьбы с этой проблемой находятся, собственно, сами драйверы; в частности, увлекательные возможности есть у DX12, Mantle и Vulcan. Кроме того, в грядущем этих возможностей, а также драйверов и чипсетов, наверняка сделается еще больше. Более подробно о методах борьбы с этой проблемой можно почитать тут.

Многоэкранный рендер

Внутри любого ВР-шлема находятся два экрана – по одному на каждый глаз. Изображения на них смещены сравнительно друг друга, чтобы создать у пользователя иллюзию глубины и уверить его, что он находится именно на горе Эверест, а не в своей комфортной московской квартире. Но при использовании двух экранов удваивается и число объектов, которые нужно отрендерить на экранах. Добавьте сюда нужда два раза отрендерить одну и ту же текстуру. Добавьте сюда эффекты вроде карт нормалей или спрайтовых крупиц. Плюс фреймрейт в 90 к/сек. Плюс обработка данных о движении игрока и девайсов. Но самый смак – это позволение экранов, составляющее 2160 х 1200 (по 1080 х 1200 на любой глаз), что сопоставимо с разрешением среднестатистического монитора формата 1080p. Кроме того, свою часть привносит и сглаживание. Поскольку экраны ВР-шлема находятся ровно у ваших глаз, качество картинки должно быть гораздо лучше, чем в обыкновенных играх.

Как быть разработчику?

Во-первых, разработчик может воспользоваться функцией, принцип труды которой очень прост: если игра лагает, она уменьшает размер экрана и снижает качество сглаживания. Во-вторых, можно гарантировать постоянную отправку команд на GPU, чтобы ему всегда было, чем заняться. В-третьих, можно воспользоваться так именуемым «экземплярным стерео-рендерингом» (от англ. «instanced stereo rendering») – это технология, какая берет информацию обо всех объектах на сцене, подготавливает ее на CPU, но пока лишь для одного глаза, затем упаковывает эту информацию, выполняет смещение, чтобы подогнать картинку под другой глаз, и лишь после этого выполняет рендер. Немало подробно об этой технологии можно почитать тут.

Кроме того, есть технология «ямковый рендеринг» (от англ. «foveated rendering»), какая увеличивает разрешение центральной части экрана, попутно снижая позволение периферийных областей. Это позволяет существенно снизить количество этих, идущих на каждый экран. При использовании технологии «кругового разуплотнения» (от англ. «radial density masking») картинка в середине остается неизменной, а на периферии формируется «шахматное» изображение, в каком одна половина пикселей рендерится, а вторая – нет, после чего на основе этой «шахматной» картинки формируется еще одна, где оставшиеся пиксели тащат в себе информацию об утерянных пикселях. Более подробно об этих технологиях можно разузнать в этой презентации от Алекса Влачоса (Alex Vlachos).

Большинство этих техник реализовано, к образцу, в программе Lab Render for Unity от Valve.

Решения будущего

Немало эффективные устройства и ПО

В последнее время разработчики пытаются улучшить производительность игровых движков при поддержки многопоточности (т.е. одновременной обработки данных несколькими процессорами), но для немало платформ эта технология пока в новинку. Если производители PC-комплектующих уже прочертили серьезную работу над повышением производительности ВР-проектов, то у производителей ВР-шлемов все еще спереди. Сегодняшний ВР-шлем – это, как правило, довольно примитивное устройство, попросту импортирующее картинки на экраны. Новые версии должны быть оснащены собственными вычислительными ресурсами для обработки этих о движении, стерео-рендеринга и репроецирования (на случай низкого фреймрейта).

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

У современных мобильных устройств (включая ноутбуки и прочие компактные компьютеры) самым узким «бутылочным горлышком» является мощность CPU. По этому показателю они приметно проигрывают настольным компьютерам. Кроме того, если использовать смартфон на пределе мощности, он начинает чувствовать тротлинг. Мобильный телефон создается с прицелом на максимизацию заряда батареи – чтобы пользователь мог и позвонить, и полазать в интернете, и немого поиграть. В итоге – ужасающее число вершин и команд отрисовки.

Круговое разуплотнение (radial density masking)

Эта технология рендерит любой второй пиксель, находящийся на периферии, а затем использует «уцелевшие» пиксели для восстановления неотрендеренных пикселей. Подобный подход дает неплохой (но и не гигантский) прирост производительности – в кое-каких случаях вплоть до 10%. Если использовать эту технологию совместно с ямковым рендерингом, можно добиться улучшения производительности, утилитарны не жертвуя качеством картинки.

Ямковый рендеринг (foveated rendering)

Эта технология снижает позволение периферийных участков изображения. Сейчас эту технологию правильней будет наименовать фиксированным ямковым рендерингом: у центральной трети экрана позволение увеличено, а у двух оставшихся – уменьшено. В ближайшем будущем должны показаться две новые версии этой технологии: акцентный ямковый рендеринг (от англ. «perceptually based foveated rendering») и следящий ямковый рендеринг (от англ. «gaze based foveated rendering»). В первом случае детализация переменяется в зависимости от важности объектов, находящихся в центре, а во втором – в подневольности от того, куда направлен взгляд пользователя (для этого используется слежение за движениями глаз). Эти технологии разбиваются на мириад иных технологий вроде глубины резкости, зависящей от взгляда пользователя, или степени детализации, зависящего от взгляда пользователя и т.д. Правда, при использовании следящего ямкового рендеринга разработчикам придется оснастить свои ВР-шлемы добавочными вычислительными ресурсами, чтобы обработка данных о слежении за глазами не ложилась на рамена PC-комплектующих.

Но наличие всех этих технологий не отменяет созидательного подхода к работе с аппаратными, программными и гейм-дизайнерскими ограничениями. Если использовать эти технологии по отдельности, они могут создать загруженность в иных участках системы. К примеру, экземплярный стерео-рендеринг может повысить нагрузку на GPU на 257%. Другие технологии могут переместить проблемы с производительностью в пункты, которые уже испытывают сильную нагрузку. К примеру, оптимизировать GPU при мощной загруженности CPU – это не только потеря времени, но и медвежья услуга всему проекту.

Как оптимизировать собственный проект?

В данный момент возможности разработчиков ограничены, но большинство проблем ВР-проектов – такие же, как и в обыкновенных играх. Следовательно, инструментарий для борьбы с этими проблемами будет образцово тем же. Разработчики мобильных игр могут задействовать уже известные им методы вроде атласинга (от англ. «atlasing»; это технология, при какой текстуры/материалы комбинируются в одном месте, которое и именуется «атласом»; близкий термин – «текстурный атлас»), использования одного большенного шейдера или запекания большинства (а то и всех) текстур. Если вы разрабатываете мобильную игру или используете для ВР собственный ноутбук, то на производительность вашего проекта будет очень мощно влиять тротлинг. Современные GPU всегда испытывают максимальную загруженность – из-за особенностей своего конструкции. Но если задействовать более мощный CPU (вроде 7-го поколения Intel Core i7 или лучше), это позволит разгрузить GPU и тем самым повысить производительность. Это проблема, с которой разработчики сражаются годами: одинешенек GPU, один экран, отложенный рендеринг, полноэкранные эффекты. Но в ВР не одинешенек, а целых два экрана, и в итоге GPU загружен почти постоянно, потому умение оптимизировать GPU становится все важнее. В частности, Oculus не рекомендует использовать полноэкранные эффекты – как раз из-за последствий для производительности.

Разбор проекта

Чтобы выяснить, насколько сильно ваш проект нагружает CPU и GPU, можно воспользоваться инструментом Intel Graphics Performance Analyzers. Он спокоен тем, что собирает все данные о производительности в одном месте. Скачать его можно отсюда, а обучающие материалы можно отыскать тут и тут.

Количество полигонов

Для обычных игр это практически не проблема, т.к. современные компьютеры могут с легкостью выдать несколько миллионов треугольников и даже не запыхаться. Однако для ВР-проекта проблемой будут даже 3 миллиона стрельбищ. Полигонную оптимизацию можно использовать и на «сырой» версии ассета, и на LOD-версиях.

Как установить

Как правило, у ВР-проекта нет ограничения на количество полигонов, но этот показатель узко связан со скоростью заполнения (от англ. «fillrate»), освещением в реальном поре и сложностью шейдера. Проблемы со скоростью заполнения могут возникнуть из-за чрезмерного «загораживания» (от англ. «overdraw»; это ситуация при какой одни объекты загорожены другими, поэтому загороженные объекты рендерятся впустую), и снижение числа полигонов придется здесь весьма кстати. Если в вашем проекте используется немало освещения в реальном времени, каждая из этих «ламп» добавочно рендерит полигоны для упреждающего рендеринга (от англ. «forward rendering»; это рекомендуемая технология для ВР). Еще одна гремучая смешение – это сложный шейдер плюс большое количество полигонов, потому я рекомендую использовать для ВР мобильные шейдеры. Но чтобы картинка засияла, к делу необходимо подойти творчески. Если просто снизить количество стрельбищ, «шейдерная» выгода будет совсем небольшой.

Что делать

Если у вас довольно рабочих рук, то ни секунды не сомневайтесь и делайте эту работу руками. Если у вас довольно средств, воспользуйтесь программами вроде Simplygon и Decimator от Maximo. Но есть и альтернативная техника, какая может разом обработать целую кучу ассетов. Используя ее, не забывайте про управление версиями, потому что такая «ковровая» оптимизация вряд ли сработает для всех моделей. К образцу, она плохо подходит для персонажных ассетов, и в этом случае вы наверняка пожелаете откатить оптимизацию назад.

import pymel.core as pm
# выделяем все объекты по образу геометрии:
pm.select(pm.listRelatives(pm.ls(geometry=True), p=True, path=True),r=True)
objectsToReduce = pm.ls(sl=True)
for objectToReduce in objectsToReduce:
pm.select(objectToReduce)
pm.polyReduce(percentage=35, version=1)

Степени детализации (LOD)

Здесь проблемы возникают из-за двух предметов: ограниченного количества вершин и ограниченного количества команд отрисовки. Труд над уровнями детализации позволяет оптимизировать сцены за счет снижения детализации у объектов, находящихся на заденем плане. К образцу, перед носом у вас щелкает своими многочисленными челюстями 45-головый монстр, а на заднем плане ютится махонький чайник, на который приходится 2 тысячи полигонов и 6 команд отрисовки: краска, карта нормалей, карта высот, карта отражений и запеченный объемный свет. 45-головый монстр, напомню, дышит вам ровно в лицо, а чайник тихонько булькает в дальнем углу. Какому объекту снизить детализацию? Монстру, неизменно? LOD в помощь!

Как определить

Конечно, LOD’ы не помогут вам в каждой сцене и с любым объектом. Порой от использования LOD’ов становится даже хуже. LOD’ы придутся для объектов с большим количеством полигонов и команд отрисовки – вроде большенный или открытой комнаты, заполненной различными точками интереса. Но благоразумнее всего использовать LOD’ы в сцене с небольшим количеством объектов, потому что люд склонны фокусироваться на отдельных предметах. Во всех этих случаях не вытекает сначала применять команды отрисовки, а потом делать LOD’ы, как и не стоит использовать LOD’ы в махоньких и тесных сценах. Дело в том, что переход от одного уровня детализации на иной происходит даже из-за малейших движений игрока, а эти переходы тоже стоят вычислительных «денежек». Наслаиваясь друг на друга, они могут вызвать проблемы с производительностью, так что употреблять LOD’ами нужно мудро.

Что делать

При работе с LOD’ами разработчик занимается тремя предметами: оптимизацией моделей, оптимизацией материалов и оптимизацией шейдеров. Для образца давайте возьмем все тот же чайник. Хотите реализма? Добавьте чайнику карту деталей. Желаете показать, что бабушка главного героя лелеяла этот чайник до своего самого заключительного дня? Добавьте ему какой-нибудь приятный шейдер вроде PBR. Как только основной герой отдалится от чайника, уберите карты высот и нормалей, а затем вполовину убавите количество вершин, а когда удалится еще дальше – еще раз урежьте верхушки и поменяйте шейдеры на мобильные.

import pymel.core as pm
# не позабудьте выбрать объект:
reductionPrecentages = [0,10,20]
nameOfLODS = []
selectedObject = pm.ls(sl)
for x in range(0,ReductionPrecentages.length):
newName = (selectedObject + "_LOD[%s]")%(x)
pm.duplicate(newName)
pm.parent(selectedObject)
pm.polyReduce(percentage=reductionPrecentages[x], version=1)

Это обновленный скрипт неплохо работает для Unity и даже выполняет за вас группировку LOD’ов. Мы модифицируем цикл for(), создаем переменную с процентом оптимизации и добавляем к этой переменной суффикс _LOD[переменная]. Затем пробегаем по списку необходимых размеров и экспортируем сквозь FBX. Далее импортируем в Unity и – вуаля! – у нас есть группа LOD’ов.

Число объектов

Все просто – чем больше объектов, тем больше ресурсов система расходует на их обработку. То же касается и текстур, наложенных на эти объекты.

Как определить

Подавайте снова вспомним про чайник и добавим к нему целый чайный комплект – с блюдцами, ложками, чашками и т.д. В результате у нас получится много различных объектов, для каждого из которых нужны специальные материалы и текстуры. Следственно, для оптимизации этих объектов потребуются разные методы: попросту комбинирование, комбинирование + атласинг и комбинирование + атласинг + LOD (для «дальних» степеней с низкой детализацией).

Комбинирование – это техника, при которой вы просто объединяете объекты воедино. Она помогает оптимизировать сцену при загораживании, потому что рендерит всё одним объектом, превращая тяни чайный набор в одну сетку.

Комбинирование + атласинг – это техника, при какой, во-первых, все объекты объединены в одну сетку, а во-вторых, у них на всех лишь одна текстура. Этот метод очень эффективен для ВР-игр, т.к. объединенные текстуры стоят, выражаясь образно, плачевные копейки. Преимущество этой техники в том, что она требует всего шесть команд отрисовки, а недостача – в том, что вы жертвуете детализацией, т.к. каждый объект, скорее всего, имеет собственную карту деталей.

Комбинирование + атласинг + LOD – это техника при какой объекты объединяются в одну сетку и оснащаются одной текстурой, но лишь на самых дальних уровнях детализации. С одной стороны, это позволяет сохранить детализацию, если игрок глядит на объект вблизи, а с другой, позволяет быстро переключиться на оптимизированную версию, когда игрок отдаляется от объекта. В частности, эта техника здорова, если игрок может взять объект в руки.

Что мастерить

Если вы решили воспользоваться простым комбинированием, просто создайте скрипт с этим кодом (это из документации к Unity о функции Mesh.CombineMeshes):

using UnityEngine;
using System.Collections;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class ExampleClass : MonoBehaviour {
void Start() {
MeshFilter[] meshFilters = GetComponentsInChildren();
CombineInstance[] combine = new CombineInstance[meshFilters.Length];
int i = 0;
while (i < meshFilters.Length) {
combine[i].mesh = meshFilters[i].sharedMesh;
combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
meshFilters[i].gameObject.active = false;
i++;
}
transform.GetComponent().mesh = new Mesh();
transform.GetComponent().mesh.CombineMeshes(combine);
transform.gameObject.active = true;
}
}

Если вы разрешили воспользоваться комбинированием с атласингом, советую программу Mesh Baker – она сэкономит вам масса рабочих часов. Для связки «комбинирование + атласинг + LOD» советую воспользоваться Mesh Baker LOD. Немало подробно можно почитать тут и тут.

Есть и более продвинутая техника, какая, впрочем, потребует творческого подхода. Ее суть в том, чтобы вывозить каждый LOD для каждого фрагмента каждого объекта. Сначала при поддержки Mesh Baker скомбинируйте все сетки с высокой детализацией, но без союзы текстур. Затем дайте Mesh Baker оптимизировать посредственную детализацию и удалите некоторые текстуры. Наконец, для сеток с низенькой детализацией замените все шейдеры максимально «легкими», но приемлемыми, а затем скомбинируйте. Эта техника потребует немало времени, но зато сэкономит вам кучу вычислительных ресурсов.

Команды отрисовки (draw calls)

Команда отрисовки – это то, что сквозь драйвер передается от CPU к GPU. Чем меньше команд прорисовки и чем они проще – тем лучше. Самый несложный способ оптимизации команд отрисовки – это оптимизация количества различных материалов и текстурных атласов, а также сокращение количества второстепенных текстур вроде карт вышин, карт нормалей и карт отражения. Выше я уже упоминал об оптимизации команд отрисовки, но в этом разделе я расскажу об этом подетальнее.

Как определить

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

Что мастерить

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

Также полезно изучить игру самостоятельно, с надетым ВР-шлемом. Объекты, какие первыми бросаются в глаза, в будущем могут стать положительной нагрузкой на вычислительные ресурсы. Если ассет не видно, попросту удалите его, а если видно – попробуйте объединить его текстуры. Желая это и требует дополнительной RAM-памяти и места на диске, зачастую комбинирование текстур стоит того, даже если вы заполняете атлас не целиком. Объединение текстур в один материал без объединения сеток дает гибкость в детализации.

Еще одно решение – самостоятельно разработать гибридную систему LOD’ов для объектов, подвигающихся независимо друг от друга. Она начинает обрабатывать объекты, если они оказываются на подобный дистанции, когда их можно будет объединить. Учтите, однако, что пора пребывания объектов на экране может варьироваться, поэтому использование этой техники может быть хуже для производительности, чем ситуация, когда объекты обрабатываются раздельно. С иной стороны, этот прием может помочь, если GPU мощно загружен, а у CPU, наоборот, еще остались ресурсы для работы над другими задачами.

Еще одна техника, о какой разработчики почему-то часто забывают – это комбинирование текстур. Это НЕ атласинг, о каком я рассказывал выше; эту технику еще называют «укладкой в каналы» (от англ. «channel packing»). Ее суть в том, чтобы пристроить разные карты в разные каналы одного RGB-файла. К образцу, у нашего чайника есть карта объемного света, карта отражений и карта вышин. Если поместить объемный свет в красный канал, отражения – в травяной канал, а высоты – в синий канал, в итоге у нас получается итого одна команда отрисовки. Останется лишь повозиться с тем, чтобы шейдеры ведали, где искать нужную карту, но в этом, в общем-то, вся суть оптимизации слабодетализированных объектов.

Итак, процедура такова:

  • Изберите слой
  • Перейдите в каналы
  • Уделите зеленый и синий каналы, чтобы у вас остался одинешенек лишь красный канал
  • Перейдите к слоям и повторите то же самое для травяного канала
  • Сделайте то же самое для синего канала
  • PROFIT!

Запечение обыкновенного света и объемного света (baking)

Как вы уже, наверно, поняли, в ВР любые эти лучше обрабатывать заранее. CPU почти все время занят, пока GPU пыжится обработать спид-дейтинг разом двух игр. Это значит, что чем больше вещей запечено – тем лучше. Используете всюду освещение в реальном времени? Готовьтесь к куче проблем.

Как установить

Почти всему нужны карты теней, т.е. всем объектам, какие не взаимодействуют с освещением, обрабатываемом в реальном времени. Более детально смотрите ниже. О том, как работать с картами теней, смотрите в Lab Render от Valve.

Что мастерить

Во-первых, ищите все, что можно запечь. К сожалению, в данный момент карты теней в Unity организованы так, что запечение света в больших сценах – это очень замороченный (а порами и вовсе безрезультативный) процесс. Поэтому рекомендую сначала вывозить все ассеты в 3D-редактор вроде Maya, а затем спокойно запечь и обыкновенный, и объемный свет. Создание хороших карт теней – это тема для отдельной статьи. По этой ссылке – документация по плагину Turtle для Maya, а по этой – документация по запечению объемного света при поддержки Substance.

Недостаток этого метода в том, что вам также придется создать шейдеры, поддерживающие вновь созданные карты теней. Их, впрочем, не непременно создавать с нуля – вы можете «разобрать», а затем оптимизировать шейдеры от Valve.

Тени от освещения в реальном поре не обязаны быть, собственно, тенями. Просто определите курс света, чтобы создать имитацию тени на земле – так, с помощью анимированного текстурного атласа, сопоставимого с персонажной анимацией или даже с древней методой, популярной как «пузырь» (от англ. «blob shadow»; это обычная круглая тень), к какому прикручена возможность угловой изменчивости. Удивительно, но такую имитацию замечают очень немногие.

Шейдеры

Шейдеры – корень зла (если сообщать исключительно об оптимизации ВР-проектов). Лишь немногие разработчики умеют строчить шейдеры, и многие из этих шейдеров плохо оптимизированы под ВР. Потому самый лучший подход – это либо воспользоваться мобильными шейдерами, либо созидательны подойти к созданию собственного шейдера.

Как определить

Если у шейдера вяще 4 слотов, и объект, для которого он используется, вряд ли привлечет пристальное внимание пользователя, то этот шейдер, по всей видимости, нехорошо оптимизирован для вашего ВР-проекта. Единственное, что нужно объектам «массовки» в ВР – это краска, карта нормалей, карта обычного света и карта объемного света.

Что мастерить

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

Технология Occlusion Culling

Вы, вероятно, ведаете, что в Unity по умолчанию включена технология Frustum Culling, какая отсекает все объекты, которые не находятся в поле зрения игрока. Но вдобавок к этому в Unity есть и технология Occlusion Culling (можно переместить как «отсечение загороженных объектов»). Представьте, к примеру, что позади нашего чайника возлежат столовые ложки. При включенном Occlusion Culling эти ложки рендериться не будут, что подходяще повлияет на производительность.

Как определить

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

Что делать

Occlusion Culling может быть и благом, и анафемой. Лично моя точка зрения такова, что об Occlusion Culling не необходимо беспокоиться вовсе. К примеру, представьте, что на столе стоит чайный комплект, а вы стоите в соседней комнате, поэтому отгорожены от этого комплекта стеной. Как правило, в играх этот набор рендерится, а затем выбрасывается – как раз из-за стены. Но технология Occlusion Culling видает всю сцену заранее просчитанной решеткой, которая состоит из ячей и знает, где какие объекты находятся. Камера отсылает лучи, чтобы проверить, какие ячеи попадают в поле ее видимости, а какие – нет. Ячейки, которые в поле видимости не попадают, не рендерятся. Советую для основы попробовать стандартные настройки – чтобы посмотреть, дает ли это хоть какой-то итог. Если результата нет, можно немного повозиться с настройками, благо немало времени это не отнимет. А если отнимет – бросайте настройку и храбро ставьте сцену на рендер. Если заметили улучшение, измерьте буквальный «вес» всех объектов на сцене.

И еще одна техника напоследок

Она совершенно новая и называется «гибридный моно-рендеринг» (от англ. «hybrid mono rendering»). Если вкратце, ее суть в том, что объекты, находящиеся вблизи, рендерятся в стерео, а удаленные объекты – в моно. Подетальнее о ней можно прочесть тут.

Дополнительные материалы

Надеюсь, эта статья поведала вам немало новоиспеченных и интересных идей об оптимизации в сфере ВР. Но это – лишь капля в море, потому что…

  • …тут можно почитать об оптимизации ВР в Unity
  • …а здесь – об оптимизации ВР в Unreal

Также выражаю вящую благодарность программе Intel Innovator Program за поддержку в написании этой статьи.

Об авторе

Тим Портер (Tim Porter) сидит разработчиком графики для PC и ВР в Underminer Studios. Он имеет богатый эксперимент в работе с передовыми графическими технологиями, благодаря чему научился массе полезных приемов и трюков. Кроме того, ранее он трудился техническим художником, что позволяет ему видеть проблемы с оптимизацией максимально размашисто. Связаться с ним можно по почте.

Оригинал можно почитать тут.