Искать

Использование префабов с запеченным светом на мобильных устройствах

и другие несложные приемы достижения 60 кадров в секунду на маломощных смартфонах

Last updated: January 2019

What you will get from this page: Michelle Martin, software engineer at MetalPop Games explains how they optimized their new mobile strategy game, Galactic Colonies, for a range of mobile devices, so they could reach as many potential players as possible.

MetalPop Games faced the challenge of making a game in which players could build huge cities on their low-end devices, without their framerate dropping or their device overheating. See how they found a balance between good-looking visuals and solid performance.

Градостроительство на маломощных устройствах

As powerful as mobile devices are today, it is still very difficult to run large and good looking game environments at a solid frame rate. Achieving solid 60fps in a large scale 3d environment on an older mobile device can be quite a challenge.

As developers we could just target high-end phones and assume that most players will have good enough hardware to run our game smoothly. But this will result in locking out a huge amount of potential players, as there are still many older devices in use. Those are all potential customers you don’t want to exclude if it can be avoided.

In our game Galactic Colonies, the players colonize alien planets and can build huge colonies made up from a large number of individual buildings. While smaller colonies might only have a dozen buildings, larger ones can easily have hundreds of them.

This is what our goal list looked like when we started building our pipeline:

  • We want huge maps with a high amount of buildings
  • We want to fast run on cheaper and/or older mobile devices
  • We want nice looking lights and shadows
  • We want an easy and maintainable production pipeline
Освещение в мобильных играх: обычные проблемы

Хорошее освещение в игре - ключ к тому, чтобы 3D-модели выглядели великолепно. В Unity это можно сделать довольно просто: настройте свой уровень, разместите динамические источники света - и всё готово! А если возникает проблема с производительностью, просто запеките все освещение и добавьте эффекты SSAO и прочие "конфетки для глаз" посредством стека постобработки. Теперь точно всё!

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

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

Спасительное запекание света

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

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

Unity light baked prefabs for mobile MetalPopGames Galactic Colonies

(Типичный уровень в Galactic Colonies с большим числом зданий)

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

Правдоподобная подделка

Процесс запекания света состоит в том, что предварительно рассчитываются светлые и темные (тени) места в статичной сцене, и эта информация сохраняется в карте освещенности.

Благодаря этому рендерер получает информацию о том, где сделать модель светлее или темнее, что создает иллюзию освещения.

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

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

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

Но в целом вы получаете грандиозный прирост скорости.

Unity light baked prefabs for mobile MetalPopGames

(Здание с картой освещенности и без нее)

Однако, не получится просто нажать кнопку Bake, если у вас динамический мир, который может постоянно изменяться игроком.

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

Не так просто запекать свет в префабах

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

Очевидно, это не сработает, когда вы создаете уровни динамически. В градостроительной игре мир не строится заранее. Вместо этого он в большой степени собирается динамически и "на лету" в зависимости от решения игрока что строить и где строить. Обычно это осуществляется путем создания экземпляров префабов всякий раз, когда игрок решает строить что-либо.

Единственное решение этой проблемы - хранить все относящиеся к запеканию света данные в префабе, а не в сцене.

К сожалению, нет легкого способа скопировать в префаб данные карты освещенности для использования, ее координаты и масштаб.

Создание конвейера для префабов с запеченным светом

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

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

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

В ходе процесса запекания света Unity создает новый набор UV-координат (указывающих на текстуры карты освещенности) и смещение и масштаб индивидуальной меши. Эти координаты меняются всякий раз при повторном запекании света.

Как использовать UV-каналы

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

Каждая меш может иметь несколько наборов UV-координат (называемых UV-каналами в Unity). В большинстве случаев достаточно одного набора UV, поскольку различные текстуры (Diffuse, Spec, Bump и т.д.) хранят информацию в одном и том же месте в изображении.

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

Недостаток использования множества UV-координат состоит в том, что они расходуют дополнительную память. Если вы используете два набора UV вместо одного, КАЖДЫЙ отдельный вертикс меши теперь имеет в два раза больше UV-координат. Для каждого вертикса вы храните два дополнительных числа с плавающей запятой, а также передаете их в графический процессор во время рендеринга.

