Реверс-инжиниринг процедурной генерации в No Man's Sky

Original author: gregkwaste
  • Translation


No Man’s Sky — это игра про исследование космоса, в которой используется технология процедурной генерации игрового окружения и ресурсов (текстур, моделей, рельефа и т.д.). Я был в восторге, когда объявили о её разработке в 2013 году, не только из-за самой игры, но в основном из-за возможности изучить игровые файлы и узнать, как она работает. После выпуска игра получила самые противоречивые отзывы, но мне всё равно интересно, что же происходит у неё внутри.

Если вы установите игру, то увидите, что по объёму она очень невелика, и это действительно так. Основная причина этого в том, что игра работает с очень ограниченным набором ресурсов и с помощью процедурной генерации создаёт на их основе буквально сотни вариантов. Я сосредоточусь на контенте, связанном с 3D-моделями игры, потому что для меня они всегда наиболее интересны. Статья будет разделена на три основные категории: геометрия, текстуры и анимации.

Геометрия


Итак, в игре файлы геометрии (вершин, буферов индексов и т.д.) хранятся в файлах с расширением ".GEOMETRY.MBIN". Уже с помощью этих файлов можно создать довольно простые парсеры, преобразующие геометрию для работы в ПО 3D-моделирования. Но этого файла недостаточно самого по себе. Такой файл с геометрией используется как контейнер для чистых геометрических данных.

Игра загружает ресурсы как сцены. Это значит, что все ресурсы моделей определяются как файлы отдельных сцен с собственными иерархиями объектов, несколькими частями сеток, несколькими типами объектов (шарниры, источники освещения, точки взаимодействия, коллизии, другие файлы сцены) и т.д. Этот тип информации хранится в файлах ".SCENE.MBIN". Они являются настоящими дескрипторами конкретной сцены, и обычно такие файлы ссылаются на один контейнер геометрии, из которого все части сеток в сцене получают соответствующую информацию о геометрии.

Пока в этом нет ничего нового. Такая же ситуация во множестве разных игр. No Man’s Sky отличается от других игр (по крайней мере, раньше я с таким не сталкивался) тем, что в этом файле сцены не просто одно готовое существо, которое можно заспаунить в игре при определённых условиях, здесь вступает в дело процедурная генерация.

Я кратко объясню, как это выглядит, приложив несколько изображений из созданного мной NMS Model Viewer.


Модель трицератопса

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

Самое важное в этих данных — фактические названия объектов. Можно чётко увидеть, что есть определённая связь между ними и способом, которым игра узнаёт о том, как комбинировать эти части и исключать ненужные при создании модели.

Заметив это, я начал искать другие файлы, которые могут управлять организацией сцены, и оказалось, что это файлы ".DESCRIPTOR.MBIN". Не у всех моделей есть такие файлы. Выяснилось, что они есть только у процедурно генерируемых моделей, а у статических моделей (таких как модель астронавта или материалы, созданные для трейлера) их нет.

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

<Data template="TkModelDescriptorList">
  <Property name="List">
    <Property value="TkResourceDescriptorList.xml">
      <Property name="TypeId" value="_HEAD_" />
      <Property name="Descriptors">
        <Property value="TkResourceDescriptorData.xml">
          <Property name="Id" value="_HEAD_ALIEN" />
          <Property name="Name" value="_Head_Alien" />
          <Property name="ReferencePaths" />
          <Property name="Chance" value="0" />
          <Property name="Children">
             ......;
          </Property>
        </Property>
        <Property value="TkResourceDescriptorData.xml">
          <Property name="Id" value="_HEAD_DIPLO" />
          <Property name="Name" value="_Head_Diplo" />
          <Property name="ReferencePaths" />
          <Property name="Chance" value="0" />
          <Property name="Children">
            ......;
          </Property>
        </Property>
        <Property value="TkResourceDescriptorData.xml">
          <Property name="Id" value="_HEAD_HIPPO" />
          <Property name="Name" value="_Head_Hippo" />
          <Property name="ReferencePaths" />
          <Property name="Chance" value="0" />
          <Property name="Children">
            ......;
          </Property>
        </Property>
        <Property value="TkResourceDescriptorData.xml">
          <Property name="Id" value="_HEAD_RHINO" />
          <Property name="Name" value="_Head_Rhino" />
          <Property name="ReferencePaths" />
          <Property name="Chance" value="0" />
          <Property name="Children">
            ......;
          </Property>
        </Property>
        <Property value="TkResourceDescriptorData.xml">
          <Property name="Id" value="_HEAD_STEG" />
          <Property name="Name" value="_Head_Steg" />
          <Property name="ReferencePaths" />
          <Property name="Chance" value="0" />
          <Property name="Children">
            .....;
          </Property>
        </Property>

