Tutorial 3 - Hello Assets

jMonkeyEngine 3 Tutorial (3) - Hello Assets

Anterior: Hello Node, Próximo: Hello Update Loop

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

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

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 de 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:

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 <— script de construção Ant
MyGame/src/… <— fontes Java vão aqui
MyGame/…

Isto é apenas um melhor prática sugerida, e é o que você consegue por padrão quando criando um novo projeto Java no 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:

// Crie uma parede com uma textura simples de 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ê 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 GUI (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().

// Exibe uma linha de texto com uma fonte padrão
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 GUI (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().

// Carrega um modelo de test_data (OgreXML + material + textura)
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);
// Você deve adicionar uma luz direcional para fazer o modelo visível!
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:

    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:
    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 (see 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 criar modelos completamente texturizados com Blender. Você pode usar o SDK para carregar modelos, converter modelos e criar cenas deles.

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

  1. Abra o menu Arquivo (File) > Exportar (Export) > Exportador OgreXML (OgreXML Exporter) para abrir o diálogo do exportador.
  2. 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.
  3. No campo Exportar Malhas (Export Meshes): Selecione um subdiretório de seu diretório assets/Models/ directory. E.g. assets/Models/something/.
  4. Ayive 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
  5. 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:

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 para converter todos os arquivos .obj/.scene/.xml/.blend para .j3o, e somente carregue as versões .j3o.

  1. Abra seu Projeto JME3 no SDK da jMonkeyEngine.
    1. 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").
    2. O arquivo .j3o aparece próximo ao arquivo .mesh.xml file e tem o mesmo nome.
    3. Mude todas as linhas do seu loadModel() de acordo. Por exemplo:
    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

Tarefa? Solução
Carregar um modelo com materiais
Spatial elephant = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
rootNode.attachChild(elephant);

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

carregar um modelo com materiais

[code]
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);
[/code]

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

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.

  1. baixe a cena de amostra town.zip.
  2. (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.)
  3. Coloque o arquivo town.zip no diretório topo de nível de seu projeto JME3, assim:

> jMonkeyProjects/MyGameProject/assets/
> MonkeyProjects/MyGameProject/build.xml
> jMonkeyProjects/MyGameProject/src/
> jMonkeyProjects/MyGameProject/town.zip
> …

  1. Use o seguinte método para carregar modelos de um arquivo zip:
    1. Verifique se town.zip está no diretório do projeto.
    2. Registre um localizador de arquivo zip para o diretório do projeto: Adicione o seguinte código sobre simpleInitApp() {

[code]
assetManager.registerLocator("town.zip", ZipLocator.class);
Spatial gameLevel = assetManager.loadModel("main.scene");
gameLevel.setLocalTranslation(0, -5.2f, 0);
gameLevel.setLocalScale(2);
rootNode.attachChild(gameLevel);
[/code]
# 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!)

  1. Limpe, construa e execute o projeto.
  2. 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:

  1. Remova o código que você adicionou para o exercício anterior.
  2. Mova o diretório dezipado town/ no diretório assets/Scenes/ de seu projeto.
  3. Adicione o seguinte código sobre simpleInitApp() {

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

  1. Note que o caminho é relativo ao diretório assets/…
  2. 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:

  1. Remova o código do exercício anterior.
  2. Se você j´pa não fez, abra o SDK e abra o projeto que contém a classe HelloAsset.
  3. Na janela de projetos, navegue para o diretório assets/Scenes/town.
  4. 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.
  5. Adicione o seguinte código em simpleInitApp() {

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

  1. Novamente, note que o caminho é relativo ao diretório assets/…
  2. Limpe, construa e execute o projeto.
  3. 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 Loop de Atualização!

Veja também:

  • O tutorial de importação do Blender definitivo
  • instantâneos de um modelo grande carregado
  • Tutoriais de vídeo para conseguir OgreXML do 3DS Max usando OgreMax
  • Se você quiser aprender a carregar sons, veja Hello Audio
  • Se você quer aprender mais sobre carregar texturas e materiais, veja Hello Material
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.