Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество

Spatial

Опубликованно: 07.05.2017, 0:21
Последняя редакция, Andry: 28.09.2017 17:11

Это введение в концепцию Spatials, и элементов графа 3D-сцены. Граф сцены — это структура данных, которая управляет всеми объектами в вашем 3D мире. Например, граф сцены отслеживает 3D-модели, которые вы загружаете и размещаете в 3D пространстве. Когда вы расширяете Java-класс от com.jme3.app.SimpleApplication, вы автоматически наследуете граф сцены и его корневой узел(rootNode).

Корневой узел(rootNode) является центральным элементом графа сцены. Даже если граф сцены пуст, он всегда содержит по крайней мере корневой узел(rootNode). Мы присоединяем Spatials к корневому узлу. Прикрепленные Spatials всегда находятся в отношениях родитель-потомок. Каждый раз, когда вы присоединяете Spatial к чему-то, он неявно отсоединяется от своего предыдущего родителя. Spatial может иметь только одного родителя. В Spatial может быть несколько потомков.

Если вы считаете, что вам нужно лучше понять концепцию Графа Сцены, сначала прочитайте Scenegraph для чайников.

Сравнение Узла и геометрии

В вашем Java-коде Spatial является либо экземпляром com.jme3.scene.Node, либо экземпляром com.jme3.scene.Geometry. Вы используете два типа Spatial для разных целей:

scene-graph

  com.jme3.scene.Spatial
Цель:  Spatial — это абстрактная структура данных, в которой хранятся пользовательские данные и преобразования (=перемещение, поворот, масштабирование) элементов графа 3D-сцены. Spatial могут быть сохранены и загружены с помощью Asset Manager.
  com.jme3.scene.Geometry com.jme3.scene.Node
Видимость:  Geometry(Геометрия) представляет собой видимый 3D-объект в графе сцены. Node(Узел) является невидимым «рычагом» управляющим группой Spatial в графе сцены.
Цель:  Используйте Geometries для представления внешнего вида объекта: Каждая геометрия содержит сетку и материал полигона, определяющие ее форму, цвет, текстуру и непрозрачность/прозрачность.
Вы прикрепляете Geometries к узлам.
Используйте узлы для структурирования и группировки геометрий и других узлов. Каждый узел привязан к одному родительскому узлу, и каждый узел может иметь ноль или более дочерних узлов (узлов или геометрий), прикрепленных к самому себе.
Когда вы преобразуете (перемещаете, поворачиваете и.т.д.) родительский узел, все его потомки преобразуются (перемещаются, вращаются и.т.д.).
Содержание:  Преобразования; настроенные данные пользователя;
Сетка и материал;
Преобразования; настроенные данные пользователя;
Нет сетки, нет материала.
Примеры:  Куб, сфера, игрок, здание, ландшафт, транспортное средство, ракеты, персонажи и.т.д. RootNode, guiNode, audioNode, пользовательский узел(Node) группировки, такой как vehicleNode или shipNode с прикрепленными пассажирами и.т.д.
Вы никогда не должны пытаться создавать Spatial объект так Spatial s = new Spatial();! Пространство — это абстрактное понятие, как млекопитающее (здесь нет никакого реального существа, называемого «млекопитающим»). Вы создаете экземпляр com.jme3.scene.Node или com.jme3.scene.Geometry. Однако некоторым методам в качестве аргумента требуется Spatial тип: это связано с тем, что они могут принимать в качестве аргументов оба варианта узел и геометрию. В этом случае вы просто передаете Node или Geometry в качестве Spatial.

Сетки

Многоугольная Сетка внутри Геометрии может быть одной из трех вещей:

  • Фигуры(Shapes): Простейший тип Meshes(сеток) — это стандартные фигуры jME, такие как кубы и сферы. Вы можете использовать несколько Shapes для построения сложных геометрий. Shapes встроены и могут быть созданы без использования AssetManager.
  • 3D-модели: 3D-модели и сцены также состоят из сеток, но являются более сложными, чем Shapes. Вы создаете Model и Сцены в внешних редакторах 3D-сеток и экспортируете их как Ogre XML или Wavefront OBJ. Используйте Asset Manager для загрузки моделей в свою игру jME3.
  • Пользовательские Mesh(Сетки): продвинутые пользователи могут создавать Пользовательские Mesh программным способом.

Что такое Clone?

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

Второй вариант использования: Когда вы загружаете модель с помощью loadModel() из AssetManager, вы можете автоматически получить объект clone(). В частности:

  • Если модель не анимирована (у нее нет AnimControl), jME загружает клон. Все клоны используют один mesh объект, чтобы использовать меньше памяти.
  • Если модель анимирована (у нее есть AnimControl), то loadModel() дублирует сетку для каждого загруженного экземпляра. (Использует больше памяти, но может анимировать.)

Обычно нет необходимости вручную использовать как-либо метод clone() на моделях. Использование метода loadModel() Asset Manager автоматически сделает все как надо для ваших моделей.

«Box миры состоящие из статических клонированных Box() фигур, будут все равно слишком медленным для больших миров. Чтобы научиться создавать быстрые миры, ищите в Интернете методики вокселизации.

