Tutorial 6 - Hello Materials

jMonkeyEngine 3 Tutorial (6) - Hello Materials

Anterior: Hello Input System, Próximo: Hello Animation

O termo Material inclui tudo que influencia o que a superfície de um modelo 3D parece: A cor, a textura. o brilho, e opacidade/transparência. Coloração de uma única cor é coberta em Hello Node. Carregar modelos que vêm com materiais é coberto com Hello Asset. Neste tutorial você aprende a criar e usar Definições de Material JME3.

Para usar os ativos de exemplo em um novo projeto do SDK da jMonkeyEngine, dê um clique com o botão direito do projeto, selecione "Propriedades" ("Properties"), vá para "Bibliotecas" ("Libraries"), pressione "Adicionar Biblioteca" ("Add Library") e adicione a biblioteca "jme3-test-data".

Código de Amostra

package jme3test.helloworld;

import com.jme3.app.SimpleApplication;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Texture;
import com.jme3.util.TangentBinormalGenerator;
import com.jme3.renderer.queue.RenderQueue.Bucket;

/** Sample 6 - how to give an object's surface a material and texture.
 * How to make objects transparent, or let colors "leak" through partially
 * transparent textures. How to make bumpy and shiny surfaces.  */

public class HelloMaterial extends SimpleApplication {
  public static void main(String[] args) {
    HelloMaterial app = new HelloMaterial();
    app.start();
  }

  @Override
  public void simpleInitApp() {
    /** A simple textured cube -- in good MIP map quality. */
    Box boxshape1 = new Box(new Vector3f(-3f,1.1f,0f), 1f,1f,1f);
    Geometry cube = new Geometry("My Textured Box", boxshape1);
    Material mat_stl = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    Texture tex_ml = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
    mat_stl.setTexture("ColorMap", tex_ml);
    cube.setMaterial(mat_stl);
    rootNode.attachChild(cube);

    /** A translucent/transparent texture, similar to a window frame. */
    Box boxshape3 = new Box(new Vector3f(0f,0f,0f), 1f,1f,0.01f);
    Geometry window_frame = new Geometry("window frame", boxshape3);
    Material mat_tt = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat_tt.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
    mat_tt.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
    window_frame.setMaterial(mat_tt);

    /** Objects with transparency need to be in the render bucket for transparent objects: */
    window_frame.setQueueBucket(Bucket.Transparent);
    rootNode.attachChild(window_frame);

    /** A cube with base color "leaking" through a partially transparent texture */
    Box boxshape4 = new Box(new Vector3f(3f,-1f,0f), 1f,1f,1f);
    Geometry cube_leak = new Geometry("Leak-through color cube", boxshape4);
    Material mat_tl = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat_tl.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
    mat_tl.setColor("Color", new ColorRGBA(1f,0f,1f, 1f)); // purple
    cube_leak.setMaterial(mat_tl);
    rootNode.attachChild(cube_leak);

    /** A bumpy rock with a shiny light effect */
    Sphere rock = new Sphere(32,32, 2f);
    Geometry shiny_rock = new Geometry("Shiny rock", rock);
    rock.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres
    TangentBinormalGenerator.generate(rock);           // for lighting effect
    Material mat_lit = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
    mat_lit.setTexture("DiffuseMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"));
    mat_lit.setTexture("NormalMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
    mat_lit.setBoolean("UseMaterialColors",true);    
    mat_lit.setColor("Specular",ColorRGBA.White);
    mat_lit.setColor("Diffuse",ColorRGBA.White);
    mat_lit.setFloat("Shininess", 5f); // [1,128]    
    shiny_rock.setMaterial(mat_lit);
    shiny_rock.setLocalTranslation(0,2,-2); // Move it a bit
    shiny_rock.rotate(1.6f, 0, 0);          // Rotate it a bit
    rootNode.attachChild(shiny_rock);

    /** Must add a light to make the lit object visible! */
    DirectionalLight sun = new DirectionalLight();
    sun.setDirection(new Vector3f(1,0,-2).normalizeLocal());
    sun.setColor(ColorRGBA.White);
    rootNode.addLight(sun);
  }
}