Процедура такова: существует основная часть, которая решает, чем она будет являться, в нашем примере это _HEAD_. Обычно части, названия которых начинаются с нижнего подчёркивания, означают, что они относятся к группе дескрипторов и только одна из них будет выбрана для финальной модели. Как вы видите, это часть определена в списке TkResourceDescriptorList. Его элементы содержат свойство «Descriptors», дочерние элементы которого являются кандидатами на выбор. Дальше нужно просто выбрать один из дочерних элементов свойства Descriptors. Так, например, выбирается модель головы. После выбора этой конкретной модели головы есть ещё одно свойство «Descriptors», имеющее собственный список возможных вариантов, и из него опять нужно выбрать один. И так далее.

После выполнения этих операций для всех элементов в файле descriptor.mbin мы в результате получим набор выбранных частей, из которого создаётся уникальная полная модель.


Пример SHARKRIG


Истребитель, экспортированный из программы просмотра моделей No Man's Model Viewer


Стражи

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

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


Случайная генерация существ на основании модели трицератопса


Процедурная генерация истребителей (кубы — это ненанесённые декали)


Процедурная генерация посадочных шлюпок


Процедурная генерация SHARKRIG

Я провёл в игре около 70 часов, и за всё это время я ни разу не встретил существо, похожее на диплодока. Это значит, что либо движок содержит ошибку и эти части не выбираются (в чём я сомневаюсь), либо вероятность выбора этих частей настолько мала, что они чрезвычайно редко появляются в игре. Множество обсуждений (в основном разгневанных) затрагивало отсутствующий в игре контент и контент, присутствующий только в игровых трейлерах, а также похожие темы. Я не могу судить о работе игры или о геймплейных возможностях, но судя по изученному мной количеству моделей существ, в игре существует КУЧА контента, который из-за решений движка (?) появляется в игре не очень часто (или не появляется совсем). По-моему, процедурно генерируемые модели диплодоков в 10 раз лучше статических, и если бы разработчики захотели, они смогли бы заставить движок загружать статические модели (и, разумеется, весь контент из трейлера) в любой момент, поэтому, хорошо это или плохо, но это, скорее всего, дизайнерское решение.


Модель диплодока из трейлера на E3

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

Текстуры


Текстуры — это ещё один сложнейший аспект моделей NMS. Как я упомянул в разделе «Геометрия», все части сеток определяются в файлах SCENE.MBIN. Элементы этих файлов выглядят примерно вот так:

<Property value="TkSceneNodeData.xml">
      <Property name="Name" value="_Head_Tri" />
      <Property name="Type" value="MESH" />
      <Property name="Transform" value="TkTransformData.xml">
        <Property name="TransX" value="0" />
        <Property name="TransY" value="0" />
        <Property name="TransZ" value="0" />
        <Property name="RotX" value="0" />
        <Property name="RotY" value="0" />
        <Property name="RotZ" value="0" />
        <Property name="ScaleX" value="1" />
        <Property name="ScaleY" value="1" />
        <Property name="ScaleZ" value="1" />
      </Property>
      <Property name="Attributes">
        <Property value="TkSceneNodeAttributeData.xml">
          <Property name="Name" value="BATCHSTART" />
          <Property name="AltID" value="" />
          <Property name="Value" value="19140" />
        </Property>
        <Property value="TkSceneNodeAttributeData.xml">
          <Property name="Name" value="BATCHCOUNT" />
          <Property name="AltID" value="" />
          <Property name="Value" value="5772" />
        </Property>
        <Property value="TkSceneNodeAttributeData.xml">
          <Property name="Name" value="VERTRSTART" />
          <Property name="AltID" value="" />
          <Property name="Value" value="3777" />
        </Property>
        <Property value="TkSceneNodeAttributeData.xml">
          <Property name="Name" value="VERTREND" />
          <Property name="AltID" value="" />
          <Property name="Value" value="4894" />
        </Property>
        <Property value="TkSceneNodeAttributeData.xml">
          <Property name="Name" value="FIRSTSKINMAT" />
          <Property name="AltID" value="" />
          <Property name="Value" value="97" />
        </Property>
        <Property value="TkSceneNodeAttributeData.xml">
          <Property name="Name" value="LASTSKINMAT" />
          <Property name="AltID" value="" />
          <Property name="Value" value="124" />
        </Property>
        <Property value="TkSceneNodeAttributeData.xml">
          <Property name="Name" value="MATERIAL" />
          <Property name="AltID" value="" />
          <Property name="Value" value="MODELS\PLANETS\CREATURES\TRICERATOPSRIG\TRICERATOPS\HEADTRIMAT.MATERIAL.MBIN" />
        </Property>
      </Property>
      <Property name="Children">

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

<?xml version="1.0" encoding="utf-8"?>
<Data template="TkMaterialData">
  <Property name="Name" value="DiploHeadMat" />
  <Property name="Class" value="Opaque" />
  <Property name="TransparencyLayerID" value="0" />
  <Property name="CastShadow" value="True" />
  <Property name="DisableZTest" value="False" />
  <Property name="Link" value="" />
  <Property name="Shader" value="SHADERS/UBERSHADER.SHADER.BIN" />
  <Property name="Flags">
    ...
  </Property>
  <Property name="Uniforms">
    ...
  </Property>
  <Property name="Samplers">
    <Property value="TkMaterialSampler.xml">
      <Property name="Name" value="gDiffuseMap" />
      <Property name="Map" value="TEXTURES/PLANETS/CREATURES/TRICERATOPSRIG/DIPLOHEAD.DDS" />
      <Property name="IsCube" value="False" />
      <Property name="UseCompression" value="True" />
      <Property name="UseMipMaps" value="True" />
      <Property name="IsSRGB" value="True" />
      <Property name="MaterialAlternativeId" value="" />
      <Property name="TextureAddressMode" value="Wrap" />
      <Property name="TextureFilterMode" value="Trilinear" />
      <Property name="Anisotropy" value="0" />
    </Property>
    <Property value="TkMaterialSampler.xml">
      <Property name="Name" value="gMasksMap" />
      <Property name="Map" value="TEXTURES/PLANETS/CREATURES/TRICERATOPSRIG/DIPLOHEAD.MASKS.DDS" />
      <Property name="IsCube" value="False" />
      <Property name="UseCompression" value="True" />
      <Property name="UseMipMaps" value="True" />
      <Property name="IsSRGB" value="False" />
      <Property name="MaterialAlternativeId" value="" />
      <Property name="TextureAddressMode" value="Wrap" />
      <Property name="TextureFilterMode" value="Trilinear" />
      <Property name="Anisotropy" value="0" />
    </Property>
    <Property value="TkMaterialSampler.xml">
      <Property name="Name" value="gNormalMap" />
      <Property name="Map" value="TEXTURES/PLANETS/CREATURES/TRICERATOPSRIG/DIPLOHEAD.BASE.NORMAL.DDS" />
      <Property name="IsCube" value="False" />
      <Property name="UseCompression" value="True" />
      <Property name="UseMipMaps" value="True" />
      <Property name="IsSRGB" value="False" />
      <Property name="MaterialAlternativeId" value="" />
      <Property name="TextureAddressMode" value="Wrap" />
      <Property name="TextureFilterMode" value="Trilinear" />
      <Property name="Anisotropy" value="0" />
    </Property>
  </Property>
