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 (intensity) of the light – normally, it is white (ColorRGBA(1,1,1,1)). 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,13, -1,13, 1,13).normalizeLocal()); rootNode.addLight(sun);
An AmbientLight influences the brightness of the scene globally. It has no direction and no location, and does not cast any shadows.
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, or cone of light. A SpotLight has a direction, a position, distance (range) and an angle. The inner angle is the central maximum of the light cone, the outer angle the edge of the light cone. Everything outside the light cone's angles is not affacted by the light.
SpotLight sl = new SpotLight(); sl.setDirection(new Vector3f(1,0,1)); // direction sl.setPosition(new Vector3f(0,0,0)); sl.setSpotInnerAngle(15f); // inner light cone (maximum) sl.setSpotOuterAngle(35f); // outer light cone (edge of the light) sl.setSpotRange(10f); // distance sl.setColor(ColorRGBA.White.mult(1.3f)); rootNode.addLight(sl);
You can use a com.jme3.scene.control.LightControl to make a SpotLight or PointLight follow a Spatial.
PointLight myLight = new PointLight(); rootNode.addLight(myLight); LightControl lightControl = new LightControl(myLight); spatial.addControl(lightControl);
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); ...