

= jMonkeyEngine 3 Урок (3) - Знакомство с ресурсами

Предыдущий: <<документация/jme3_ru/начальная/знакомство_с_узлами#,Знакомство с узлами>>,
Следующий: <<документация/jme3_ru/начальная/знакомство_с_основным_циклом_обработки_событий#,Знакомство с циклом обновления>>,
Английская версия: <<jme3/beginner/hello_asset#,Hello Assets>>


В этом уроке мы научимся загружать 3D-модели и текст в граф сцены, используя jME <<jme3/advanced/asset_manager#,Asset Manager>>. Вы также узнаете, как правильно  определить пути, и какие форматы использовать.



image::jme3/beginner/beginner-assets-models.png[beginner-assets-models.png,with="320",height="250",align="center"]



<<sdk_ru/sample_code#,Проблема нахождения файлов, чтобы запустить этот образец?>>`jME3-testdata.jar`““““



== Пример Кода

[source,java]

----

package jme3test.helloworld;

import com.jme3.app.SimpleApplication;
import com.jme3.font.BitmapText;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;

/** Пример 3 - как загрузить модель OBJ и OgreXML модель, 
 * материал / текстуру, или текст. */
public class HelloAssets extends SimpleApplication {

    public static void main(String[] args) {
        HelloAssets app = new HelloAssets();
        app.start();
    }

