123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Asciidoctor 1.5.4"><title>Light and Shadow</title><link rel="stylesheet" href="./asciidoctor.css">
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
- <link rel="stylesheet" href="./coderay-asciidoctor.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css"></head><body class="article toc2 toc-left"><div id="header"><div id="toolbar"><a href="https://github.com/jMonkeyEngine/wiki/edit/master/src/docs/asciidoc/jme3/advanced/light_and_shadow.adoc"><i class="fa fa-pencil-square" aria-hidden="true"></i></a><a href="https://github.com/jMonkeyEngine/wiki/new/master/src/docs/asciidoc/jme3/advanced/"><i class="fa fa-plus-square" aria-hidden="true"></i></a><input dir="auto" style="position: relative; vertical-align: top;" spellcheck="false" autocomplete="off" class="searchbox__input aa-input" id="doc-search" name="search" placeholder="Search in the doc" required="required" type="search"></div><h1>Light and Shadow</h1><div class="details"><span class="author" id="author"></span><br><span id="revnumber">version ,</span> <span id="revdate">2016/03/17 20:48</span></div><div id="toc" class="toc2"><div id="toctitle">Table of Contents</div><ul class="sectlevel1"><li><a href="#light-sources-and-colors">Light Sources and Colors</a><ul class="sectlevel2"><li><a href="#pointlight">PointLight</a></li><li><a href="#directionallight">DirectionalLight</a></li><li><a href="#spotlight">SpotLight</a></li><li><a href="#ambientlight">AmbientLight</a></li></ul></li><li><a href="#light-follows-spatial">Light Follows Spatial</a></li><li><a href="#basicshadowrenderer-deprecated">BasicShadowRenderer (deprecated)</a></li><li><a href="#casting-shadows">Casting Shadows</a></li><li><a href="#parallel-split-shadow-map-deprecated">Parallel-Split Shadow Map (deprecated)</a></li><li><a href="#screen-space-ambient-occlusion">Screen Space Ambient Occlusion</a></li></ul></div></div><div id="content"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p><span class="image"><img src="../../jme3/advanced/shading-ani.gif" alt="Examples of shading and lighting." height=""></span></p></div>
- <div class="paragraph"><p>Light and Shadow are two separate things in 3D engines, although we percieve them together in real life:</p></div>
- <div class="ulist"><ul><li><p>Lighting means that an object is brighter on the side facing the light direction, and darker on the backside. Computationally, this is relatively easy.</p></li><li><p>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.</p></li></ul></div>
- <div class="admonitionblock important"><table><tr><td class="icon"><i class="fa icon-important" title="Important"></i></td><td class="content"><div class="paragraph"><p>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.</p></div></td></tr></table></div></div></div>
- <div class="sect2"><h3 id="light-sources-and-colors">Light Sources and Colors</h3><div style="text-align: right;" class="imageblock"><div class="content"><img src="../../jme3/advanced/light-sources.png" alt="A lit scene with multiple light sources" height="200"></div></div>
- <div class="paragraph"><p>You can add several types of light sources to a scene using <code>rootNode.addLight(mylight)</code>.</p></div>
- <div class="paragraph"><p>The available light sources in <code>com.jme3.light</code> are:</p></div>
- <div class="ulist"><ul><li><p>SpotLight</p></li><li><p>PointLight</p></li><li><p>AmbientLight</p></li><li><p>DirectionalLight</p></li></ul></div>
- <div class="paragraph"><p>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.</p></div>
- <div class="paragraph"><p>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).</p></div>
- <div class="paragraph"><p>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.</p></div>
- <div class="sect2"><h3 id="pointlight">PointLight</h3><div style="text-align: right;" class="imageblock"><div class="content"><img src="../../jme3/advanced/elephant-pointlights.png" alt="An elephant model illuminated by pointlights" height="205"></div></div>
- <div class="paragraph"><p>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 be used to cast shadows along with a PointLightShadowRenderer (see the Casting Shadows section)</p></div>
- <div class="paragraph"><p><strong>Typical example:</strong> Lamp, lightbulb, torch, candle.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">PointLight lamp_light = <span class="keyword">new</span> PointLight();
- lamp_light.setColor(ColorRGBA.Yellow);
- lamp_light.setRadius(<span class="float">4f</span>);
- lamp_light.setPosition(<span class="keyword">new</span> Vector3f(lamp_geo.getLocalTranslation()));
- rootNode.addLight(lamp_light);</code></pre></div></div></div>
- <div class="sect2"><h3 id="directionallight">DirectionalLight</h3><div style="text-align: right;" class="imageblock"><div class="content"><img src="../../jme3/advanced/house-directionallight.png" alt="A house model illuminated with a sun-like directional light" height="210"></div></div>
- <div class="paragraph"><p>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.</p></div>
- <div class="paragraph"><p><strong>Typically example:</strong> Sun light.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">DirectionalLight sun = <span class="keyword">new</span> DirectionalLight();
- sun.setColor(ColorRGBA.White);
- sun.setDirection(<span class="keyword">new</span> Vector3f(-<span class="float">.5f</span>,-<span class="float">.5f</span>,-<span class="float">.5f</span>).normalizeLocal());
- rootNode.addLight(sun);</code></pre></div></div></div>
- <div class="sect2"><h3 id="spotlight">SpotLight</h3><div style="text-align: right;" class="imageblock"><div class="content"><img src="../../jme3/advanced/spotlight.png" alt="Spotlight" height=""></div></div>
- <div class="paragraph"><p>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.</p></div>
- <div class="paragraph"><p><strong>Typical Example:</strong> Flashlight</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">SpotLight spot = <span class="keyword">new</span> SpotLight();
- spot.setSpotRange(<span class="float">100f</span>); <span class="comment">// distance</span>
- spot.setSpotInnerAngle(<span class="float">15f</span> * FastMath.DEG_TO_RAD); <span class="comment">// inner light cone (central beam)</span>
- spot.setSpotOuterAngle(<span class="float">35f</span> * FastMath.DEG_TO_RAD); <span class="comment">// outer light cone (edge of the light)</span>
- spot.setColor(ColorRGBA.White.mult(<span class="float">1.3f</span>)); <span class="comment">// light color</span>
- spot.setPosition(cam.getLocation()); <span class="comment">// shine from camera loc</span>
- spot.setDirection(cam.getDirection()); <span class="comment">// shine forward from camera loc</span>
- rootNode.addLight(spot);</code></pre></div></div>
- <div class="paragraph"><p>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.</p></div></div>
- <div class="sect2"><h3 id="ambientlight">AmbientLight</h3><div class="paragraph"><p>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.</p></div>
- <div class="paragraph"><p><strong>Typical example:</strong> Regulate overall brightness, tinge the whole scene in a warm or cold color.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">AmbientLight al = <span class="keyword">new</span> AmbientLight();
- al.setColor(ColorRGBA.White.mult(<span class="float">1.3f</span>));
- rootNode.addLight(al);</code></pre></div></div>
- <div class="admonitionblock tip"><table><tr><td class="icon"><i class="fa icon-tip" title="Tip"></i></td><td class="content"><div class="paragraph"><p>You can increase the brightness of a light source gradually by multiplying the light color to values greater than 1.0f. +Example: <code>mylight.setColor(ColorRGBA.White.mult(1.3f));</code></p></div></td></tr></table></div></div></div>
- <div class="sect1"><h2 id="light-follows-spatial">Light Follows Spatial</h2><div class="sectionbody"><div class="paragraph"><p>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.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">PointLight myLight = <span class="keyword">new</span> PointLight();
- rootNode.addLight(myLight);
- LightControl lightControl = <span class="keyword">new</span> LightControl(myLight);
- spatial.addControl(lightControl); <span class="comment">// this spatial controls the position of this light.</span></code></pre></div></div>
- <div class="paragraph"><p>Obviously, this does not apply to AmbientLights, which have no position.</p></div></div></div>
- <div class="sect1"><h2 id="basicshadowrenderer-deprecated">BasicShadowRenderer (deprecated)</h2><div class="sectionbody"><div class="paragraph"><p>Full code sample</p></div>
- <div class="ulist"><ul><li><p><a href="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestShadow.java">TestShadow.java</a></p></li></ul></div></div></div>
- <div class="sect1"><h2 id="casting-shadows">Casting Shadows</h2><div class="sectionbody"><div class="paragraph"><p>For each type of non-ambient light source, JME3 implements two ways to simulate geometries casting shadows on other geometries:</p></div>
- <div class="ulist"><ul><li><p>a shadow renderer (which you apply to a viewport) and</p></li><li><p>a shadow filter (which you can add to a viewport’s filter post-processor).</p></li></ul></div>
- <table class="tableblock frame-all grid-all spread"><colgroup><col style="width: 100%;"></colgroup><tbody><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>light source class</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>shadow renderer class</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>shadow filter class</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>DirectionalLight</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>DirectionalLightShadowRenderer</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>DirectionalLightShadowFilter</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>PointLight</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>PointLightShadowRenderer</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>PointLightShadowFilter</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>SpotLight</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>SpotLightShadowRenderer</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>SpotLightShadowFilter</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>AmbientLight</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>(not applicable)</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>(not applicable)</p></div></div></td></tr></tbody></table>
- <div class="paragraph"><p>You only need one shadow simulation per light source: if you use shadow rendering, you won’t need a shadow filter and vice versa. Which way is more efficient depends partly on the complexity of your scene. All six shadow simulation classes have similar interfaces, so once you know how to use one, you can easily figure out the rest.</p></div>
- <div class="paragraph"><p>Shadow calculations (cast and receive) have a performance impact, so use them sparingly. With shadow renderers, you can turn off shadow casting and/or shadow receiving for individual geometries, for portions of the scene graph, or for the entire scene:</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">spatial.setShadowMode(ShadowMode.Inherit); <span class="comment">// This is the default setting for new spatials.</span>
- rootNode.setShadowMode(ShadowMode.Off); <span class="comment">// Disable shadows for the whole scene, except where overridden.</span>
- wall.setShadowMode(ShadowMode.CastAndReceive); <span class="comment">// The wall can cast shadows and also receive them.</span>
- floor.setShadowMode(ShadowMode.Receive); <span class="comment">// Any shadows cast by the floor would be hidden by it.</span>
- airplane.setShadowMode(ShadowMode.Cast); <span class="comment">// There's nothing above the airplane to cast shadows on it.</span>
- ghost.setShadowMode(ShadowMode.Off); <span class="comment">// The ghost is translucent: it neither casts nor receives shadows.</span></code></pre></div></div>
- <div class="paragraph"><p>Both shadow renderers and shadow filters use shadow modes to determine which objects can cast shadows. However, only the shadow renderers pay attention to shadow modes when determining which objects receive shadows. With a shadow filter, shadow modes have no effect on which objects receive shadows.</p></div>
- <div class="paragraph"><p>Here’s a sample application which demonstrates both DirectionalLightShadowRenderer and DirectionalLightShadowFilter:</p></div>
- <div class="ulist"><ul><li><p><a href="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestDirectionalLightShadow.java">TestDirectionalLightShadow.java</a></p></li></ul></div>
- <div class="paragraph"><p>Here is the key code fragment:</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> DirectionalLight sun = <span class="keyword">new</span> DirectionalLight();
- sun.setColor(ColorRGBA.White);
- sun.setDirection(cam.getDirection());
- rootNode.addLight(sun);
- <span class="comment">/* Drop shadows */</span>
- <span class="directive">final</span> <span class="type">int</span> SHADOWMAP_SIZE=<span class="integer">1024</span>;
- DirectionalLightShadowRenderer dlsr = <span class="keyword">new</span> DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, <span class="integer">3</span>);
- dlsr.setLight(sun);
- viewPort.addProcessor(dlsr);
- DirectionalLightShadowFilter dlsf = <span class="keyword">new</span> DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, <span class="integer">3</span>);
- dlsf.setLight(sun);
- dlsf.setEnabled(<span class="predefined-constant">true</span>);
- FilterPostProcessor fpp = <span class="keyword">new</span> FilterPostProcessor(assetManager);
- fpp.addFilter(dlsf);
- viewPort.addProcessor(fpp);</code></pre></div></div>
- <div class="paragraph"><p>Constructor arguments:
- * your AssetManager object
- * size of the rendered shadow maps, in pixels per side (512, 1024, 2048, etc…)
- * the number of shadow maps rendered (more shadow maps = better quality, but slower)</p></div>
- <div class="paragraph"><p>Properties you can set:
- * setDirection(Vector3f) – the direction of the light
- * setLambda(0.65f) – to reduce the split size
- * setShadowIntensity(0.7f) – shadow darkness (1=black, 0=invisible)
- * setShadowZextend(float) – distance from camera to which shadows will be computed</p></div></div></div>
- <div class="sect1"><h2 id="parallel-split-shadow-map-deprecated">Parallel-Split Shadow Map (deprecated)</h2><div class="sectionbody"><div class="paragraph"><p>Full sample code</p></div>
- <div class="ulist"><ul><li><p><a href="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestPssmShadow.java">TestPssmShadow.java</a></p></li></ul></div>
- <div style="text-align: right;" class="imageblock"><div class="content"><img src="../../jme3/advanced/shadow.png" alt="A lit scene with PSSM drop shadows" height="200"></div></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="directive">private</span> PssmShadowRenderer pssmRenderer;
- ...
- public <span class="type">void</span> simpleInitApp() {
- ....
- pssmRenderer = <span class="keyword">new</span> PssmShadowRenderer(assetManager, <span class="integer">1024</span>, <span class="integer">3</span>);
- pssmRenderer.setDirection(<span class="keyword">new</span> Vector3f(-<span class="float">.5f</span>,-<span class="float">.5f</span>,-<span class="float">.5f</span>).normalizeLocal()); <span class="comment">// light direction</span>
- viewPort.addProcessor(pssmRenderer);</code></pre></div></div></div></div>
- <div class="sect1"><h2 id="screen-space-ambient-occlusion">Screen Space Ambient Occlusion</h2><div class="sectionbody"><div class="paragraph"><p>Full sample code</p></div>
- <div class="ulist"><ul><li><p><a href="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestSSAO.java">jme3/src/test/jme3test/post/TestSSAO.java</a> – Screen-Space Ambient Occlusion shadows</p></li><li><p><a href="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestTransparentSSAO.java">jme3/src/test/jme3test/post/TestTransparentSSAO.java</a> – Screen-Space Ambient Occlusion shadows plus transparancy</p></li><li><p><a href="http://hub.jmonkeyengine.org/2010/08/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/">Screen Space Ambient Occlusion for jMonkeyEngine (article)</a></p></li></ul></div>
- <div class="paragraph"><p>Ambient Occlusion refers to the shadows which nearby objects cast on each other under an ambient lighting. Screen Space Ambient Occlusion (SSAO) approximates how light radiates in real life.</p></div>
- <div class="paragraph"><p>In JME3, SSAO is implemented by adding an instance of <code>com.jme3.post.SSAOFilter</code> to a viewport which already simulates shadows using another method such as DirectionalLightShadowRenderer.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">FilterPostProcessor fpp = <span class="keyword">new</span> FilterPostProcessor(assetManager);
- SSAOFilter ssaoFilter = <span class="keyword">new</span> SSAOFilter(<span class="float">12.94f</span>, <span class="float">43.92f</span>, <span class="float">0.33f</span>, <span class="float">0.61f</span>);
- fpp.addFilter(ssaoFilter);
- viewPort.addProcessor(fpp);</code></pre></div></div>
- <div class="paragraph"><p><span class="image"><img src="../../jme3/advanced/shading-textured-ani.gif" alt="Shading with and without Ambient Occlusion" height=""></span></p></div></div></div></div><div id="footer"><div id="footer-text">Version <br>Last updated 2016-07-22 07:15:15 UTC</div></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script><script>docsearch({
- apiKey: 'a736b6d93de805e26ec2f49b55013fbd',
- indexName: 'jmonkeyengine',
- inputSelector: '#doc-search',
- debug: false // Set debug to true if you want to inspect the dropdown
- });</script></body></html>
|