Как добавлять поля и методы в Spatial

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

Вы хотите добавить пользовательские методы доступа к Spatial? Не расширяйте Node или Geometry, вместо этого используйте Пользовательские Control. Вы хотите добавить настраиваемые поля в Spatial? Не расширяйте Node или Geometry, вместо этого используйте встроенный метод setUserData(). Везде где вы можете обращается к Spatial вы можете легко получить доступ к полям объекта (User Data) и методам доступа (методы control) таким образом.

В этом первом примере добавляется целочисленное поле с именем health в Spatial playerNode, и оно инициализируется до 100.

playerNode.setUserData("health", 100);

Второй пример добавляет набор пользовательских методов доступа к объекту игрока. Вы создаете пользовательский класс PlayerControl() и добавляете этот control в Spatial:

playerNode.addControl(new PlayerControl());

В классе PlayerControl() вы определяете настраиваемые методы, которые задают и получают ваши пользовательские данные в spatial объекте. Например элемент Control может добавить методов доступа, которые задают и получают здоровье игрока:

public int getHealth() {
  return (Integer)spatial.getUserData("health");
}
public void setHealth(int h) {
  spatial.setUserData("health",h);
}

Вы можете получить доступ к этим данным, везде где у вас есть доступ к этой Spatial playerNode.

health = playerNode.getControl(PlayerControl.class).getHealth();
...
playerNode.getControl(PlayerControl.class).setHealth(99);
  • Вы можете добавить столько объектов данных (типов String, Boolean, Integer, Float, Array) в Spatial, сколько вы хотите. Просто указывая их уникальными строками, чувствительными к регистру (health, Inventory, equipment, и.т.д.(здоровье, инвентарь, оборудование)).
  • Сохраняемые данные могут даже быть настраиваемым объектом Java, если вы создадите пользовательский Java-класс для реализации интерфейса Savable!
  • Когда вы сохраняете Spatial как .j3o-файл, пользовательские данные также сохраняются, и все Savable восстанавливаются при следующей загрузке .j3o!

Вот как вы указываете все ключевые данные, которые уже определены для конкретного Spatial:

for(String key : spatial.getUserDataKeys()){
    System.out.println(spatial.getName()+"'s keys: "+key);
}

Как получить доступ к именованной под-сетке

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

  1. Откройте модель в 3D-редакторе сетки или в JMonkeyEngine SDK Scene Composer.
  2. Определите существующие имена под-сеток в модели.
  3. При необходимости присвойте уникальные имена под-сеткам в модели.

В следующем примере Узел house(дом) является загруженной моделью. Под-сетки в Узле называются его дочерними узлами. Строка, door 12(дверь 12), здесь это имя сетки, которую вы ищете.

Geometry submesh = (Geometry) houseScene.getChild("door 12");

Что такое Culling(отсечение)?

Есть два типа отсечения: Отсечение по направлению нормали(Face culling) и отсечение по пирамиде видимости(view frustrum culling).

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

Использование: «Внутренняя часть сетки (так называемая задняя поверхность) обычно не видна игроку, а в качестве оптимизации режим Back пропускает вычисление всех задних поверхностей по умолчанию. Активация режимов Off или Front может быть полезна когда вы отлаживаете пользовательские сетки с целю определить случайные полигоны с вывернутыми нормалями.

Вы можете переключить com.jme3.material.RenderState.FaceCullMode на:

  • FaceCullMode.Back (по умолчанию) — рисуются только фронтовые стороны сетки. Отсечение Backface — это поведение по умолчанию.
  • FaceCullMode.Front — рисуются только обратные стороны сетки. Сетка с отсечением по направлению нормали, скорее всего, будет невидимой. Используется для отладки «встроенных пользовательских сеток».
  • FaceCullMode.FrontAndBack — Используйте это, чтобы сделать сетку временно невидимой.
  • FaceCullMode.Off — рисуется каждая сторона сетки. Выглядит нормально, но замедляет большие сцены.

Пример:

material.getAdditionalRenderState().setFaceCullMode(FaceCullMode.FrontAndBack);

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

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

  • CullHint.Dynamic — по умолчанию, быстрее, потому что он не тратит время на объекты, которые находятся вне зоны видимости.
  • CullHint.Never — вычислять и рисовать все всегда (даже если оно не попадает на экран пользователя, потому что оно скрыто). Медленнее, но может использоваться при отладке пользовательских сеток.
  • CullHint.Always — все пространство забито и не видно. Быстрый способ временно скрыть Spatial. Скрыть Spatial быстрее, чем его отсоединение, но используется больше памяти.
  • CullHint.Inherit — наследует поведение отсечения из родительского узла.

Пример:

spatial.setCullHint(CullHint.Never); // всегда рисуется

Смотрите также

  • Оптимизация — класс GeometryBatchFactory объединяет несколько геометрий в сетки с собственной текстурой у каждой.
  • Траверс SceneGraph — Найдите любой узел или геометрию в scenegraph.

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Добавить комментарий

jMonkeyEngine.ru © 2017. Все права сохранены.