Previous: Hello Input System,
Next: Hello Animation When we speak of Materials, we mean everything that influences what the surface of a 3D model looks like: The color, texture, and material (shininess, opacity/transparency). Simple coloring is covered in Hello Node. Loading models that come with materials is covered in Hello Asset. Here we focus on using and creating JME3 Material Definitions.
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(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(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(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.png"));
mat_lit.setTexture("NormalMap",
assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
mat_lit.setFloat("Shininess", 5f); // [0,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
Move around with the WASD keys to have a closer look at the translucency, and the rock's bumpiness.
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, we create a box with a simple unshaded Monkey texture as material.
/** A simple textured cube. */ 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:
Unshaded.j3md
material definition.Monkey.jpg
file and load it into the material. 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 translucent: Black areas remain opaque, gray areas become translucent, and white areas become transparent. In combination with setting the texture blend mode to BlendMode.Alpha
, this results in a partially translucent/transparent texture!
You also need to set the render bucket of the object with the translucent texture to Bucket.Transparent
. This 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, so they can be drawn in any order.
/** A translucent/transparent texture. */ 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 we did it the same as before, with only one added step for the transparency.
Unshaded.j3md
material definition.Monkey.png
file and load it into the material. Bucket.Transparent
to ensure that the translucent objects is drawn after objects behind it.Tip: Learn more about creating PNG images with an alpha layer in the help system of your graphic editor.
But textures are not all. Have a look at the shiny bumpy sphere again – you cannot get such a nice material with just a texture. We will have a quick look at some advanced jme features here – lit materials: In a lit material, the standard texture layer is refered to as Diffuse Map, any material can have it. 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.
Sphere rock = new Sphere(32,32, 2f); Geometry shiny_rock = new Geometry("Shiny rock", rock);
rock.setTextureMode(Sphere.TextureMode.Projected);
TangentBinormalGenerator.generate(rock);
Lighting.j3md
default material.Material mat_lit = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
mat_lit.setFloat("Shininess", 5f); // [0,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);
As you have seen, the following default materials can always be found in jme/core-data/Common
.
Default Definition | Usage | Parameters |
---|---|---|
Common/MatDefs/Misc/Unshaded.j3md | Textured: Use with mat.setTexture() and TextureKey. Colored: Use with mat.setColor() and RGBAColor. | ColorMap : Texture. |
Common/MatDefs/Light/Lighting.j3md | Use with shiny Textures, Bump- and NormalMaps textures. Requires a light source. | Ambient, Diffuse, Specular : Color DiffuseMap, NormalMap, SpecularMap : Texture Shininess : Float |
In a real game, you will create your custom Materials based these existing ones – as you have just seen in the example with the shiny rock.
Look at the purple leak-through sample above again. It takes four lines to create and set the Material.
Unshaded.j3md
Material definition.Color
parameter to purple (new ColorRGBA(1f,0f,1f,1f)
).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. Here is an example:
Create a file assets/Materials/LeakThrough.j3m
with the following content:
Material Leak Through : Common/MatDefs/Misc/Unshaded.j3md { MaterialParameters { Color : 1 0 1 1 ColorMap : Textures/ColoredTex/Monkey.png } }
Material
is a keyword.Leak Through
is a name that you can choose. Using this new custom material LeakThrough.j3m
only takes one line.
mat_tl
in them.cube_leak.setMaterial((Material) assetManager.loadAsset( "Materials/LeakThrough.j3m"));
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.
Go back to the bumpy rock sample above:
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 Material Definition 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