    @Override
    public void simpleInitApp() {

        Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");
        Material mat_default = new Material( 
            assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
        teapot.setMaterial(mat_default);
        rootNode.attachChild(teapot);

        // Создадим стену с простой текстурой test_data
        Box box = new Box(2.5f,2.5f,1.0f);
        Spatial wall = new Geometry("Box", box );
        Material mat_brick = new Material( 
            assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat_brick.setTexture("ColorMap", 
            assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
        wall.setMaterial(mat_brick);
        wall.setLocalTranslation(2.0f,-2.5f,0.0f);
        rootNode.attachChild(wall);

        // Отображение строки текста шрифтом по умолчанию
        guiNode.detachAllChildren();
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText helloText = new BitmapText(guiFont, false);
        helloText.setSize(guiFont.getCharSet().getRenderedSize());
        helloText.setText("Hello World");
        helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
        guiNode.attachChild(helloText);

        // Загрузка модели из test_data (OgreXML + material + texture)
        Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
        ninja.scale(0.05f, 0.05f, 0.05f);
        ninja.rotate(0.0f, -3.0f, 0.0f);
        ninja.setLocalTranslation(0.0f, -5.0f, -2.0f);
        rootNode.attachChild(ninja);
        // Вы должны добавить света, чтобы сделать модель видимой
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f));
        rootNode.addLight(sun);

    }
}
----

Написав и запустив кода из примера. Вы должны увидеть зеленый ниндзя рядом с разноцветным чайником, стоящего за стеной. Текст на экране должен сказать “Hello World.



== Менеджер ресурсов

*Под игровыми ресурсами(asset), мы имеем в виду все мультимедийные файлы, такие как модели, материалы, текстуры, целые сцены, пользовательские шейдеры, музыку и звуковые файлы, и пользовательские шрифты.* JME3 поставляется с удобным объектом AssetManager, который помогает вам получить доступ к вашим ресурсам. 
В AssetManager можно загружать файлы из:


*  нынешнего пути к классу (на верхнем уровне папки проекта), 
*  `assets` в каталоге проекта, и
*  дополнительные пользовательские пути, которые вы регистрируете.

Ниже приводится Рекомендуемая структура папок для хранения ресурсов в папках проекта: 


[source]

----

MyGame/assets/               
MyGame/assets/Interface/
MyGame/assets/MatDefs/
MyGame/assets/Materials/
MyGame/assets/Models/       <-- ваш .j3o models идет сюда
MyGame/assets/Scenes/
MyGame/assets/Shaders/
MyGame/assets/Sounds/       <-- ваш audio files идет сюда
MyGame/assets/Textures/     <-- ваш textures идет сюда
MyGame/build.xml            <-- По умолчанию собирается Ant script
MyGame/src/...              <-- ваш Java sources идет сюда
MyGame/...

----

Это просто предложение лучшего решения, и это то, что вы получаете по умолчанию при создании нового Java проекта в jMokeyEngine <<документация/sdk_ru#,sdk_ru>>.  Технически вы можете сделать имя папки`assets` и имен подпапок какими хотите.



=== Загрузка Текстур

Место текстуры в подкаталоге “assets/Textures/. Загрузите текстуру в Материала, прежде чем установить Материал. В следующем примере кода в методе `simpleInitApp()` загружает пример простой модели на стену:


[source,java]

----

// Создать стену с простой текстурой от test_data
Box box = new Box(2.5f,2.5f,1.0f);
Spatial wall = new Geometry("Box", box );
Material mat_brick = new Material( 
    assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat_brick.setTexture("ColorMap", 
    assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
wall.setMaterial(mat_brick);
wall.setLocalTranslation(2.0f,-2.5f,0.0f);
rootNode.attachChild(wall);

----

В этом случае вы <<документация/jme3_ru/начальная/знакомство_с_материалом#,создайте свой собственный Материал>> и применить его к Геометрии. Ваш основной материал, и материал по умолчанию описывается (например “Unshaded.j3md), как показано в этом примере. 



=== Загрузка текста и шрифтов

Этот пример выводит на экран текст “Hello World в качестве шрифта по умолчанию в нижней части окна. Вы прикрепляете текст к “guiNode – это специальный узел для плоских (ортогональных) элементов дисплея. Вы отображаете текст, чтобы показать, очки, здоровья игрока и др.
Следующий пример кода находится в методе ` simpleInitApp () `.


[source,java]

----
// Текста с шрифта отображается по умолчанию
guiNode.detachAllChildren();
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
BitmapText helloText = new BitmapText(guiFont, false);
helloText.setSize(guiFont.getCharSet().getRenderedSize());
helloText.setText("Hello World");
helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
guiNode.attachChild(helloText);

----

*Совет:* Удаляйте текст в guiNode путем отсоединения всех ее потомков.



=== Загрузка модели

Экспортируйте 3D-модели в формате OgreXML (.mesh.xml, .scene, .material, .skeleton.xml) и помещайте их в подкаталог `assets/Models/`. Следующий пример кода находится в методе ` simpleInitApp () `.


[source,java]

----

// Загрузка модели из test_data (OgreXML + material + texture)
Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
ninja.scale(0.05f, 0.05f, 0.05f);
ninja.rotate(0.0f, -3.0f, 0.0f);
ninja.setLocalTranslation(0.0f, -5.0f, -2.0f);
rootNode.attachChild(ninja);
// Необходимо добавить направленного света, чтобы сделать модель видимой!
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
rootNode.addLight(sun);

----

Обратите внимание, что вам не нужно, создавать Материал, если вы экспортировали модель с материалом. Запомните, что нужно добавлять источник света, как показано на рисунке, иначе материал (и вся модель) не видны!



=== Загрузка Ресурсов из Пользовательского Пути

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


Вот пример использования в ZipLocator зарегистрированного в файл `town.zip` в верхнем уровне папки вашего проекта


[source,java]

----

    assetManager.registerLocator("town.zip", ZipLocator.class);
    Spatial scene = assetManager.loadModel("main.scene");
    rootNode.attachChild(scene);

----

Вот HttpZipLocator он может загружать модели из ZIP-архивов:


[source,java]

----

    assetManager.registerLocator(
      "http://jmonkeyengine.googlecode.com/files/wildhouse.zip", 
      HttpZipLocator.class);
    Spatial scene = assetManager.loadModel("main.scene");
    rootNode.attachChild(scene);

----

JME3 предлагает ClasspathLocator, ZipLocator, FileLocator, HttpZipLocator, и UrlLocator (смотрите `com.jme3.asset.plugins`). 



== Создание Моделей и Сцен

Для создания 3D-моделей и сцен, вам нужен 3D Mesh Editor. Если у вас нет каких-либо инструментов, установить Blender и плагин OgreXML Exporter
Тогда вы сможете link:http://en.wikibooks.org/wiki/Blender_3D:_Noob_to_Pro/UV_Map_Basics[создать полностью текстурированные модели (например, Blender)] и экспортировать их в ваш проект.
Затем вы используете <<документация/sdk_ru#,sdk_ru>> to <<документация/sdk_ru/model_loader_and_viewer#,load models>>, <<документация/sdk_ru/blender#,convert models>>, и <<документация/sdk_ru/scene_composer#,create 3D scenes>> от них. 


*Пример:* Из Blender, экспортировать свои модели в виде Ogre XML сеток с материалами следующим образом:


.  Откройте меню File &gt; Export &gt; OgreXML Exporter что бы открыть диалоговое окно экспорта.
.  In the Export Materials field: Give the material the same name as the model. For example, the model `something.mesh.xml` goes with `something.material`, plus (optionally) `something.skeleton.xml` and some JPG texture files.
.  In the Export Meshes field: Select a subdirectory of your `assets/Models/` directory. E.g. `assets/Models/something/`.
.  Activate the following exporter settings: 
**  Copy Textures: YES
**  Rendering Materials: YES
**  Flip Axis: YES
**  Require Materials: YES
**  Skeleton name follows mesh: YES

.  Click export.


=== Модель Форматы Файлов

JME3 можете преобразовать и загрузить


*  Ogre XML models + materials, 
*  Ogre DotScenes, 
*  Wavefront OBJ + MTL models, 
*  .Blend файлы.

Метод `loadModel()` загружает файлы определенного формата при запуске вашего кода непосредственно из SDK. Однако если вы откомпилируете в исполняемый файл то по умолчанию в скрипт сборки, оригинальные модели файлов (XML, OBJ и т.д.) _не включены_. Это означает, когда вы запустите исполняемый файл вне SDK, при загрузке любых оригинальных моделей напрямую, вы получите следующее сообщение об ошибке:


[source]

----
com.jme3.asset.DesktopAssetManager loadAsset
WARNING: Cannot locate resource: Models/Ninja/Ninja.mesh.xml
com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.NullPointerException

----

Вы можете увидите, что загрузка *XML/OBJ/Blend файлов*  приемлема только на этапе разработки в SDK. Например, каждый раз, когда ваш дизайнер обновляет файлы в каталоге ресурсов, вы можете быстро просмотреть последнюю версию в вашей среде разработки.


Но для теста на качество сборки и для релиза, используйте исключительно *.j3o файлы* . J3o-это оптимизированный двоичный формат для jME3 приложений. Когда вы делаете QA test, или готовитесь к релизу, используйте <<документация/sdk_ru#,sdk_ru>> чтобы <<документация/sdk_ru/model_loader_and_viewer#,преобразовать>> все .obj/.scene/.xml/.blend файлы в .j3o файлы, обновите весь код, чтобы загружал .j3o файлы. Скрипт сборки по умолчанию автоматически упаковывает .j3o файлы в исполняемые файлы.


Откройте ваш JME3 проекта в jMonkeyEngine SDK.


.  Щелкните правой кнопкой мыши .Blend .OBJ, или .mesh.xml файла в окне Projects window, и выбрать “convert to JME3 binary. 
.  В .j3o файл появится рядом с .mesh.xml файлом и имеет то же имя.
.  Обновить все ваши `loadModel()` строки соответственно. Например: 
[source,java]

----
Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.j3o");
----


““



=== Загрузка Моделей и Сцен
[cols="2", options="header"]
|===

a| Задача? 
a| Решение! 

a| Загрузка модели с материалами 
a| Используйте менеджер ресурсов, метод `loadModel()` и прикрепите Spatial к rootNode. 
[source,java]

----
Spatial elephant = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
rootNode.attachChild(elephant);
----

[source,java]

----
Spatial elephant = assetManager.loadModel("Models/Elephant/Elephant.j3o");
rootNode.attachChild(elephant);
----


a| Загрузить модель без материалов 
a| Если у вас есть модель без материалы, вы должны дать ей материал, чтобы сделать её видимой. 
[source,java]

----
Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.j3o");
Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); // материал по умолчанию
teapot.setMaterial(mat);
rootNode.attachChild(teapot);
----


a| Загрузить сцену 
a| Загружайте сцену так же, как вы загружаете модели: 
[source,java]

----
Spatial scene = assetManager.loadModel("Scenes/town/main.scene");
rootNode.attachChild(scene);
----

[source,java]

----
Spatial scene = assetManager.loadModel("Scenes/town/main.j3o");
rootNode.attachChild(scene);
----


|===


== Упражнение - Как правильно загружать ресурсы

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


.  link:http://jmonkeyengine.googlecode.com/svn/trunk/engine/town.zip[Скачать town.zip] образец сцены. 
.  (Дополнительно:) Распаковав town.zip вы увидеть структуру, содержащую Ogre dotScene: Вы получите папку с именем `town`. Она содержит файлы XML и текстуры, и файл с названием main.scene. (Это просто для вашей информации, вам не нужно ничего делать с ней.)
.  Место town.zip файл в корневом каталоге вашего JME3 проекта, например, так: 
[source]

----
jMonkeyProjects/MyGameProject/assets/
jMonkeyProjects/MyGameProject/build.xml
jMonkeyProjects/MyGameProject/src/
jMonkeyProjects/MyGameProject/town.zip
...

----


Используйте следующий метод для загрузки модели из zip файла:


.  Проверьте ` town.zip ` в папке проекта.
.  Зарегистрируйте элемент zip файл в папке проекта: добавьте следующий код в `simpleInitApp() {`
[source,java]

----
    assetManager.registerLocator("town.zip", ZipLocator.class);
    Spatial gameLevel = assetManager.loadModel("main.scene");
    gameLevel.setLocalTranslation(0, -5.2f, 0);
    gameLevel.setLocalScale(2);
    rootNode.attachChild(gameLevel);
----

Теперь метод loadModel() ищет этот zip непосредственно для загрузки файлов. +
(Это значит, не нужно писать `loadModel(town.zip/main.scene)` или аналог!)


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

*Совет:* Если вы регистрируетесь новые элемент, убедитесь, что не получается каких-либо конфликтов имен файлов: Не называйте все сцены `main.scene` дайте каждой сцене уникальное имя.


Ранее в этом учебнике, вы загружали сцены и модели из паки ресурсов assets. Это наиболее распространенныq способом которым вы будете загружать сцены и модели. Ниже стандартная процедура:


.  Удалите код, который вы добавили в предыдущем упражнении.
.  Переместите распакованные `town/` в папку the `assets/Scenes/` папки проекта.
.  Добавьте следующий код в `simpleInitApp() {` 
[source,java]

----
    Spatial gameLevel = assetManager.loadModel("Scenes/town/main.scene");
    gameLevel.setLocalTranslation(0, -5.2f, 0);
    gameLevel.setLocalScale(2);
    rootNode.attachChild(gameLevel);
----

 Обратите внимание, что путь относительно `assets/…` папки.


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

Здесь есть третий метод, который вы должны знать, это загрузка scene/model из .j3o файла:


.  Удалить код из предыдущего упражнения.
.  Если вы этого еще не сделали, откройте <<документация/sdk_ru#,sdk_ru>> и откройте проект, содержащий HelloAsset класс.
.  В окне проектов, перейдите к `assets/Scenes/town` папке. 
.  Щелкните правой кнопкой мыши `main.scene` и конвертировать сцену в двоичный: В jMonkeyPlatform создастся main.j3o файл.
.  Добавьте следующий код в `simpleInitApp() {`
[source,java]

----
    Spatial gameLevel = assetManager.loadModel("Scenes/town/main.j3o");
    gameLevel.setLocalTranslation(0, -5.2f, 0);
    gameLevel.setLocalScale(2);
    rootNode.attachChild(gameLevel);
----

 Опять же, обратите внимание, что путь относительно папки `assets/…`.


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


== Вывод

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


Давайте добавим немного экшена в сцену и изучим <<документация/jme3_ru/начальная/знакомство_с_основным_циклом_обработки_событий#,цикл обработки событий>>!

'''

*См. также:*


*  <<jme3/external/blender#,Окончательный урок по Blender import>>
*  link:http://www.jmonkeyengine.com/forum/index.php?topic=14418.0[Скриншоты большой загруженной модели]
*  link:http://www.youtube.com/user/aramakara[Видео-уроки по получению OgreXML в 3DS Max используя OgreMax]
*  Если вы хотите узнать, как загрузить звуки, см. <<документация/jme3_ru/начальная/знакомство_со_звуком#,Знакомство со Звуком>>
*  Если вы хотите узнать больше о загрузке текстур и материалов, см. <<документация/jme3_ru/начальная/знакомство_с_материалом#,Знакомство с Материалом>>
<tags><tag target="beginner" /><tag target="intro" /><tag target="documentation" /><tag target="lightnode" /><tag target="material" /><tag target="model" /><tag target="node" /><tag target="gui" /><tag target="hud" /><tag target="texture" /></tags>