Você deveria ver

  • Esquerda - Um cubo com uma textura de macaco marrom.
  • Meio - Uma figura de macaco translucente em frente de uma pedra brilhante.
  • Direita - Um cubo com uma textura de macaco roxa.

Mova ao redor com as teclas para dar um olhar mais próximo na translucência, e na rugosidade da pedra.

Textura não Tonalizada Simples

Tipicamente você quer dar aos objetos em suas cena texturas: Pode ser rocha, grama, tijolo, madeira, água, metal , papel… Uma textura é um arquivo de imagem normal em formato JPG ou PNG. Neste exemplo, você cria uma caixa com uma textura de Macaco não tonalizada como material.

    /** A simple textured cube. */
    Box boxshape1 = new Box(new Vector3f(-3f,1.1f,0f), 1f,1f,1f);
    Geometry cube = new Geometry("My Textured Box", boxshape1);
    Material mat_stl = new Material(assetManager, 
        "Common/MatDefs/Misc/Unshaded.j3md");
    Texture tex_ml = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
    mat_stl.setTexture("ColorMap", tex_ml);
    cube.setMaterial(mat_stl);
    rootNode.attachChild(cube);

Aqui está o que nós fizemos:

  • Criar uma geometria (Geometry) de uma malha caixa (Box). Vamos chamá-la cubo.
  • Criar uma textura com o arquivo Monkey.jpg e carregá-lo dentro do material.
  • O Mapa de Cor (ColorMap) é a camada de material típica onde texturas vão.
  • Aplique o material para o cubo, e anexe o cubo ao nó raiz (rootnode).

Textura não Tonalizada Transparente

Monkey.png é a mesma textura que Monkey.jpg, mas com um canal alfa adicionado. O canal alfa permite você especificar quais áreas da textura você quer que sejam opacas ou transparentes: Áreas pretas permancem opacas, áreas cinza se tornam translucentes, e áreas branca se tornam transparentes.

Para uma textura translucente/transparente, você precisa:

  • Uma textura com canal alfa
  • Um modo de mistura de textura BlendMode.Alpha
  • Uma geometria no "balde" de renderização Bucket.Transparent. Este balde assegura que o objeto translucente é desenhado no topo dos objetos atrás dele, e eles aparecem corretamente sob as partes translucentes. (Para objetos não-translucentes a ordem de desenho não é importante, porque o z-buffer mantém pista de se um pixel está atrás de alguma coisa mais ou não, e a cor de um pixel não depende dos pixels debaixo dele, isto é porque geometrias (Geometries) podem ser desenhadas em qualquer ordem.)
    /** A translucent/transparent texture. */
    Box boxshape3 = new Box(new Vector3f(0f,0f,0f), 1f,1f,0.01f);
    Geometry seethrough = new Geometry("see-through box", boxshape3);
    Material mat_tt = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat_tt.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
    mat_tt.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); // activate transparency
    seethrough.setMaterial(mat_tt);
    seethrough.setQueueBucket(Bucket.Transparent);
    rootNode.attachChild(seethrough);

O que você fez é o mesmo que antes, com somente um passo adicionado para a transparência.

  • Criar uma geometria (Geometry) de uma malha. Esta Geometria (Geometry) é uma caixa ereta plana.
  • Criar um Material baseado na definição de material padrão da jME3 Unshaded.j3md.
  • Criar uma textura do arquivo Monkey.png e carregue ela dentro do material.
  • O Mapa de Cor (ColorMap) é a camada de material onde texturas vão. Este arquivo PNG deve ter uma camada alfa.
  • Ative a transparência no material por configurar o modo de mistura para Alfa (Alpha)!
  • Aplique o material para a Geometria (Geometry).
  • Configure o QueueBucket da Geometria (Geometry) para Bucket.Transparent.
  • Anexe o cubo para o nó raiz (rootnode).