Создание префабов

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

Представьте себе куб с одной и той же текстурой на каждой грани: отдельные грани куба имеют одни и те же UV-координаты, поскольку они повторно используют одну и ту же текстуру. Но это не сработает для объекта с картой освещенности, поскольку каждая сторона куба по-своему освещена и отбрасывает тень. Каждой стороне требуется собственное пространство в карте освещенности со своими индивидуальными данными по освещенности. Как результат, возникает необходимость в новом наборе UV.

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

После запекания освещенности мы запускаем скрипт, который проходит по всем мешам в сцене и записывает UV-координаты в фактический канал UV2 меши с примененными величинами для смещения и масштабирования.

Код для изменения меши относительно простой:

Mesh meshToModify = GetComponent().sharedMesh;
Vector4 lightmapOffsetAndScale = GetComponent().lightmapScaleOffset;

Vector2[] modifiedUV2s = meshToModify.uv2;
for (int i = 0; i < meshToModify.uv2.Length; i++)
{
    modifiedUV2s[i] = new Vector2(meshToModify.uv2[i].x * lightmapOffsetAndScale.x +
    lightmapOffsetAndScale.z, meshToModify.uv2[i].y * lightmapOffsetAndScale.y +
    lightmapOffsetAndScale.w);
}
meshToModify.uv2 = modifiedUV2s;

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

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

Настраиваемый шейдер карты освещенности

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

Фактическая текстура карты освещенности добавляется настраиваемым шейдером, который применяет карту освещенности к модели в качестве второй световой текстуры во время рендеринга.

Шейдер очень простой и короткий, и помимо применения цвета и карты освещенности, вычисляет малозатратный эффект фиктивного зеркального отражения/глянца.

Shader "Custom/LightmappedPrefabWithSpec"
{
  Properties
  {
    _MainTex("Base (RGB)", 2D) = "white" {}
    _Lightmap("Lightmap", 2D) = "white" {}
    _Specmap("Specmap", 2D) = "white" {}
    _SpecularAtt("Glossiness", Range(0.1, 2)) = 0.5
    _SpecularAmt("Specular", Range(0, 1)) = 0.5
  }

  SubShader
  {
    Tags{ "Queue" = "Geometry+1" }
    Pass
    {
      CGPROGRAM

      // Defining the name of the vertex shader
      #pragma vertex vert

      // Defining the name of the fragment shader
      #pragma fragment frag


      // Include some common helper functions,
      // specifically UnityObjectToClipPos and DecodeLightmap.
      #include "UnityCG.cginc"

      // Color Diffuse Map
      sampler2D _MainTex;
      // Tiling/Offset for _MainTex, used by TRANSFORM_TEX in vertex shader
      float4 _MainTex_ST;


      // Lightmap (created via Unity Lightbaking)
      sampler2D _Lightmap;
      // Tiling/Offset for _Lightmap, used by TRANSFORM_TEX in vertex shader
      float4 _Lightmap_ST;

      // Grayscale Map indicating which parts of the models have specular
      // Note: _Specmap_ST is not needed, as this map is using the same
      // UVs as for the _MainTex.
      sampler2D _Specmap;

      // This is the vertex shader input: position, UV0, UV1, normal
      // UV1 (= second UV channel) needed for the lightmap texture coordinates
      struct appdata
      {
        float4 vertex   : POSITION;
        float2 texcoord : TEXCOORD0;
        float2 texcoord1: TEXCOORD1;
        float3 normal: NORMAL;
      };

      // This is the data passed from the vertex to fragment shader
      struct v2f
      {
        float4 pos  : SV_POSITION; // position of the pixel
        float2 txuv : TEXCOORD0; // for accessing the diffuse color map
        float2 lmuv : TEXCOORD1; // for accessing the light map
        float3 normalDir : TEXCOORD2; // for fake specular
      };

      // This is the vertext shader, doing nothing special at all.
      // Most notably it is calculating the surface normal, because that
      // is needed for the fake specular lighting in the fragment shader.
      v2f vert(appdata v)
      {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.txuv = TRANSFORM_TEX(v.texcoord.xy, _MainTex); // using _MainTex_ST
        o.lmuv = TRANSFORM_TEX(v.texcoord1.xy, _Lightmap); // using _Lightmap_ST

        // Calculating the normal of the vertex for the fragment shader
        float4x4 modelMatrixInverse = unity_WorldToObject;
        o.normalDir = normalize(mul(float4(v.normal, 0.0), modelMatrixInverse).xyz);

        return o;
      }

      uniform float _SpecularAtt;
      uniform float _SpecularAmt;

      // Fragment Shader
      half4 frag(v2f i) : COLOR
      {
        // Reading color directly from the diffuse texture, using first UV channel
        half4 col = tex2D(_MainTex, i.txuv.xy);
        // Reading specular (on/off) value from spec map texture
        half4 specVal = tex2D(_Specmap, i.txuv.xy);
        // Reading lightmap value from the lightmap texture
        half4 lm = tex2D(_Lightmap, i.lmuv.xy);

        // Fake specular light angle calculation with a hard-coded light direction
        half3 th = normalize(half3(0, 1, -0.25));
        float spec = max(0, dot(i.normalDir, th));

        // Adjusting by overall specular amount and glossyness (material parameters)
        spec = _SpecularAmt * pow(spec, 40.0 * _SpecularAtt);
        // We're just using red value of the specular texture, like a grayscale map,
        // although technically spec could be colored.
        // Example: float3 specCol = specVal * spec;
        spec = spec * specVal.r;

        // Calculating the final color of the pixel by bringing it all together
        col.rgb = min(half4(1,1,1,1), col.rgb * DecodeLightmap(lm) + col.rgb * spec);
        return col;
      }
      ENDCG
    }
  }
  Fallback "Diffuse"
}

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

