# jMonkeyEngine 3 Tutorial (6) - Hello Materials

Previous: Hello Input System, Next: Hello Animation

The term Material includes everything that influences what the surface of a 3D model looks like: The color, texture, shininess, and opacity/transparency. Plain coloring is covered in Hello Node. Loading models that come with materials is covered in Hello Asset. In this tutorial you learn to create and use custom JME3 Material Definitions.

To use the example assets in a new jMonkeyEngine SDK project, right-click your project, select "Properties", go to "Libraries", press "Add Library" and add the "jme3-test-data" library.

## Sample Code

    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);
      }
    }

You should see

- Left ??? A cube with a brown monkey texture.
- Middle ??? A translucent monkey picture in front of a shiny rock.
- Right ??? A cube with a purple monkey texture.

Move around with the WASD keys to have a closer look at the translucency, and the rock's bumpiness.

## Simple Unshaded Texture

Typically you want to give objects in your scene textures: It can be rock, grass, brick, wood, water, metal, paper??? A texture is a normal image file in JPG or PNG format. In this example, you create a box with a simple unshaded Monkey texture as 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);

Here is what we did:

1. Create a Geometry from a Box mesh. Let's call it `cube`.
2. Create a Material based on jME3's default `Unshaded.j3md` material definition.
3. Create a texture from the `Monkey.jpg` file and load it into the material.
   The ColorMap is the typical material layer where textures go.
4. Apply the material to the cube, and attach the cube to the rootnode.

## Transparent Unshaded Texture

`Monkey.png` is the same texture as `Monkey.jpg`, but with an added alpha channel. The alpha channel allows you to specify which areas of the texture you want to be opaque or transparent: Black areas remain opaque, gray areas become translucent, and white areas become transparent.

For a partially translucent/transparent texture, you need:

- A texture with alpha channel
- A Texture blend mode of `BlendMode.Alpha`
- A geometry in the `Bucket.Transparent` render bucket. This bucket ensures that the translucent object is drawn on top of objects behind it, and they show up correctly under the translucent parts. (For non-translucent objects the drawing order is not so important, because the z-buffer keeps track of whether a pixel is behind something else or not, and the color of a pixel doesn't depend on the pixels under it, this is why opaque Geometries can be drawn in any order.)

        /** 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);

What you did is the same as before, with only one added step for the transparency.

1. Create a Geometry from a mesh. This Geometry is flat upright box.
2. Create a Material based on jME3's default `Unshaded.j3md` material definition.
3. Create a texture from the `Monkey.png` file and load it into the material.
   The ColorMap is the material layer where textures go. This PNG file must have an alpha layer.
4. Activate transparency in the material by setting the blend mode to Alpha!
5. Apply the material to the Geometry.
6. Set the QueueBucket of the Geometry to `Bucket.Transparent`.
7. Attach the cube to the rootnode.

Tip: Learn more about creating PNG images with an alpha layer in the help system of your graphic editor.

## Shininess and Bumpiness

But textures are not all. Have a close look at the shiny sphere ??? you cannot get such a nice bumpy material with just a texture. JME3 also supports so-called Phong-illuminated materials:

In a lit material, the standard texture layer is refered to as Diffuse Map, any material can use this layer. A lit material can additionally have lighting effects such as Shininess used together with the Specular Map layer, and even a realistically bumpy or cracked surface with help of the Normal Map layer.

Let's have a look at the part of the code example where you create the shiny bumpy rock.

1. Create a Geometry from a Sphere shape. Note that this shape is a normal smooth sphere mesh.

           Sphere rock = new Sphere(32,32, 2f);
           Geometry shiny_rock = new Geometry("Shiny rock", rock);

   1. (Only for Spheres) Change the sphere's TextureMode to make the square texture project better onto the sphere.

              rock.setTextureMode(Sphere.TextureMode.Projected);

   2. You generate TangentBinormals for the sphere mesh so you can use the NormalMap layer of the texture.

              TangentBinormalGenerator.generate(rock);

2. Create a material based on the `Lighting.j3md` default material.

           Material mat_lit = new Material(assetManager,
           "Common/MatDefs/Light/Lighting.j3md");

   1. Set a standard rocky texture in the `DiffuseMap` layer.

              mat_lit.setTexture("DiffuseMap", assetManager.loadTexture(
              "Textures/Terrain/Pond/Pond.jpg"));

   2. Set the `NormalMap` layer that contains the bumpiness. The NormalMap was generated for this particular DiffuseMap with a special tool (e.g. Blender).

              mat_lit.setTexture("NormalMap", assetManager.loadTexture(
              "Textures/Terrain/Pond/Pond_normal.png"));

   3. Set the Material's Shininess to a value between 1 and 128. For a rock, a low fuzzy shininess is appropriate.

              mat_lit.setFloat("Shininess", 5f); // [1,128]

3. Assign your newly created material to the Geometry.

           shiny_rock.setMaterial(mat_lit);

4. Let's move and rotate the geometry a bit to position it better.

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

Remember that any Lighting.j3md-based material requires a light source, as shown in the full code sample above.

Tip: To deactivate Shininess, do not set `Shininess` to 0, but instead set the `Specular` color to `ColorRGBA.Black`.

## Default Material Definitions

As you have seen, you can find the following default materials in `jme/core-data/Common/???`.

Default Definition | Usage | Parameters
--- | --- | ---
`Common/MatDefs/Misc/Unshaded.j3md` | Colored: Use with mat.setColor() and ColorRGBA. Textured: Use with mat.setTexture() and Texture. | Color : Color ColorMap : Texture2D
`Common/MatDefs/Light/Lighting.j3md` | Use with shiny Textures, Bump- and NormalMaps textures. Requires a light source. | Ambient, Diffuse, Specular : Color DiffuseMap, NormalMap, SpecularMap : Texture2D Shininess : Float

For a game, you create custom Materials based on these existing MaterialDefintions ??? as you have just seen in the example with the shiny rock's material.

## Exercises

### Exercise 1: Custom .j3m Material

Look at the purple leak-through sample above again. It takes four lines to create and set the Material.

- Note how it loads the `Unshaded.j3md` Material definition.
- Note how it sets the `Color` parameter to purple (`new ColorRGBA(1f,0f,1f,1f)`).
- Note how it sets the `ColorMap` to a texture path.

If you want to use one custom material for several models, you can store it in a .j3m file, and save a few lines of code every time. You create a j3m file as follows:

1. Create a file `assets/Materials/LeakThrough.j3m` in your project directory, with the following content:

       Material Leak Through : Common/MatDefs/Misc/Unshaded.j3md {
            MaterialParameters {
                Color : 1 0 1 1
                ColorMap : Flip Textures/ColoredTex/Monkey.png
            }
       }

   - Note that `Material` is a fixed keyword.
   - Note that `Leak Through` is a String that you can choose to name the material.
   - Note how the code sets the same three properties, Color, ColorMap, and Unshaded.j3md.
2. In the code sample, comment out the three lines with `mat_tl` in them.
3. Below them, add the following line:

       cube_leak.setMaterial((Material) assetManager.loadMaterial( "Materials/LeakThrough.j3m"));

4. Run the app. The result is the same.

Using this new custom material `LeakThrough.j3m` only takes one line. You have replaced the three lines of an on-the-fly material definition with one line that loads a custom material from a file. This method is very handy if you use the same material often.

### Exercise 2: Bumpiness and Shininess

Go back to the bumpy rock sample above:

1. Comment out the DiffuseMap line, and run the app. (Uncomment it again.)
   - Which property of the rock is lost?
2. Comment out the NormalMap line, and run the app. (Uncomment it again.)
   - Which property of the rock is lost?
3. Change the value of Shininess to values like 0, 63, 127.
   - What aspect of the Shininess changes?

## Conclusion

You have learned how to create a Material, specify its properties, and use it on a Geometry. You know how to load an image file (.png, .jpg) as texture into a material. You know to save texture files in a subfolder of your project's `assets/Textures/` directory.

You have also learned that a material can be stored in a .j3m file. The file references a built-in MaterialDefinition and specifies values for properties of that MaterialDefinition. You know to save your custom .j3m files in your project's `assets/Materials/` directory.

Now that you know how to load models and how to assign good-looking materials to them, let's have a look at how to animate models in the next chapter, Hello Animation.

See also

- How to Use Materials
- Material Editing
- forum thread
- (PDF)
- (Not done with JME3, this is just to show the fantastic range of Material parameters in the hands of an expert, until we have a JME3 demo for it.)

documentation, beginner, intro, model, material, color, texture, transparency

view online version