</Data>

Важная часть файлов материалов — раздел «Samplers». Очевидно, что в этом разделе определяются текстуры, используемые в части модели. И вот что интересно: для статических моделей все текстуры являются очень качественными текстурами, которые без всяких проблем можно использовать непосредственно на моделях. Но если сетка используется для процедурно генерируемой модели, правильной является только текстура нормалей. Диффузная текстура, которая содержит всю цветовую информацию о части, представляет собой пустую белую текстуру.

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


Пример текстуры с пятнами

Детали текстуры при процедурной генерации могут очень сильно отличаться. Похоже, что текстуры создаются послойно. Я покажу пример сборки процедурно генерируемой текстуры существа. Обычно нижним слоем служит базовая текстура, добавляющая основной цвет и оттенок модели (имена таких текстур заканчиваются на .BASE.DDS). На следующем слое находится текстура подбрюшья (.UNDERBELLY.DDS), которая добавляет деталей на брюхе животного. Затем идёт ещё один слой, добавляющий больше деталей на случайных участках модели (.UNDERLAYER.X.DDS). Потом идут отметины (.MARKINGS.X.DDS), определяющие наиболее заметные детали кожи модели. На следующем слое снова находятся детали кожи, расположенные поверх отметин (.SKIN.DDS), а на последнем слое накладывается ещё одна текстура (TOP.X.DDS), добавляющая деталей на отдельные части модели.

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

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


FURPALETTE.DDS


PAINTPALETTE.DDS

Итак, в процессе создания планеты (или создания звёздной системы) выбираются определённые цвета, которые будут использованы для живых существ всей планеты. Я говорю о выборе цвета, потому что в игровых файлах есть конкретные цветовые палитры размером 8×8 (в папке PCBANKS/TEXTURES/PALETTES). Вероятно, эти палитры составляют различные формы. Это значит, что 64 цвета, содержащиеся в палитрах, обычно объединяются в группы по 4 или 8 цветов. Поэтому когда игра создаёт среду планеты, она выбирает из этих групп, которые будут использованы позже. Эти группы легко определить, глядя на палитры, потому что они на самом деле являются градиентом двух граничных цветов.

Индексирование в выбранной группе выполняется с информацией, содержащейся в файле .texture.mbin file. Описание текстуры в таких файлах выглядит следующим образом:

<Property value="TkProceduralTexture.xml">
        <Property name="Name" value="GRADIENT" />
        <Property name="Palette" value="TkPaletteTexture.xml">
          <Property name="Palette" value="Fur" />
          <Property name="ColourAlt" value="Alternative1" />
        </Property>
        <Property name="Probability" value="1" />
        <Property name="TextureGameplayUse" value="IgnoreName" />
        <Property name="OverrideAverageColour" value="False" />
        <Property name="AverageColour" value="Colour.xml">
          <Property name="R" value="0" />
          <Property name="G" value="0" />
          <Property name="B" value="0" />
          <Property name="A" value="0" />
        </Property>
        <Property name="Diffuse" value="TEXTURES/PLANETS/CREATURES/TRICERATOPSRIG/ALIENDIPLO.MARKINGS.GRADIENT.DDS" />
        <Property name="Normal" value="TEXTURES/PLANETS/CREATURES/TRICERATOPSRIG/ALIENDIPLO.MARKINGS.GRADIENT.NORMAL.DDS" />
        <Property name="Mask" value="TEXTURES/PLANETS/CREATURES/TRICERATOPSRIG/ALIENDIPLO.MARKINGS.GRADIENT.MASKS.DDS" />
      </Property>

