Lighting means that an object is brighter on the side facing the light direction, and darker on the backside. A light source with a direction or location is required for lit Materials to be visible. Lighting does not automatically mean that objects cast a shadow on the floor or other objects: Activating shadow processing is an extra step described below.
You can add several light sources to a scene using rootNode.addLight()
. All Lighting.j3md- based Materials require a light source to be visible.
The available light sources in com.jme3.light
are SpotLight, PointLight, AmbientLight, and DirectionalLight. You can set the color of the light – normally, it is white. You can choose to set other colors to influence the scene's atmosphere.
A PointLight has a location and shines from there in all directions as far as its radius reaches, like a lamp. The light intensity decreases with increased distance from the light source.
PointLight lamp_light = new PointLight(); lamp_light.setColor(ColorRGBA.Yellow); lamp_light.setRadius(4f); lamp_light.setPosition(new Vector3f(lamp_geo.getLocalTranslation())); rootNode.addLight(lamp_light);
A DirectionalLight has no position, only a direction. It is considered "infinitely" far away and sends out parallel beams of light. It can cast shadows. You typically use it to simulate sun light:
DirectionalLight sun = new DirectionalLight(); sun.setColor(ColorRGBA.White); sun.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); rootNode.addLight(sun);
An AmbientLight influences the brightness of the whole scene globally. It has no direction and no location, and does not cast any shadow.
AmbientLight al = new AmbientLight(); al.setColor(ColorRGBA.White.mult(1.3f)); rootNode.addLight(al);
A SpotLight is like a flashlight that sends a distinct beam of light. (Still work in progress, as of alpha-3.)
Here we use a material based on Lighting.j3md (More info about Materials). Lighting.j3md-based materials dynamically support Shininess, and Ambient, Diffuse, and Specular Colors.
Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); TangentBinormalGenerator.generate(teapot.getMesh(), true); Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); mat.setBoolean("m_UseMaterialColors", true); mat.setColor("m_Ambient", ColorRGBA.Black); mat.setColor("m_Diffuse", ColorRGBA.Blue); mat.setColor("m_Specular", ColorRGBA.White); mat.setFloat("m_Shininess", 12); rootNode.attachChild(teapot);
In this example, we use material colors instead of textures. But you can equally well use Lighting.j3md to create a Material that uses texture maps, such as the Diffuse and Normal map used here, but also Specular and Paralax Maps:
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("m_DiffuseMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.png")); mat_lit.setTexture("m_NormalMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png")); mat_lit.setFloat("m_Shininess", 5f); // [0,128] shiny_rock.setMaterial(mat_lit); rootNode.attachChild(shiny_rock);
This lighting updates live when the object or light source moves. If you shine a colored PointLight at this object, you will see a light reflection in the color of the PointLight. This lighting method doesn't make the node cast a shadow onto other nodes.
Use the Shadow Renderer to make textured scene nodes cast and receive shadows. Switch off the default shadow mode, and add a jME SceneProcessor named com.jme3.shadow.BasicShadowRenderer to the viewPort.
BasicShadowRenderer bsr; ... public void simpleInitApp() { ... rootNode.setShadowMode(ShadowMode.Off); bsr = new BasicShadowRenderer(assetManager, 256); bsr.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); viewPort.addProcessor(bsr); ...
For every scene node that needs shadows, individually specify the shadow behaviour: Whether it cast shadows, receive shadows, both, or neither.
wall.setShadowMode(ShadowMode.CastAndReceive); ... floor.setShadowMode(ShadowMode.Receive); ... airplane.setShadowMode(ShadowMode.Cast); ... ghost.setShadowMode(ShadowMode.Off); ...
The PSSM shadow renderer can cast real-time shadows on curved surfaces.
To activate it, add a jME SceneProcessor named com.jme3.shadow.PssmShadowRenderer
to the viewPort.
private PssmShadowRenderer pssmRenderer; ... public void simpleInitApp() { .... pssmRenderer = new PssmShadowRenderer( assetManager,1024,4,PssmShadowRenderer.EDGE_FILTERING_PCF); pssmRenderer.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); viewPort.addProcessor(pssmRenderer);
The constructor expects the following values:
You can set the following properties on the pssmRenderer
object:
As usual, specify the shadow behaviour for every scene node.
... teapot.setShadowMode(ShadowMode.CastAndReceive); ... soil.setShadowMode(ShadowMode.Receive); ...