Unity light baked prefabs for mobile Material setup MetalPopGames

(Настройка материала с использованием настраиваемого шейдера)

Настройка и статическое пакетирование

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

Во всех префабов из заданной сцены используется единственная карты освещенности. Это означает добавление одной текстуры, помимо префабов, с одним материалом.

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

Unity light baked prefabs for mobile bake level MetalPopGames

(Уровень запекания в редакторе Unity)

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

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

  • The correct material is assigned to all meshes
  • Hides everything that doesn’t need to be baked during the process
  • Combines/bakes the meshes
  • Copies the UVs and creates prefabs
  • Names everything correctly and checks out the necessary files from the version control system

Unity light baked prefabs for mobile custom inspector MetalPopGames

(Пользовательский инспектор для облегчения рабочего процесса)

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

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

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

Фиктивное освещение и динамические части

Одним из очевидным недостатков сцены, в которой 100% освещения запечено заранее, является то, что в нее трудно внедрить динамические объекты или движение. Для всего, что отбрасывает тени, потребовался бы расчет освещенности и теней в реальном времени, чего, конечно же, мы хотели бы полностью избежать. Но без движущихся объектов 3D-среда выглядит статической и мертвой.

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

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

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

Shader "Custom/FakeLighting"
{
  Properties
  {
    _Color ("Color", Color) = (1,1,1,1)
    _Brightness ("Brightness", Range(0,1)) = 0.4
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
  }

  SubShader
  {
    Tags { "RenderType" = "Opaque" }
    LOD 200
    Pass
    {

      CGPROGRAM

      // Define name of vertex shader
      #pragma vertex vert
      // Define name of fragment shader
      #pragma fragment frag

      // Include some common helper functions, such as UnityObjectToClipPos
      #include "UnityCG.cginc"

      float4 _Color;
      float _Brightness;

      // Color Diffuse Map
      sampler2D _MainTex;
      // Tiling/Offset for _MainTex, used by TRANSFORM_TEX in vertex shader
      float4 _MainTex_ST;

      // This is the vertex shader input: position, UV0, UV1, normal
      struct appdata
      {
        float4 vertex   : POSITION;
        float2 texcoord : TEXCOORD0;
        float3 normal: NORMAL;
      };

      // This is the data passed from the vertex to fragment shader
      struct v2f
      {
        float4 pos  : SV_POSITION;
        float2 txuv : TEXCOORD0;
        float3 normalDir : TEXCOORD2;
      };

      // This is the vertex shader
      v2f vert(appdata v)
      {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.txuv = TRANSFORM_TEX(v.texcoord.xy,_MainTex);

        // Calculating normal so it can be used for fake lighting
        // in the fragment shader
        float4x4 modelMatrixInverse = unity_WorldToObject;
        o.normalDir = normalize(mul(float4(v.normal, 0.0), modelMatrixInverse).xyz);

        return o;
      }

      // This is the fragment shader
      half4 frag(v2f i) : COLOR
      {
        // Reading color from diffuse texture
        half4 col = tex2D(_MainTex, i.txuv.xy);

        // Using hard-coded light direction for fake lighting
        half3 th = normalize(half3(0.25, 1, -0.25));
        // Using hard-coded light direction for fake specular
        // This matches the value inside the LightmappedPrefabWithSpec shader
        half3 sth = normalize(half3(0, 1, -0.25));

        // Fake lighting
        float lightVal = max(0, dot (i.normalDir, th));
        float lightScale = 0.75;
        lightVal = lightVal * lightScale;

        // Fake spec
        float spec = max(0, dot(i.normalDir, sth));
        float specScale = 0.65;
        float specAtt = 0.65;
        spec = specScale * pow (spec, 40.0 * specAtt);

        // Add in a general brightness (similar to ambient/gamma) and then
        // calculate the final color of the pixel
        col.rgb = min(half4(1,1,1,1), col.rgb * _Brightness +
                      col.rgb * lightVal * _Color + col.rgb * spec);
        return col;
      }

      ENDCG
    }
  }
  FallBack "Diffuse"
}