Я снова не буду говорить о том, что делают остальные опции. Нас волнует только описание в свойстве «Palette». Из информации в этом свойстве мы можем узнать, какой цвет нам нужно выбрать для части. В нашем случае видно, что требуется индекс палитры «Fur» (мех) (которая, как мы видели ранее, состоит из групп по 4 цвета), и в выбранной группе нам нужен цвет «Alternative1». Вот как индексируются цвета в палитрах. Эти значения свойства «ColourAlt» могут быть равны «Primary», «Alternative1», «Alternative2», «Alternative3» и т.д. Значит, primary будет первым цветом в группе, alternative1 — вторым, и т.д. Тут я тоже не на 100% уверен, но я использую палитры так, и это логично, исходя из принципа групп цветов в палитре.

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

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

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

Анимации



Скелетная анимация модели трицератопса


Цикл анимации ходьбы астронавта


Анимация медленной ходьбы процедурно сгенерированной модели Spiderrig

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

Во-первых, скелеты моделей определяются в файлах «SCENE.MBIN». Они представляют собой иерархическую систему шарниров, к которой с помощью скиннинга вершин прикрепляются части моделей. В этом нет ничего удивительного. Интересно то, что, как я упомянул в разделе «Геометрия», в файле SCENE.MBIN есть множество частей сеток. Поэтому для управления анимацией и движением всех этих частей назначенная система шарниров влияет на все части сцены.

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

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

Выводы


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

Однозначного ответа на этот вопрос нет.

Как разработчик ПО и реверс-разработчик видеоигр я отвечаю: да, определённо стоила. С технической точки зрения я никогда не видел игровых механик, похожих на механику NMS, и я сомневаюсь, что увижу в новых играх, использующих технологию процедурной генерации. Потому что никто не будет пытаться создавать вымышленные миры с таким уровнем случайности. Технически No Man’s Sky стала настоящим сокровищем, и каждый, кто пытается отрицать это, просто лжёт себе, или не знает о том, как работает игра (или не интересуется этим). Игровой движок имеет очень большой потенциал, и я постоянно думаю о том, какой могла стать игра, если бы движок был в руках большой игровой студии. Даже с учётом ограниченности ресурсов мне всё равно нравится многообразие существ, которое я вижу в игре (и я считаю, что с помощью более тонкой настройки мы можем выжать даже больше из имеющихся ресурсов).

Мои чувства как игрока противоречивы. Хотя это и не мой стиль игры, но с самого предзаказа No Man’s Sky я знал, что это будет игра, в которой я смогу просто расслабиться. Изучать окружающую среду, растения и животных. Сначала все они кажутся одинаковыми, но приглядевшись, мы увидим в большинстве из них отличия. Может быть, отличаются только текстуры, но они разные: это может быть маленький рог на голове существа, или разные пятна, или отличающаяся деталь корабля. Контент есть в игре (даже геймплейный, который бы разработчики могли заспаунить, если бы хотели), нельзя сказать, что его нет. Всё, что мы получаем — это результат чрезвычайно хорошей процедуры генерации. Фактически, контент, создаваемый движком NMS для системы из 2-3 планет, намного превосходит ресурсы, которые можно видеть, например в ARK. Разумеется, никакие существа не будут полностью идеальными, как динозавры в ARK, но в этом и состоит их прелесть. Именно движок может создавать роскошных и величественных созданий, и в то же время — самых невразумительных животных, которые были в компьютерных играх. Вот почему я купил эту игру, и почему я люблю её. Я живу ради тех моментов, когда после исследования разной утомительной ерунды я внезапно приземляюсь на самую красивую планету, которую когда-либо видел. Повторюсь, я не сравниваю элементы RPG или возможности геймплея. Я говорю только о процедурном контенте. Это не значит, что игра не могла быть лучше. Я верю, что могла, и жду, что разработчики её улучшат.

