2 <h1><a>Light and Shadow</a></h1>
7 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/shading-ani.gif">
11 Light and Shadow are two separate things in 3D engines, although we percieve them together in real life:
14 <li><div> Lighting means that an object is brighter on the side facing the light direction, and darker on the backside. Computationally, this is relatively easy. </div>
16 <li><div> Lighting does not mean that objects cast a shadow on the floor or other objects: Activating shadow processing is an additional step described here. Since casting shadows has an impact on performance, drop shadows and ambient occlusion shading are not activated by default.</div>
22 <p><div>A light source with a direction or location is required for all Geometries with Lighting.j3md-based Materials. An ambient light is not sufficient. In a scene with no appropriate light sources, Geometries with Lighting.j3md-based Materials do not render. Only Geometries with Unshaded.j3md-based Materials are visible independent of any light sources.
27 <!-- EDIT1 SECTION "Light and Shadow" [1-1017] -->
28 <h2><a>Light Sources and Colors</a></h2>
33 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/light-sources.png">
37 You can add several types of light sources to a scene using <code>rootNode.addLight(mylight)</code>.
41 The available light sources in <code>com.???jme3.???light</code> are:
44 <li><div> SpotLight </div>
46 <li><div> PointLight</div>
48 <li><div> AmbientLight</div>
50 <li><div> DirectionalLight</div>
56 You control the color and intensity of each light source. Typically you set the color to white (<code>new ColorRGBA(1.0f,1.0f,1.0f,1.0f)</code> or <code>ColorRGBA.White</code>), which makes all scene elements appear in their natural color.
60 You can choose to use lights in other colors than white, or darker colors. This influences the scene's atmosphere and will make the scene appear colder (e.g. <code>ColorRGBA.Cyan</code>) or warmer (<code>ColorRGBA.Yellow</code>), brighter (higher values) or darker (lower values).
64 You can get a list of all lights added to a Spatial by calling <code>getWorldLightList()</code> (includes inherited lights) or <code>getLocalLightList()</code> (only directly added lights), and iterating over the result.
68 <!-- EDIT2 SECTION "Light Sources and Colors" [1018-2059] -->
69 <h3><a>PointLight</a></h3>
74 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/elephant-pointlights.png">
78 A PointLight has a location and shines from there in all directions as far as its radius reaches. The light intensity decreases with increased distance from the light source. A PointLight can at the moment not be used for casting shadows (using the PssmShadowRenderer - read more about this below).
82 <strong>Typical example:</strong> Lamp, lightbulb, torch, candle.
84 <pre>PointLight lamp_light = new PointLight();
85 lamp_light.setColor(ColorRGBA.Yellow);
86 lamp_light.setRadius(4f);
87 lamp_light.setPosition(new Vector3f(lamp_geo.getLocalTranslation()));
88 rootNode.addLight(lamp_light);</pre>
91 <!-- EDIT3 SECTION "PointLight" [2060-2762] -->
92 <h3><a>DirectionalLight</a></h3>
97 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/house-directionallight.png">
101 A DirectionalLight has no position, only a direction. It sends out parallel beams of light and is considered "infinitely" far away. You typically have one directional light per scene. A DirectionalLight can be used together with shadows.
105 <strong>Typically example:</strong> Sun light.
107 <pre>DirectionalLight sun = new DirectionalLight();
108 sun.setColor(ColorRGBA.White);
109 sun.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal());
110 rootNode.addLight(sun);</pre>
113 <!-- EDIT4 SECTION "DirectionalLight" [2763-3367] -->
114 <h3><a>SpotLight</a></h3>
119 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/spotlight.png">
123 A SpotLight sends out a distinct beam or cone of light. A SpotLight has a direction, a position, distance (range) and two angles. 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 affected by the light.
127 <strong>Typical Example:</strong> Flashlight
129 <pre>SpotLight spot = new SpotLight();
130 spot.setSpotRange(100f); // distance
131 spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // inner light cone (central beam)
132 spot.setSpotOuterAngle(35f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light)
133 spot.setColor(ColorRGBA.White.mult(1.3f)); // light color
134 spot.setPosition(cam.getLocation()); // shine from camera loc
135 spot.setDirection(cam.getDirection()); // shine forward from camera loc
136 rootNode.addLight(spot);</pre>
139 If you want the spotlight to follow the flycam, repeat the setDirection(???) and setPosition(???) calls in the update loop, and kee syncing them with the camera position and direction.
143 <!-- EDIT5 SECTION "SpotLight" [3368-4502] -->
144 <h3><a>AmbientLight</a></h3>
149 An AmbientLight simply influences the brightness and color of the scene globally. It has no direction and no location and shines equally everywhere. An AmbientLight does not cast any shadows, and it lights all sides of Geometries evenly, which makes 3D objects look unnaturally flat; this is why you typically do not use an AmbientLight alone without one of the other lights.
153 <strong>Typical example:</strong> Regulate overall brightness, tinge the whole scene in a warm or cold color.
155 <pre>AmbientLight al = new AmbientLight();
156 al.setColor(ColorRGBA.White.mult(1.3f));
157 rootNode.addLight(al);</pre>
160 <p><div>You can increase the brightness of a light source gradually by multiplying the light color to values greater than 1.0f. <br/>
161 Example: <code>mylight.setColor(ColorRGBA.White.mult(1.3f));</code>
166 <!-- EDIT6 SECTION "AmbientLight" [4503-5325] -->
167 <h2><a>Light Follows Spatial</a></h2>
172 You can use a <code>com.jme3.scene.control.LightControl</code> to make a SpotLight or PointLight follow a Spatial. This can be used for a flashlight being carried by a character, or for car headlights, or an aircraft's spotlight, etc.
174 <pre>PointLight myLight = new PointLight();
175 rootNode.addLight(myLight);
176 LightControl lightControl = new LightControl(myLight);
177 spatial.addControl(lightControl); // this spatial controls the position of this light.</pre>
180 Obviously, this does not apply to AmbientLights, which have no position.
184 <!-- EDIT7 SECTION "Light Follows Spatial" [5326-5891] -->
185 <h2><a>Simple Lighting</a></h2>
193 <li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestSimpleLighting.java"><param name="text" value="<html><u>TestSimpleLighting.java</u></html>"><param name="textColor" value="blue"></object></div>
195 <li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestLightRadius.java"><param name="text" value="<html><u>TestLightRadius.java</u></html>"><param name="textColor" value="blue"></object></div>
201 For Simple Lighting we use Geometries with Materials based on Lighting.j3md (learn <a href="/com/jme3/gde/docs/jme3/advanced/materials_overview.html">more about Materials</a> here). Lighting.j3md-based materials dynamically support Shininess, and Ambient, Diffuse, and Specular light if there is a light source present. Note that this lighting method alone does not make the Geometry cast a shadow onto other Geometries automatically (see below for how to add drop shadows etc).
205 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/teapot-phong-illuminated.png">
207 <pre>Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
208 TangentBinormalGenerator.generate(teapot.getMesh(), true);
209 Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
210 mat.setBoolean("m_UseMaterialColors", true);
211 mat.setColor("m_Ambient", ColorRGBA.Orange);
212 mat.setColor("m_Diffuse", ColorRGBA.Orange);
213 mat.setColor("m_Specular", ColorRGBA.White);
214 mat.setFloat("m_Shininess", 12);
215 rootNode.attachChild(teapot);</pre>
218 The above example uses material colors and no textures. You can of course also use Lighting.j3md to create a lit Material that uses Texture Maps. The following example uses Shininess, Diffuse Map and Normal Map (a.k.a Bump Map).
222 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/bump-mapped-sphere.png">
224 <pre>Sphere rock = new Sphere(32,32, 2f);
225 Geometry shiny_rock = new Geometry("Shiny rock", rock);
226 rock.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres
227 TangentBinormalGenerator.generate(rock); // for lighting effect
228 Material mat_lit = new Material(
229 assetManager, "Common/MatDefs/Light/Lighting.j3md");
230 mat_lit.setTexture("m_DiffuseMap", // surface color
231 assetManager.loadTexture("Textures/Terrain/Pond/Pond.png"));
232 mat_lit.setTexture("m_NormalMap", // surface bumps
233 assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
234 mat_lit.setFloat("m_Shininess", 5f); // surface smoothness [1,128]
235 shiny_rock.setMaterial(mat_lit);
236 rootNode.attachChild(shiny_rock);</pre>
239 These light effects update live when the object or light source moves. If you shine a colored PointLight at this object, you will see a light reflection tinged in the color of the PointLight.
243 <!-- EDIT8 SECTION "Simple Lighting" [5892-8541] -->
244 <h2><a>BasicShadowRenderer</a></h2>
252 <li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestShadow.java"><param name="text" value="<html><u>TestShadow.java</u></html>"><param name="textColor" value="blue"></object></div>
258 Use the Shadow Renderer to make Geometries with Lighting.j3md-based Materials cast and receive basic drop shadows. This fast and simple implementation of a shadow effect is good for scenes with flat floors, but looks less realistic on uneven terrains. To use it, you add a jME SceneProcessor named com.jme3.shadow.BasicShadowRenderer to the viewPort.
262 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/drop-shadows.png">
264 <pre>BasicShadowRenderer bsr;
266 public void simpleInitApp() {
268 bsr = new BasicShadowRenderer(assetManager, 256);
269 bsr.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal()); // light direction
270 viewPort.addProcessor(bsr);
274 Shadow calculations (cast and receive) have a performance impact, therefor we recommend to use them smartly. Switch off the default shadow mode for the whole scene graph, and then specify the shadow behaviour individually for every scene node that needs shadows: You specifiy whether it casts shadows, receives shadows, both (slower), or neither (faster).
276 <pre>rootNode.setShadowMode(ShadowMode.Off); // reset all
277 wall.setShadowMode(ShadowMode.CastAndReceive); // normal behaviour (slow)
278 floor.setShadowMode(ShadowMode.Receive); // can't see shadow cast below floor anyway...
279 airplane.setShadowMode(ShadowMode.Cast); // nothing casts shadows onto airplane anyway...
280 ghost.setShadowMode(ShadowMode.Off); // ghost is translucent anyway...</pre>
283 <!-- EDIT9 SECTION "BasicShadowRenderer" [8542-10211] -->
284 <h2><a>DirectionalLightShadowRenderer</a></h2>
292 <li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestDirectionalLightShadow.java"><param name="text" value="<html><u>TestDirectionalLightShadow.java</u></html>"><param name="textColor" value="blue"></object></div>
295 <pre> DirectionalLight sun = new DirectionalLight();
296 sun.setColor(ColorRGBA.White);
297 sun.setDirection(cam.getDirection());
298 rootNode.addLight(sun);
301 final int SHADOWMAP_SIZE=1024;
302 DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
303 dlsr.setLight(sun);
304 viewPort.addProcessor(dlsr);
306 DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
307 dlsf.setLight(sun);
308 dlsf.setEnabled(true);
309 FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
310 fpp.addFilter(dlsf);
311 viewPort.addProcessor(fpp);</pre>
314 <!-- EDIT10 SECTION "DirectionalLightShadowRenderer" [10212-11184] -->
315 <h2><a>Parallel-Split Shadow Map (deprecated)</a></h2>
323 <li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestPssmShadow.java"><param name="text" value="<html><u>TestPssmShadow.java</u></html>"><param name="textColor" value="blue"></object></div>
329 The more advanced PSSM shadow renderer can cast real-time shadows, even on curved surfaces such as terrains. It is a bit more resource hungry than the BasicShadowRenderer. To activate PSSM drop shadows, add a jME SceneProcessor named <code>com.jme3.shadow.PssmShadowRenderer</code> to the viewPort. PSSM stands for the Parallel-Split Shadow Map technique.
333 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/shadow.png">
335 <pre>private PssmShadowRenderer pssmRenderer;
337 public void simpleInitApp() {
339 pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 3);
340 pssmRenderer.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal()); // light direction
341 viewPort.addProcessor(pssmRenderer);</pre>
344 The constructor expects the following values:
347 <li><div> Your assetManager object</div>
349 <li><div> The size of the rendered shadowmaps (512, 1024, 2048, etc???)</div>
351 <li><div> The number of shadow maps rendered (the more shadow maps, the more quality, the less FPS).</div>
357 You can set the following properties on the <code>pssmRenderer</code> object:
360 <li><div> setDirection(Vector3f) ??? the direction of the light</div>
362 <li><div> setLambda(0.65f) ??? Factor to use to reduce the split size</div>
364 <li><div> setShadowIntensity(0.7f) ??? shadow darkness (1 black, 0 invisible)</div>
366 <li><div> setShadowZextend() ??? distance how far away from camera shadows will still be computed</div>
372 As said above, it's more efficient to specify individual shadow behaviour for each Geometry.
374 <pre>teapot.setShadowMode(ShadowMode.CastAndReceive);
375 terrain.setShadowMode(ShadowMode.Receive); </pre>
378 <!-- EDIT11 SECTION "Parallel-Split Shadow Map (deprecated)" [11185-12920] -->
379 <h2><a>Screen Space Ambient Occlusion</a></h2>
387 <li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestSSAO.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestSSAO.java</u></html>"><param name="textColor" value="blue"></object>, <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestSSAO2.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestSSAO2.java</u></html>"><param name="textColor" value="blue"></object> ??? Screen-Space Ambient Occlusion shadows</div>
389 <li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestTransparentSSAO.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestTransparentSSAO.java</u></html>"><param name="textColor" value="blue"></object> ??? Screen-Space Ambient Occlusion shadows plus transparancy</div>
391 <li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/#more-321"><param name="text" value="<html><u>Screen Space Ambient Occlusion for jMonkeyEngine (article)</u></html>"><param name="textColor" value="blue"></object></div>
397 Ambient Occlusion refers to the shadows that nearby objects cast on each other under an ambient lighting. It???s an approximation of how light radiates in a real life scene. To activate Ambient Occlusion shadows, add a jME SceneProcessor named <code>com.jme3.post.SSAOFilter</code> to the viewPort. SSAO stands for the Screen Space Ambient Occlusion technique.
399 <pre>FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
400 SSAOFilter ssaoFilter = new SSAOFilter(12.94f, 43.92f, 0.33f, 0.61f);
401 fpp.addFilter(ssaoFilter);
402 viewPort.addProcessor(fpp);</pre>
405 <img src="nbdocs:/com/jme3/gde/docs/jme3/advanced/shading-textured-ani.gif">
410 <!-- EDIT12 SECTION "Screen Space Ambient Occlusion" [12921-] -->
411 <p><em><a href="http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:light_and_shadow?do=export_xhtmlbody">view online version</a></em></p>