= jMonkeyEngine 3 Tutorial (3) - Hello Assets
:author:
:revnumber:
:revdate: 2016/03/17 20:48
:keywords: beginner, intro, documentation, lightnode, material, model, node, gui, hud, texture
:relfileprefix: ../../
:imagesdir: ../..
ifdef::env-github,env-browser[:outfilesuffix: .adoc]


Anterior: <<jme3/beginner/hello_node_pt#, Hello Node pt>>,
Próximo: <<jme3/beginner/hello_main_event_loop_pt#, Hello Update Loop pt>>

Neste tutorial nós aprenderemos a carregar modelos 3D e colcoar texto no grafo de cena, usando o <<jme3/advanced/asset_manager#, Gerenciador de Ativo (Asset Manager)>> da JME. Você também aprenderá como determinar os caminhos corretos, e quais formatos de arquivo usar.


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



[TIP]
====
<<sdk/sample_code#, Problema no achar os arquivos para executar a amostra?>> Para conseguir os ativos (modelos 3D), adicione o arquivo `jme3-test-data.jar` incluso para seu classpath. no projeto criado com o SDK da jMonkeyEngine (recomendado), simplesmente dê um clique com o botão direito em seu projeto, escolha “Propriedades (“Properties), vá para “Bibliotecas (“Libraries), pressione “Adicionar Biblioteca (“Add Library) e adiciona a biblioteca pré-configurada “jme3-test-data library.
====



== Amostra de Código

[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;

/** Sample 3 - how to load an OBJ model, and OgreXML model,
 * a material/texture, or text. */
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);

        // Create a wall with a simple texture from test_data
        Box box = new Box(Vector3f.ZERO, 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);

        // Display a line of text with a default font
        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);

        // Load a model from 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);
        // You must add a light to make the model visible
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f));
        rootNode.addLight(sun);

    }
}
----

Compile e execute a amostra de código. Você deveria ver um ninja verde com um bule colorido permanecendo atrás de uma parede. O texto na tela deveria dizer “Hello World.


== O gerenciador de ativo

*Por ativos de jogo nós queremos dizer todos os arquivos multimídia, tais como modelos, materiais e texturas, cenas inteiras, shaders customizados, música e arquivos de som, e fontes customizadas.* JME3 vem com um objeto AssetManager prático que ajuda você a acessar seus ativos.
O AssetManager pode carregar arquivos de:

*  O classpath atual (o nível do topo de seu diretório de projeto),
*  O diretório `ativos` de seu projeto, e
*  opcionalmente, caminhos persoanlizados que você registrar.

O seguinte é a estrutura de diretório recomendada em seu diretório de projeto:

[source]
----

MyGame/assets/Interface/
MyGame/assets/MatDefs/
MyGame/assets/Materials/
MyGame/assets/Models/
MyGame/assets/Scenes/
MyGame/assets/Shaders/
MyGame/assets/Sounds/
MyGame/assets/Textures/
MyGame/build.xml            <-- Ant build script
MyGame/src/...              <-- Java sources go here
MyGame/...

----

Isto é apenas um melhor prática sugerida, e é o que você consegue por padrão quando criando um novo projeto Java no <<jme3/beginner/sdk#,SDK>> da jMokeyEngine. Você pode criar um diretório de ativos e tecnicamente nomear os subdiretórios da maneira que você gostar.


=== Carregando Texturas

Coloque suas texturas em um subdiretório de `assets/Textures/`. Carregue a textura em um material antes que você configure o Material. A seguinte amostra de código é do método `simpleInitApp()` e carrega um modelo de parede simples:

[source,java]
----

// Create a wall with a simple texture from test_data
Box box = new Box(Vector3f.ZERO, 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);

----

Neste caso, você <<jme3/beginner/hello_material#,cria seu próprio Material>> e aplica ele para a geometria (Geometry). Você baseia Materiais nas descrições de material padrão (por exemplo, “Unshaded.j3md), como mostrado neste exemplo.


=== Carregando Texto e Fontes

Este exemplo exibe o texto “Hello World na fonte padrão na aresta do fundo da janela. Você anexa texto para o nó da +++<abbr title="Graphical User Interface">GUI</abbr>+++ (`guiNode`) – isto é um nó especial para elementos de exibição plana (ortogonal). Você exibe texto para mostrar a pontuação do jogo, a saúde do jogador, etc.
A seguinte amostra de código vai no método `simpleInitApp()`.

[source,java]
----
// Display a line of text with a default font
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);

----

*Dica:* Limpe o texto existente no nó da +++<abbr title="Graphical User Interface">GUI</abbr>+++ (guiNode) por retirar todas as suas crianças.


=== Carregando um modelo

Exporte seu modelo 3D no formato OgreXML (.mesh.xml, .scene, .material, .skeleton.xml) e coloque ele em um subdiretório de `assets/Models/`. A seguinte amostra de código vai no método `simpleInitApp()`.

[source,java]
----

// Load a model from 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);
// You must add a directional light to make the model visible!
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
rootNode.addLight(sun);