С другой стороны, если вы не настроены на расслабление, терпеливость и внимание к деталям, игра не стоит покупки, и вся процедурная генерация для вас будет простой тратой ресурсов. Это не шутер, где за вами постоянно охотятся и вы постоянно находитесь в напряжении. Разработчики чётко дают это понять. Для тех, кто выбрал такой стиль игры, всё будет выглядеть одинаковым. Даже если бы контент из трейлера создавался в игре, и на каждой второй планете была пышная растительность, динозавры и песчаные черви, игра всё равно наскучила бы вам. После третьей звёздной системы вам показалось бы всё одинаковым, потому что вы бы не приглядывались внимательно. Нельзя винить игру или разработчиков за то, что вы не занимаетесь исследованиями в игре про исследования. Кроме того, процедурная генерация никогда не была и не станет способом создания достойного контента «с нуля». По крайней мере, не в ближайшем будущем. Нельзя просто написать математическое выражение и создать новое животное. Такое сгодится для рельефа, растений, камней или кораблей (при этом текстурирование всё равно будет под большим вопросом), но для живых подвижных объектов, таких как существа или NPC всё становится настолько сложным, что это практически невозможно. (Разумеется, если бы это было возможно, у разработчиков не было причин не сделать этого, ведь они уже сделали подобное с остальными объектами.) Поэтому если вы ожидаете через каждые пять шагов видеть нового инопланетянина, то простите, это проблема ваших ожиданий, а не разработчиков. Если и есть способ создания такого контента, то это именно способ движка NMS.

В конце концов, после всех моих исследований я знаю, что в игре есть достаточно контента, чтобы по крайней мере создавать всё по-новому на каждой планете, так что я не могу винить игру или движок. Я могу обвинить настройку и конфигурирование движка. Ещё я могу обвинит проклятые многоплатформенные релизы и издателя. Я уверен на 10000000000000000000%, что разработчики были вынуждены торопиться при выпуске игры. Игра, которую мы получили, далека от завершённости, и даже не приближается на 80% к возможностям, которые предусмотрены движком. После изучения файлов мне это абсолютно ясно. Она ближе к технической демке, а не к игре. Попытка запихнуть одинаковый контент на PC и PS4 просто растерзала игру, а стремление заставить работать её на слабых машинах ещё больше снизило качество. Лично я жду обновлений, и их должно быть много. Я могу простить множество ошибок Hello Games при релизе игры, завышенную стоимость, нехватку связи с потребителями, даже отсутствие многих возможностей (например, многопользовательского режима, на который, честно говоря, мне наплевать). Но даже с учётом неразберихи и напряжения перед релизом я не могу простить того, что они не смогли полностью показать, на что способен движок с правильной конфигурацией. Моддеры сейчас погружаются в дебри файлов и пытаются найти способы создания тем же самым движком более богатого и разнообразного контента. И чаще всего у них это получается, потому что движок может обеспечивать гораздо более качественную игру. Все эти опции должны быть доступными любому игроку, а не только моддерам. Очевидно, разработчики решили не давать игрокам такой возможности, чтобы все они находились в одинаковой вселенной и могли иметь общие точки маршрута, существ и планеты. Но они должны были оставить такую возможность. Сделать упор на одиночной игре и показать всем игрокам, на что способен движок.

Почему-то мне кажется, что рано или поздно HG так и поступят. Они не могут просто забыть четыре с лишним года работы над движком, который на самом деле замечателен. А всем любителям конспирологических теорий о Hello Games я могу сказать, что у разработчиков была тысяча способов получить ваши деньги, и если бы у них было такое желание, это могло бы произойти гораздо раньше.

Ещё до того, как движок игры станет настолько прекрасным…
Support the author
Share post