Dica: aprenda mais sobre criar imagens PNG com uma camada alfa no sistema de ajuda de seu editor gráfico.

Brilho e Rugosidade

Mas texturas não são tudo. Dê uma olhada na esfera brilhante - você não pode conseguir tal material rugoso com apenas uma textura. JME3 também suporta os assim chamados materiais iluminados por Phong:

Em um material iluminado, a camada de textura padrão é referida como Mapa Difuso (Diffuse Map), qualqurt material pode usar esta camada. Um material iluminado pode adicionalmente ter efeitos de iluminação tais como Brilho usado junto com uma camada de Mapa Especular (Specular Map), e mesmo uma superfície realisticamente rugosa ou quebrada com a ajuda de uma camada de Mapa de Normal (Normal Map).

Vamos dar uma olhada na parte do exemplo de código onde você cria a pedra rugosa brilhante.

  1. Crie uma Geometria (Geometry) de uma forma Esfera (Sphere). Note que esta forma é uma malha de esfera suave.
        Sphere rock = new Sphere(32,32, 2f);
        Geometry shiny_rock = new Geometry("Shiny rock", rock);
  1. (Somente para Esferas (Spheres)) Mude o Modo de Textura (TextureMode) da esfera para fazer a textura quadra se projetar melhor na esfera.
            rock.setTextureMode(Sphere.TextureMode.Projected);
  1. Você gera Binormais de Tangente (TangentBinormals) para a malha de esfera para que você use a camada de Mapa de Normal (NormalMap) da textura.
            TangentBinormalGenerator.generate(rock);
  1. Crie um material baseado no material padrão Lighting.j3md.
        Material mat_lit = new Material(assetManager, 
        "Common/MatDefs/Light/Lighting.j3md");
  1. Configure uma textura rochosa padrão na camda do Mapa Difuso (DiffuseMap) - http://jmonkeyengine.googlecode.com_svn_trunk_engine_test-data_textures_terrain_pond_pond.jpg
            mat_lit.setTexture("DiffuseMap", assetManager.loadTexture(
            "Textures/Terrain/Pond/Pond.jpg"));
  1. Configure a camada de Mapa Normal (NormalMap) que contém a rugosidade. O Mapa Normal (NormalMap) foi gerado para este Mapa Difuso (DiffuseMap) particular com uma ferramenta especial (e.g. Blender).
            mat_lit.setTexture("NormalMap", assetManager.loadTexture(
            "Textures/Terrain/Pond/Pond_normal.png"));
  1. Configure o Brilho do Material para um valor entre 1 e 128. Para uma rocha, um brilho fuzzy é apropriado
            mat_lit.setFloat("Shininess", 5f); // [1,128]
  1. Atribua seu material recém criado para a Geometria (Geometry).
        shiny_rock.setMaterial(mat_lit);
  1. Vamos mover e rotacionar a geometria um pouco para posicioná-lo melhor.
        shiny_rock.setLocalTranslation(0,2,-2); // Move it a bit
        shiny_rock.rotate(1.6f, 0, 0);          // Rotate it a bit
        rootNode.attachChild(shiny_rock);

Lembre que qualquer material baseado em Lighting.j3md requer uma fonte de luz, como mostrado na amostra de código completa acima.

Dica: Para desativar o Brilho, não configure o Brilho para 0, mas ao invés disso configure a cor Especular (Specular) para ColorRGBA.Black.

Definições de Material Padrão

Como você já viu, você pode achar os seguintes materiais padrão em jme/core-data/Common/….

Definição Padrão Uso Parâmetros
Common/MatDefs/Misc/Unshaded.j3md

Texturizado: Use com mat.setTexture() e Texture. || Color : Color
ColorMap : Texture2D ||

Common/MatDefs/Light/Lighting.j3md

Requer uma fonte de luz. || Ambient, Diffuse, Specular : Color
DiffuseMap, NormalMap, SpecularMap : Texture2D
Shininess : Float ||