----

Note que você precisa criar um Material se você exportou o modelo com um material. Lembre-se de adicionar uma fonte de luz, como mostrado, de outra maneira o material (e o modelo inteiro) não estará visível!


=== Carregando Ativos de Caminhos Personalizados

E seu jogo dependen de arquivos de modelo fornecidos pelo usuário, que não estão inclusos na distribuição? Se um arquivo não é localizado no local padrão (e.g. diretório de ativos), você pode registrar um localizador (Locator) customizado e carregá-lo de qualquer caminho.

Aqui está um exemplo de uso de um ZipLocator que está registrado para um arquivo `town.zip` no nível topo de seu diretório de projeto:

[source,java]
----

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

----

 Aque está um HttpZipLocator que pode baixar modelos zipados e carregá-los:

[source,java]
----

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

----

JME3 oferece ClasspathLocator, ZipLocator, FileLocator, HttpZipLocator, e UrlLocator (Veja `com.jme3.asset.plugins`).


== Criando Modelos e Cenas

Para criar modelos 3D e cenas, você precisa de um editor de malha 3D (3D Mesh Editor) com um plugin exportador (Exporter) OgreXML. Por exemplo, você pode link:http://en.wikibooks.org/wiki/Blender_3D:_Noob_to_Pro/UV_Map_Basics[ criar modelos completamente texturizados com Blender].

Você pode usar o <<sdk#,SDK>> para <<sdk/model_loader_and_viewer#,carregar modelos>>, <<sdk/blender#, converter modelos>> e <<sdk/scene_composer#, criar cenas>> deles.

Se você usar Blender, exporte seus modelos como malhas Ogre XML com materiais como se segue:

.  Abra o menu Arquivo (File) &gt; Exportar (Export) &gt; Exportador OgreXML (OgreXML Exporter) para abrir o diálogo do exportador.
.  No campo Exportar Materiais (Export Materials): Dê ao material o mesmo nome que o modelo. Por exemplo, o modelo `something.mesh.xml` acompanha `something.material`, mais (opcionalmente) `something.skeleton.xml` e alguns arquivos de textura JPG.
.  No campo Exportar Malhas (Export Meshes): Selecione um subdiretório de seu diretório `assets/Models/` directory. E.g. `assets/Models/something/`.
.  Ative as seguintes configurações do exportador:
**  Copiar Texturas (Copy Textures): YES
**  Renderizar materiais (Rendering Materials): YES
**  Virar Eixos (Flip Axis): YES
**  Requer Materiais (Require Materials): YES
**  Nome do Esqueleto segue o da malha (Skeleton name follows mesh): YES

.  Clique em exportar.


=== Formatos de Arquivo de Modelo

JME3 pode carregar modelos Ogre XML + materials, Ogre DotScenes, bem como modelos Wavefront OBJ+MTL models. O código loadModel() trabalha com estes arquivos quando você executa o código diretamente do SDK da jMonkeyEngine SDK.

Se você construir os executáveis usando o scrit de construção padrão, então os arquivos de modelo originais (XML, OBJ, etc) não são inclusos. Quando você executar o executável, você obetrá uma mensagem de erro se você tentar carregar quaisquer modelos diretamente:

[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

----

Carregando os arquivos XML/OBJ diretamente é somente aceitável durante a fase de desenvolvimento. Se seus projetista gráfico coloca arquivos atualizados para o diretório de ativos, você pode rapidamente revisar a versão mais recente em seu ambiente de desenvolvimento.

Para teste e para a construção de liberação final, voc~e usa arquivos .j3o exclusivamente. J3o é um formato binário otimizado para aplicações jME3, e arquivos .j3o são automaticamente inclusos no arquivo JAR distribuível pelo script de construção. Quando você faz construções de teste de QA (Quality and Assurance - Averiguação da Qualidade) ou está pronto para liberar, use o <<sdk#,SDK>> para <<sdk/model_loader_and_viewer#, converter>> todos os arquivos .obj/.scene/.xml/.blend para .j3o, e somente carregue as versões .j3o.

Abra seu Projeto JME3 no SDK da jMonkeyEngine.

.  Dê um clique com o botão direito em um arquivo .Blend, .OBJ, ou .mesh.xml file na janela Projetos (Projects), e escolha “converter para binário JME3 (“convert to JME3 binary)..
.  O arquivo .j3o aparece próximo ao arquivo .mesh.xml file e tem o mesmo nome.
.  Mude todas as linhas do seu loadModel() de acordo. Por exemplo:
[source,java]
----
Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.j3o");
----


Se seu executável dá uma exceção em tempo de execução, tenha certeza de que você converteu todos os modelos para .j3o!


=== Carregando Modelos e a Cena
[cols="2", options="header"]
|===

a| tarefa?
a| Solução!

a| Carregar um modelo com materiais
a| Use o método `loadModel()` do gerenciador de ativo (asset manager) e anexe o Spatial para o nó raiz (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| carregar um modelo sem materiais
a| Se você tiver um modelo sem materiais, você tem de dár a ele um material para fazê-lo visível.
[source,java]
----
Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.j3o");
Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); // default material
teapot.setMaterial(mat);
rootNode.attachChild(teapot);
----


a| Carregar uma cena
a| Você carrega cenas da mesma forma que você carrega modelos:
[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);
----


|===


== Exercício - Como Carregar Ativos

Como um exercício, vamos tentar diferentes maneiras de carregar uma cena. Você aprenderá a como carregar a cena diretamente, ou de um arquivo zip.

.  link:http://jmonkeyengine.googlecode.com/svn/trunk/engine/town.zip[baixe a cena de amostra town.zip].
.  (Opcional:) Dezipe o arquivo town.zip para ver a estrutura da Ogre dotScene contida: Você terá um diretório chamado `town`. Ele contém arquivos XML e textura, e o arquivo chamado main.scene. (Isto é apenas para sua informação, você não precisa fazer nada com ele.)
.  Coloque o arquivo town.zip no diretório topo de nível de seu projeto JME3, assim:
[source]
----
jMonkeyProjects/MyGameProject/assets/
jMonkeyProjects/MyGameProject/build.xml
jMonkeyProjects/MyGameProject/src/
jMonkeyProjects/MyGameProject/town.zip
...

----


Use o seguinte método para carregar modelos de um arquivo zip:

.  Verifique se `town.zip` está no diretório do projeto.
.  Registre um localizador de arquivo zip para o diretório do projeto: Adicione o seguinte código sobre `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);
----

O método loadModel() agora pesquisa pelo arquivo zip diretamente para carregar os arquivos (isto significa, não escreva `loadModel(town.zip/main.scene)` ou similar!)

.  Limpe, construa e execute o projeto. +Você deveria agora ver o Ninja+parede+bule permanecendo em uma cidade.

*Dica:*  se você registrar novos localizadores, tenha certeza de que você não tenha quaisquer conflitos de nome: Não nomeie todas as cenas `main.scene` mas dê a cada cena um nome único.

Anteriormente neste tutorial, você carregou cenas e modelos do diretório de ativo. Isto é a maneira mais comum que você estará carregando cenas e modelos. Aqui está o procedimento típico:

.  Remova o código que você adicionou para o exercício anterior.
.  Mova o diretório dezipado `town/` no diretório `assets/Scenes/` de seu projeto.
.  Adicione o seguinte código sobre `simpleInitApp() {`
[source,java]
----
    Spatial gameLevel = assetManager.loadModel("Scenes/town/main.scene");
    gameLevel.setLocalTranslation(0, -5.2f, 0);
    gameLevel.setLocalScale(2);
    rootNode.attachChild(gameLevel);
----

 Note que o caminho é relativo ao diretório `assets/…`.

.  Limpe, construa e execute o projeto. De novo, você deveria ver o Ninja+parede+bule em uma cidade.

Aqui está um terceiro método que você deve conhecer, carregando uma cena/modelo de um arquivo .j3o:

.  Remova o código do exercício anterior.
.  Se você j´pa não fez, abra o <<sdk#,SDK>> e abra o projeto que contém a classe HelloAsset..
.  Na janela de projetos, navegue para o diretório `assets/Scenes/town`.
.  Dê um clique com o botão direito em `main.scene` e converta a cena para binário: A jMonkeyPlatform gera um arquivo main.j3o.
.  Adicione o seguinte código em `simpleInitApp() {`
[source,java]
----
    Spatial gameLevel = assetManager.loadModel("Scenes/town/main.j3o");
    gameLevel.setLocalTranslation(0, -5.2f, 0);
    gameLevel.setLocalScale(2);
    rootNode.attachChild(gameLevel);
----

 Novamente, note que o caminho é relativo ao diretório `assets/…` directory.

.  Limpe, construa e execute o projeto. +De novo, você deveria ver o Ninja+parede+bule em uma cidade.


== Conclusão

Agora você sabe como popular o grafo de cena com modelos e formas estáticas, e como construir cenas. Você aprendeu como carregar ativos usando o `gerenciador de ativos (assetManager)` e você viu que os caminhos iniciam relativos ao seu diretório de projeto. Uma outra coisa importante que você aprendeu é converter modelos para o formato .j3o para os JARs executáveis etc.

Vamos adicionar alguma ação para a cena e continuar com o  <<jme3/beginner/hello_main_event_loop-pt#, Loop de Atualização pt>>!
'''

*See also:*

*  <<jme3/external/blender#,O tutorial de importação Blender definitivo>>
*  link:http://www.jmonkeyengine.com/forum/index.php?topic=14418.0[Instantâneos de um grande modelo carregado]
*  link:http://www.youtube.com/user/aramakara[Video tutoriais for obter OgreXML do 3DS Max usando OgreMax]
*  Se você quer aprender a como carregar sons, veja <<jme3/beginner/hello_audio_pt#,Hello Audio pt>>
*  Se você quer aprender mais sobre carregar materiais, veja <<jme3/beginner/hello_material_pt#,Hello Material pt>>