Comments 33

    +1
    «Как вы видите, на первый взгляд сцена представляет собой полный хаос, нельзя даже точно сказать, что мы видим, и это точно нельзя создать в сцене.» — очень старался, но так и не «осилил» это предложение.
      0
      Статью написал сам движок NMS.
      0
      Отличный перевод и статья, я единственное не понимаю, почему разработчики не додумались до такой идеи, как менять «волшебное число» генерации из перехода с одной галактики в другую, чтобы весь мир тоже менялся.
        0
        Я думаю, что менять параметры можно, однако слишком опасно: побочные эффекты могут проявиться из ниоткуда. Это же сильно нелинейная система — процедурный мир.
        +6
        из воспоминаний разработчиков — Elite была готова генерировать 32 млн звезд, но издатели попросили ограничить до 8к — так лучше видно «разнообразие».
        ЗЫ. спасибо за сатью!
          0
          вообще там речь была про 8 галактик :) и в итоге те их миллионы никуда не делись, просто стали недоступны из стандартной игры. кстати, в нмс поступили похожим образом, только число галактик сделали 256 и не стали закольцовывать на начало списка отчего-то
          0
          Я думал, отреверсили и поняли почему оно так дико тормозит :)
            +2
            Теперь всё это хорошенько смешать, и получится отличный инструмент для игроделов.
            Можно будет сгенерировать сотни персонажей, и отобрать лучших для своей игры.
            А если будет удобный инструмент создания правил генерирования, то персонажи разных игр даже не будут похожи друг на друга.
              +3
              На самом деле такая технология была бы полезна для того, чтобы мир был менее «одинаковый». Когда игра надоедает, начинаешь присматриваться и начинает бросаться в глаза что все люди/животные/техника/здания/прочие_объекты вообще одинаковые. А так, было бы здорово, если все они отличались чуть-чуть — этот домик более ветхий; у этого статиста шрам на лице, а у этого ожег на руке и царапинка на шее; у того животного не хватает глаза и выдран клок шерсти, а у этого лапа в грязи; на той машинке помят бампер и поцарапано крыло, а на третьей у водителя на приборной панели целый иконостас; у одного охранника обычный АК, а у второго с примотанной тряпкой на прикладе и т.п.

              Обычно такие элементы в играх жестко ограничены, а если бы генерировались рандомно, а не заранее намоделены были…
                0
                Помнится, вроде крайтек лет 10 назад обещали автогенерируемых персонажей, чтобы абсолютно все npc получались с разной внешностью. Так я этого и не дождался.
                  0
                  забавно, что сейчас Стар Ситизен делает именно это на том же движке, но даже они решили (на данном этапе), что лучше иметь примерно 20 «заготовок» лиц и добавлять к ним небольшие изменения.
                0
                Процедурная генерация — будущее для ОЧЕНЬ больших игр. (В той мере, в какой они будут нужны. Земля для миллиардов, город для миллиона).
                  –2
                  Автор рассуждает об игре как о скринсейвере с рыбками.
                    0
                    Получается что NMS это крутецкая демка про процедурную генерацию за 3500р (на пс4). Спасибо за статью)
                      +9
                      На мой взгляд генерация ни разу не прорывная.Берем пять деталей и пытаемся слепить из них два ну совершенно разных существа, ага. Я уже обжегся с завышенными ожиданиями от генерации еще на spore Уила Райта (хотя как набор мини-игр в то время этот проект был действительно впечатляющим).

                      Я это все к чему — после крутых книг/фильмов о фантастике, после в ручную созданных рас в космических стратегиях (см stellaris) не получается верить что во вселенной могут быть только двух-четырехногие существа отличающихся парой лишних крыльев.
                        +1
                        Все так, ничего особо революционного в нмс нет. Со Спорой сравнивали со дня релиза и не в пользу нмс, очевидно. Но самая беда нмс в том, что, скажем так, пропорции генератора выбрали неверно: взяли «крылья ноги и хвосты», тупо смешали погуще и вперед выпекать животин, как пирожки на конвейере. А не надо было давать такой частый выход фауны — люди не должны так часто видеть нечто настолько уникальное (теоретически), как формы жизни, а особенно — фауну. В результате всем это просто приелось и началось автоматическое сравнение и мозг человека волей-неволей стал замечать одинаковые «детали» всех этих франкенштейнов и отторгать мир игры.
                          0
                          Соглашусь. Процедурная генерация может быть неплоха как фон, но неспособна дать реальное разнообразие и интерес, ну или во всяком случае это требует огромного количества труда, как нарисовать очень много составных частей и подобрать всякие хитрые коэффициенты чтобы оно красиво смешивалось — зачастую это более трудоемко чем нарисовать нужное количество зверей/инопланетян вручную.

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

                          Процедурной генерацией все болели несколько лет назад, и мне казалось что уже переболели когда увидели ее ограниченность и так сказать «однообразное разнообразие».
                            0
                            Это не её ограниченность, а её реализации. Или подхода к генерации. Более тщательный и осмысленный подход должен исправить ситуацию. А пока большинство генераторов сделаны по принципу — рандом на входе, рандом на выходе. В лучшем случае с минимальным анализом результата (чтобы комнаты не пересекались в пространстве например).

                            Весь реальный мир по сути — процедурная генерация, и ничего, вполне играбельно ;)
                          0
                          Интересно, а как игра сшивает разные сетки? Если я правильно понял, то модель собирается из кучи их.
                            +2
                            Думаю, что у вершин швов есть индексы, и швы просто соединяются соответственно им. Например, вершина 1 шва «шеи» соединяется с вершиной 1 шва «головы», и т.д. А вот автоматический скиннинг и анимации — это действительно сложно.
                            0
                            Я никогда не понимал, почему нельзя подключить всех желающих к такому проекту — дать им сырой движок и выбрать для каждого желающего сферу которую он будет там прокачивать, потом собрать результат и соединить все вместе. Фантазии тысяч желающих могло реализоваться в этой игре… А так они малым составом потеют и тужатся, чтобы впихнуть все в сжатые сроки, при этом выбрав для этого совершенно инновационную технологию построения игровой структуры.
                              0
                              Ответ прост — деньги. А то придется делиться с тысячами желающих.
                              • UFO just landed and posted this here
                                  0
                                  Только в этом случае проект никогда не будет готов. Это же деятельность ради деятельности, а не ради результата. В этом нет ничего плохого, но для коммерческого продукта такой подход не подойдёт.

                                  Другое дело, если уже после запуска игры дать игрокам инструменты и позволить делиться своими творениями. Ну то есть модостроение и прочие штуки никто не отменял. Может, разработчиками NMS стоило в эту сторону больше развивать игру — люди могли бы создавать свои планеты, звёздные системы и галактики )
                                    0
                                    Не смогли бы, проект не подразумевает даже минимальной «отсебятины» в мире, абсолютно все прибито генерацией, видимо они решили/поняли, что сервак не осилит такого.
                                    Пришлось бы сильно переделывать движок, а в итоге получится средненькая игра-редактор моделек. Или вот как автор описанной в статье утилиты сделал, только данные будут храниться на сервере и доступны всем.
                                      0
                                      Но если ограничить игроков только существующими деталями конструктора (описанными в статье), то достаточно на сервере хранить seed для объекта, сгенерированного игроком, и тогда все другие игроки смогли бы получить тот же самый контент в результате генерации. Было бы интересно, мне кажется.

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

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

                                    А те кто хочет и умеет зачастую уже и так делают что-то свое, зачем им в чужое лезть?

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

                                      Соглашусь что рассчитывать не стоит, но есть много игр в стиме где в мастерской много годных материалов.

                                        0
                                        Вы удивитесь, но людей, готовых бесплатно помочь в разработке игры, очень много. Для большинства — это возможность самоутвердиться — похвастаться друзьям, что они сделали свой вклад в крупный проект. Множество игроков вполне реально понимают, что они обычные потребители, и прикоснуться к миру игроделов, это мечта многих геймеров. К тому же это добавило бы популярности игре.
                                          0
                                          Все бы хорошо, но только не про эту конкретную игру. :) Как видно из статьи, замоддить в традиционном смысле можно всего несколько вещей: космонавта, которого все равно никто не видит, и несколько скриптовых объектов. А в движок все равно мододелов не пустят. Ну разве что кто-то отреверсит все целиком, включая сервак. Но кому теперь это нужно?
                                  –4
                                  Технически No Man’s Sky стала настоящим сокровищем

                                  ну само собой, за 60 бачей-то, еще бы не сокровище… :3

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

                                    Only users with full accounts can post comments. Log in, please.