Para um jogo, você cria Materiais Customizadps baseados nestas Definições Materiais existentes – como você já viu no exemplo com o material de rocha brilhante.

Exercícios

Exercício 1: Material .j3m Personalizado

Olhe na amostra de vazamento (leak-through) roxo acima de novo. Ela leva quatro linhas para criar e configurar o Material.

  • Note como isto carrega a definição de Material Unshaded.j3md.
  • Note como isto configura o parâmetro de cor (Color) para roxo (new ColorRGBA(1f,0f,1f,1f)).
  • Note como isto configura o Mapa de Cor (ColorMap) para um caminho de textura.

Se você quer usar um material customizado para vários modelos, você pode armazená-lo em um arquivo .j3m, e salvar algumas linhas de código toda vez. Você cria um arquivo j3m como se segue:

  • Crie um arquivo assets/Materials/LeakThrough.j3m em seu diretório de projeto, com o seguinte conteúdo:
    Material Leak Through : Common/MatDefs/Misc/Unshaded.j3md {
         MaterialParameters {
             Color : 1 0 1 1
             ColorMap : Flip Textures/ColoredTex/Monkey.png
         }
    }
  • Note que Material é uma palavra-chave fixa.
  • Note que Leak Through é uma String que você pode escolher para nomear o material.
  • Note como o código configura as mesmas três propriedades, Cor (Color), Mapa de Cor (ColorMap), e Unshaded.j3md.
  • Na amostra de código comente as três linhas com mat_tl nelas.
  • Abaixo delas, adicione a seguinte linha:
    cube_leak.setMaterial((Material) assetManager.loadMaterial( "Materials/LeakThrough.j3m"));
  • Execute o aplicativo. O resultado é o mesmo.

Usando este novo material customizado LeakThrough.j3m somente leva uma linha. Você substituiu as três linhas de uma definição de material "na hora" (on-the-fly) com uma linha que carrega um material personalizado de um arquivo. Este método é muito prático se você usa o mesmo material frequentemente.

Exercício 2: Rugosidade e Brilho

Volte à amostra de rocha rugosa acima:

  • Comente a linha de Mapa Difuso (DiffuseMap) e execute a aplicação. (Descomente ela de novo.)
    • Qual propriedade da rocha é perdida?
  • Comente a linha do Mapa de Normal (NormalMap), e execute a aplicação. (Descomente ela de novo.)
    • Qual propriedade da rocha é perdida?
  • Mude o valor de Brilho para valores como 0, 63, 127.
    • Que aspecto do Brilho muda?

Conclusão

Você aprendeu a como criar um Material, especificar suas propriedades, e usá-lo em uma Geometria (Geometry). Você sabe como carregar um arquivo de imagem (.png, .jpg) como textura em um material. Você sabe como salvar arquivos de textura em uma subpasta do diretório assets/Textures/ de seu projeto.

Você também aprendeu que um material pode ser armazenado em um arquivo .j3m. O arquivo referência uma Definição de Material (MaterialDefinition) embutida e especifica valores para propriedades daquela Definição de Material (MaterialDefinition). Você sabe salvar seus arquivos .j3m customizados em seu diretório assets/Materials/ do seu projeto.

Agora que você sabe como carregar modelos e como atribuir materiais de boa aparência para eles, vamos dar uma olhada em como animar modelos no próximo capítulo Hello Animation.

Veja também

  • Como Usar Materiais
  • Edição de Material
  • Thread de fórum de Materiais
  • Documentação de Materiais jME3 (PDF)
  • Vídeo Tutorial: Edição e Atribuição de Materiais para Modelos na SDK de jMonkeyEngine
  • Criando texturas em Blender
  • Vários instantâneos de Material (Não prontos com JME3, isto é apenas para mostrar o fantástico alcance de parâmetros Material nas mãos de um expert, até que nós tenhamos uma demo JME3 para ele.)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.