Также объекты либо не имели тени или мы создавали фиктивную тень как часть динамики. Большинство наших поверхностей - плоские, так что в нашем случае это не было большим препятствием.

Unity light baked prefabs for mobile Galactic Colonies MetalPopGames

(Здания, в которых используются дополнительные динамические объекты)

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

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

Всегда быстрее работать с постоянными, чем с динамическими величинами. Это дало нам базисное освещение, светлые и темные стороны мешей.

Зеркальное отражение/глянец

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

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

К счастью, в нашей игре есть только один источник света, который стоит использовать для эффекта зеркального отражения: это солнце. В нашем случае солнце никогда не движется, так что можно считать, что солнечный свет всегда падает с одного направления. Мы можем значительно упростить шейдер, используя только один источник света, причем с фиксированным положением и углом.

Более того, наша камера в Galactic Colonies показывает сцену в перспективе "вид сверху", как в большинстве градостроительных игр. Камера может быть немного наклонена и немного приближаться или отдаляться, но не может вращаться относительно вертикальной оси.

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

Таким образом мы могли жестко закодировать постоянную величину в шейдер и тем самым достичь малозатратного эффекта зеркального отражения/глянца.

Unity light baked prefabs for mobile Galactic Colonies MetalPopGames

(Фиктивный эффект зеркального отражения/глянца)

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

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

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

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

Префабы с запеченным освещением поверх префабов с запеченным освещением

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

Такая ситуация вызывает проблемы. поскольку мы имеем объект с запеченным освещением поверх другого объекта с запеченным освещением. Прям запеканка!

Мы решили эту проблему с помощью другого малозатратного приема:

  • The surface where the additional object was to be added had to be flat and use a specific gray color matching the base building
  • In return for that trade-off, we could bake the objects on a smaller flat surface and place it on top of the area with just a slight offset
  • Lights, highlights, colored glow and shadows were all baked into the tile

Unity light baked prefabs for mobile Galactic Colonies MetalPopGames

(Запеченные объекты используют синее свечение и отбрасывают тени)

Малозатратное и эффективное запекание света – если вы может мириться с ограничениями

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

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

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

Unity light baked prefabs for mobile Galactic Colonies MetalPopGames

(Построенная игроком колония, в которой используются префабы с запеченным освещением)

Используйте то, что подходит для вашей игры

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

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

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

Дополнительные ресурсы

Мы очень хотим знать, нравится ли вам наш контент.

Да, хочу больше Нет, могло быть и лучше
Согласен

Мы используем cookie-файлы, чтобы вам было удобнее работать с нашим веб-сайтом. Подробные сведения смотрите на странице политики обработки cookie-файлов.