{"id":145,"date":"2018-11-01T13:37:01","date_gmt":"2018-11-01T13:37:01","guid":{"rendered":"https:\/\/blog.nameless.zanity.net\/?p=145"},"modified":"2018-11-10T02:34:21","modified_gmt":"2018-11-10T02:34:21","slug":"using-a-light-function-to-make-a-lantern-that-casts-dynamic-soft-shadows-from-its-model","status":"publish","type":"post","link":"https:\/\/blog.nameless.zanity.net\/?p=145","title":{"rendered":"Using a light function to make a lantern that casts dynamic, soft shadows from its model"},"content":{"rendered":"<p>The goal of this tutorial is to set up a lantern object which casts soft dynamic shadows from the solid parts of the lantern.<\/p>\n<p>The two normal ways of creating detailed shadows are to either bake them with static lights (which will not work for a moveable light source), or to use Raytraced Distance Field Soft Shadows, which don&#8217;t work very well if the light source is actually <em>inside<\/em> the model which is supposed to cast the shadow.<\/p>\n<p>Instead of either of those, I will explain how to solve this problem by using a light function.<\/p>\n<p>A light function is a material shader that can filter the intensity of light being output by a light source.\u00a0 It can be used to give the light different intensities at different angles, with the output of the light dependant on the colour of the material, from black (no illumination) to white (full illumination).<\/p>\n<p>We will use this to effectively mask the parts of the light where we don&#8217;t want it to shine at full brightness.<br \/>\nFurther, we will blend between two different masks depending on the distance, giving a more realistic effect where the shadows are fairly sharp close to the light source, but get softer as the distance increases.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-211\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLampSoftShadowsPreview.jpg\" alt=\"\" width=\"1014\" height=\"483\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLampSoftShadowsPreview.jpg 1014w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLampSoftShadowsPreview-300x143.jpg 300w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLampSoftShadowsPreview-768x366.jpg 768w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLampSoftShadowsPreview-800x381.jpg 800w\" sizes=\"auto, (max-width: 1014px) 100vw, 1014px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><!--more--><\/p>\n\n<h2>Requirements<\/h2>\n<p>This tutorial will need the following tools:<\/p>\n<ul>\n<li>A 3D modelling package<\/li>\n<li>An image manipulation tool (<a href=\"https:\/\/www.irfanview.com\/\">IrfanView<\/a> is suggested, as I have included a batch script which makes use of it to automate some steps.)<\/li>\n<li><a href=\"https:\/\/gpuopen.com\/archive\/gamescgi\/cubemapgen\/\">AMD CubeMapGen<\/a><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h2>The model<\/h2>\n<p>The first step is to create the model that you wish the light source to be inside.\u00a0 That is a very complicated subject, far beyond the scope of this tutorial.<\/p>\n<p>I will be using this miner&#8217;s lamp as the example model.<\/p>\n<div id=\"attachment_147\" style=\"width: 576px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SafetyLamp.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-147\" class=\"wp-image-147 size-large\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SafetyLamp-566x800.jpg\" alt=\"\" width=\"566\" height=\"800\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SafetyLamp-566x800.jpg 566w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SafetyLamp-212x300.jpg 212w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SafetyLamp.jpg 722w\" sizes=\"auto, (max-width: 566px) 100vw, 566px\" \/><\/a><p id=\"caption-attachment-147\" class=\"wp-caption-text\">A Miner&#8217;s Lamp model<\/p><\/div>\n<p>This model has a cylindrical area which will contain the light.\u00a0 The position of the light is specified by a socket (which the Point Light component will be attached to inside Unreal.)<\/p>\n<p>The expectation would be for the light produced by this to be blocked in a cylinder at the top and the bottom, and to have six small vertical bars of shadow where the support beams are.<\/p>\n<p>&nbsp;<\/p>\n<h2>Creating a cubemap for the light mask<\/h2>\n<p>We will need to create a cubemap to act as a mask for which sides of the lamp are obstructed.<br \/>\nThe cubemap will effectively be a 360\u00b0 view from the position of the light source, with white for the angles at which the light escapes the lamp and black for the angles where is obstructed.<\/p>\n<p>I created the cubemap for the lantern by making a copy of the model and placing it inside a sphere with flipped normals.<br \/>\nI painted the model itself with a pure black material, and the sphere with a pure white one.\u00a0 (I also subdivided and smoothed the mesh to make the shape of the shadow more rounded than the actual in-game model.)<\/p>\n<div id=\"attachment_150\" style=\"width: 524px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LanternInSphere.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-150\" class=\"wp-image-150 size-full\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LanternInSphere.jpg\" alt=\"\" width=\"514\" height=\"457\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LanternInSphere.jpg 514w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LanternInSphere-300x267.jpg 300w\" sizes=\"auto, (max-width: 514px) 100vw, 514px\" \/><\/a><p id=\"caption-attachment-150\" class=\"wp-caption-text\">Setting up a scene for capturing a cubemap<\/p><\/div>\n<p>The cubemap needs to be created from the point on the model where the light will originate &#8211; in this case, I created it from the socket that I placed in the model for the flame position.<\/p>\n<p>Most 3D modelling packages should have the capability to create a cubemap for a specific point in 3D space.\u00a0 The exact procedure to create a cubemap will depend on the chosen application.<br \/>\nRegardless, the process should result in a set of six images, one for each face of the cube: Back, down, front, left, right, and up.<\/p>\n<p>The images need to be arranged into a cube-cross image, using the following format:<\/p>\n<div id=\"attachment_152\" style=\"width: 394px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SampleCubeMap_cubecross.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-152\" class=\"wp-image-152 size-full\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SampleCubeMap_cubecross.jpg\" alt=\"\" width=\"384\" height=\"512\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SampleCubeMap_cubecross.jpg 384w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SampleCubeMap_cubecross-225x300.jpg 225w\" sizes=\"auto, (max-width: 384px) 100vw, 384px\" \/><\/a><p id=\"caption-attachment-152\" class=\"wp-caption-text\">A cross view of a sample cubemap with labelled sides<\/p><\/div>\n<p>&nbsp;<\/p>\n<p>The following Windows batch script will use IrfanView to rotate and place the six images of the cubemap into the appropriate cross position.<br \/>\nIt assumes that the input images are named as follows (replace baseFilename with the appropriate name of for the cubemap.):<\/p>\n<ul>\n<li>baseFilename_LF.png &#8211; Left<\/li>\n<li>baseFilename_RT.png &#8211; Right<\/li>\n<li>baseFilename_BK.png &#8211; Back<\/li>\n<li>baseFilename_FR.png &#8211; Front<\/li>\n<li>baseFilename_UP.png &#8211; Up<\/li>\n<li>baseFilename_DN.png &#8211; Down<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>(To use this, modify the path to IrfanView as appropriate for your system.)<\/p>\n<pre>@echo off\r\nset iview=\"C:\\Program Files (x86)\\IrfanView\\i_view32.exe\"\r\n\r\n%iview% %1_LF.png \/bright=-255 \/convert tmp_0.png\r\n%iview% %1_LF.png \/rotate_l \/convert tmp_1.png\r\n%iview% %1_RT.png \/rotate_r \/convert tmp_2.png\r\n%iview% %1_BK.png \/rotate_r \/rotate_r \/convert tmp_3.png\r\n%iview% %1_FR.png \/convert tmp_4.png\r\n%iview% %1_UP.png \/rotate_r \/rotate_r \/convert tmp_5.png\r\n%iview% %1_DN.png \/rotate_r \/rotate_r \/convert tmp_6.png\r\n%iview% \/panorama=(2,tmp_0.png,tmp_2.png,tmp_0.png,tmp_0.png) \/convert tmp_a.png\r\n%iview% \/panorama=(2,tmp_3.png,tmp_5.png,tmp_4.png,tmp_6.png) \/convert tmp_b.png\r\n%iview% \/panorama=(2,tmp_0.png,tmp_1.png,tmp_0.png,tmp_0.png) \/convert tmp_c.png\r\n%iview% \/panorama=(1,tmp_a.png,tmp_b.png,tmp_c.png) \/convert %1_cubecross.png\r\n\r\ndel tmp_0.png tmp_1.png tmp_2.png tmp_3.png tmp_4.png tmp_5.png tmp_6.png\r\ndel tmp_a.png tmp_b.png tmp_c.png<\/pre>\n<p>&nbsp;<\/p>\n<p>Save as MakeCubeCross.cmd and run from the command line with:<\/p>\n<pre>MakeCubeCross basefilename<\/pre>\n<p>(You can also make the &#8220;cube cross&#8221; manually using your favourite image editing tool.)<\/p>\n<p>The cube cross for the miner&#8217;s lamp looks like this:<\/p>\n<div id=\"attachment_153\" style=\"width: 394px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/MinerLamp_cubecross.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-153\" class=\"wp-image-153 size-full\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/MinerLamp_cubecross.jpg\" alt=\"\" width=\"384\" height=\"512\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/MinerLamp_cubecross.jpg 384w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/MinerLamp_cubecross-225x300.jpg 225w\" sizes=\"auto, (max-width: 384px) 100vw, 384px\" \/><\/a><p id=\"caption-attachment-153\" class=\"wp-caption-text\">The cross view of the cubemap for the Miner&#8217;s Lamp<\/p><\/div>\n<p>Next, open AMD CubeMapGen.<\/p>\n<p>The interface of this tool is filled with a lot of buttons and it is a bit confusing.<\/p>\n<div id=\"attachment_168\" style=\"width: 1050px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/CubeMapGen.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-168\" class=\"wp-image-168 size-full\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/CubeMapGen.png\" alt=\"\" width=\"1040\" height=\"806\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/CubeMapGen.png 1040w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/CubeMapGen-300x233.png 300w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/CubeMapGen-768x595.png 768w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/CubeMapGen-800x620.png 800w\" sizes=\"auto, (max-width: 1040px) 100vw, 1040px\" \/><\/a><p id=\"caption-attachment-168\" class=\"wp-caption-text\">The CubeMapGen interface<\/p><\/div>\n<p>Select the &#8220;Load Cube Cross&#8221; button near the top of the panel on the right, and open the cube cross file.<\/p>\n<p>Wait for a few moments for it to load.<br \/>\nNear the bottom of the panel, there is an Output Cube Size setting; configure that to an appropriate size.\u00a0 Small sizes (such as 128) might be sufficient for simple shapes, though you may need to go higher if the shape has a lot of round edges.\u00a0 I chose 512 for the lamp model.<\/p>\n<p>Select &#8220;Save CubeMap (.dds)&#8221;, pick a filename, and save the resulting DDS file, ready to be imported into Unreal.<\/p>\n<p>Leave CubeMapGen open for now, as you&#8217;ll need it again later.<\/p>\n<p>&nbsp;<\/p>\n<h2>Setting up the basic light function in Unreal Engine<\/h2>\n<p>Open Unreal, import the cubemap dds, and then create a new Material for the light function.<\/p>\n<p>On the Details panel, change the Material Domain to Light Function.\u00a0 A light function material only has one pin &#8211; for Emissive Colour.<\/p>\n<p>Create a Texture Sample, select the cube map texture, and drag the output into the Emissive Colour on the material.<\/p>\n<p>Create a Light Vector node.\u00a0 This gives the coordinates of the light, and will be used to feed into the UV of the texture sample.<br \/>\nHowever, it appears to always be mis-rotated by 90\u00b0, so create an MF_RotateVector_90 node.<br \/>\nHook the Light Vector Node into its input, and hook its output CW Y into the UVs of the texture sampler.<\/p>\n<p>The completed material should look something like this:<\/p>\n<div id=\"attachment_155\" style=\"width: 810px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LightFunctionSimple.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-155\" class=\"wp-image-155 size-large\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LightFunctionSimple-800x441.png\" alt=\"\" width=\"800\" height=\"441\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LightFunctionSimple-800x441.png 800w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LightFunctionSimple-300x165.png 300w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LightFunctionSimple-768x423.png 768w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/LightFunctionSimple.png 828w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><p id=\"caption-attachment-155\" class=\"wp-caption-text\">Simple light function material<\/p><\/div>\n<p>The next step is to set up the lamp&#8217;s blueprint.<\/p>\n<p>Add a Static Mesh component for the lamp, and create a point light under it, with the appropriate parent socket.<br \/>\nOn the Point Light, scroll down the properties panel to the Light Function section, and select the newly created material as the Light Function Material.<br \/>\nThe rest of the properties don&#8217;t matter for this effect, though you might want to adjust the intensity, attenuation radius, and possibly turn on Ray Traced Distance Field Shadows.<\/p>\n<p>To make sure that the engine shadows don&#8217;t interfere with the fake, masked ones, make sure to turn Casts Shadows off on the lamp mesh.<br \/>\n(This does, unfortunately mean that no other light source will be to cast shadows of the lamp, but that should be fine in most cases.\u00a0 You may want to toggle the shadow casting back on at any time that the lamp is turned off.)<\/p>\n<div id=\"attachment_157\" style=\"width: 810px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SimpleLightFunctionShadows.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-157\" class=\"wp-image-157 size-large\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SimpleLightFunctionShadows-800x368.jpg\" alt=\"\" width=\"800\" height=\"368\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SimpleLightFunctionShadows-800x368.jpg 800w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SimpleLightFunctionShadows-300x138.jpg 300w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SimpleLightFunctionShadows-768x354.jpg 768w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/10\/SimpleLightFunctionShadows.jpg 1099w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><p id=\"caption-attachment-157\" class=\"wp-caption-text\">The &#8220;shadows&#8221; cast by the simple light function, as they appear in-game.<\/p><\/div>\n<p>Here is the effect in-game.\u00a0 Notice how the cast shadow is very sharp and harsh.<\/p>\n<p>There are two issues here.<\/p>\n<p>The first\u00a0 is that the shadows remain extremely crisp, with hard edges, regardless of the distance.\u00a0 Those shadows should get softer and less defined the farther away from the light they are.<\/p>\n<p>The second is that the shadowed areas are pitch black.\u00a0 Realistically, there&#8217;d be enough light scatter from the surrounding surfaces to provide at least some illumination even in places that are obscured by the shadows.<\/p>\n<p>We&#8217;ll deal with the sharp shadows first.<br \/>\nThe idea here is to fade between two different cube maps based on the distance from the light, so that the shadows close to the light will be sharp, while those farther away will be much softer.<\/p>\n<h2>Creating a second cubemap to use at farther distances<\/h2>\n<p>Switch back to CubeMapGen, with the cube cross we created earlier loaded.<br \/>\nThe blue part of the control interface is used to apply a filter to the cubemap.<\/p>\n<p>Under Filter Type, select Gaussian to apply a Gaussian blur.<br \/>\nThe Base Filter Angle is the amount of blur to apply.\u00a0 You will probably need to play around with this value to get the exact effect that you want.\u00a0 10 is a good starting point.<br \/>\nClick the &#8220;Filter Cubemap&#8221; button near the bottom of the interface to apply the blur.\u00a0 Note that it will take several seconds to process (or minutes, depending on the level of blur and the size of the map), as indicated by the text at the top-left corner.\u00a0 The map shown in the display will be incomplete until it has finished.<\/p>\n<div id=\"attachment_166\" style=\"width: 394px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLamp_cubecross2.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-166\" class=\"wp-image-166 size-full\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLamp_cubecross2.jpg\" alt=\"\" width=\"384\" height=\"512\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLamp_cubecross2.jpg 384w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/MinerLamp_cubecross2-225x300.jpg 225w\" sizes=\"auto, (max-width: 384px) 100vw, 384px\" \/><\/a><p id=\"caption-attachment-166\" class=\"wp-caption-text\">The cross view of the blurred cubemap for the Miner&#8217;s Lamp<\/p><\/div>\n<p>Once you are happy with the level of blur, save this second cube map as .dds.<\/p>\n<p>&nbsp;<\/p>\n<h2>Adding a distance-based blend to the second cubemap<\/h2>\n<p>To set up the distance-based facing, first import the second cube map into Unreal, and then go to edit the material we created earlier.<\/p>\n<p>Add a second Texture Sample using the new cubemap, and plug the same wire (the rotation of the light vector) into the UVs of this one as well.<\/p>\n<p>Add three Scalar Parameters and name them LightRadius, NearDistance, and FarDistance.<br \/>\nThe light function only has access to the distance of the surface being struck as a range between 0 and 1, where 1 represents the maximum attenuation radius of the light source.\u00a0 In order to convert that into an actual distance, the LightRadius will need to be passed into the material.<br \/>\nThe other two parameters are to allow the distances to be adjusted; anything below NearDistance will use purely the first (sharp) cubemap, while anything beyond FarDistance will use purely the second (blurred) cubemap, with anything between the two points using an appropriate fade between the two.<\/p>\n<p>The suggested default values are:<\/p>\n<ul>\n<li>LightRadius: 1000<\/li>\n<li>NearDistance: 100<\/li>\n<li>FarDistance: 500<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>To set up the fading, grab the CW Y output of the MF_RotateVector_90, and plug it into a VectorLength node (use the V3 pins).<\/p>\n<p>Then, set up the following sequence of mathematical operations:<\/p>\n<pre style=\"padding-left: 30px;\">((VectorV3Length * LightRadius) - NearDistance) \/ (FarDistance - NearDistance)<\/pre>\n<p>And then clamp the result to the range 0 &#8211; 1.<\/p>\n<p>Finally, create a Lerp node between the sharp cubemap (A) and the blurred cubemap (B), using the result of the previous clamp as the alpha.<\/p>\n<p>The result should look something like this:<\/p>\n<div id=\"attachment_163\" style=\"width: 810px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel2.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-163\" class=\"wp-image-163 size-large\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel2-800x320.png\" alt=\"\" width=\"800\" height=\"320\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel2-800x320.png 800w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel2-300x120.png 300w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel2-768x307.png 768w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel2.png 1745w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><p id=\"caption-attachment-163\" class=\"wp-caption-text\">Light function material with distance-based fading between sharp and blurred textures<\/p><\/div>\n<p>There&#8217;s one last step, which is to configure the lamp&#8217;s blueprint to push the radius of its light down into an instance of the material.<\/p>\n<p>Set up the Construction Script of the blueprint to create a dynamic material instance of the light function, set its LightFunction parameter base on the light&#8217;s attenuation radius, and then apply it as the light function to the light.<\/p>\n<div id=\"attachment_161\" style=\"width: 810px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/BlueprintForLightFunctionMaterial.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-161\" class=\"wp-image-161 size-large\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/BlueprintForLightFunctionMaterial-800x276.png\" alt=\"\" width=\"800\" height=\"276\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/BlueprintForLightFunctionMaterial-800x276.png 800w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/BlueprintForLightFunctionMaterial-300x104.png 300w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/BlueprintForLightFunctionMaterial-768x265.png 768w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/BlueprintForLightFunctionMaterial.png 1364w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><p id=\"caption-attachment-161\" class=\"wp-caption-text\">Construction script for lamp blueprint<\/p><\/div>\n<p>&nbsp;<\/p>\n<h2>Dealing with the dark shadows<\/h2>\n<p>The shadowed areas are still pitch black, which is easily fixed by applying a floor of light to the light function.<\/p>\n<p>Create two new ScalarParameters and name them NearMinimumLight and FarMinimumLight.<br \/>\nHook them up so that they are added to the output of the two texture samples before they are put into the Lerp node.<\/p>\n<p>Suggested default values are:<\/p>\n<p>NearMinimumLight: 0.01<br \/>\nFarMinimumLight: 0.10<\/p>\n<p>The final graph should look something like this:<\/p>\n<div id=\"attachment_164\" style=\"width: 810px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel3.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-164\" class=\"wp-image-164 size-large\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel3-800x320.png\" alt=\"\" width=\"800\" height=\"320\" srcset=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel3-800x320.png 800w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel3-300x120.png 300w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel3-768x307.png 768w, https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionLevel3.png 1745w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><p id=\"caption-attachment-164\" class=\"wp-caption-text\">Final light function, with distance-based fading between sharp and blurred, and minimum light levels for shadows<\/p><\/div>\n<p>&nbsp;<\/p>\n<h2>The result<\/h2>\n<p>The final effect, in game, should look like this:<\/p>\n<div style=\"width: 1142px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-145-1\" width=\"1142\" height=\"494\" loop autoplay preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionMinerLamp.mp4?_=1\" \/><a href=\"https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionMinerLamp.mp4\">https:\/\/blog.nameless.zanity.net\/wp-content\/uploads\/2018\/11\/LightFunctionMinerLamp.mp4<\/a><\/video><\/div>\n","protected":false},"excerpt":{"rendered":"<p>The goal of this tutorial is to set up a lantern object which casts soft dynamic shadows from the solid parts of the lantern. The two normal ways of creating detailed shadows are to either bake them with static lights (which will not work for a moveable light source), or to use Raytraced Distance Field [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-145","post","type-post","status-publish","format-standard","hentry","category-unreal-engine-4"],"_links":{"self":[{"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=\/wp\/v2\/posts\/145","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=145"}],"version-history":[{"count":22,"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=\/wp\/v2\/posts\/145\/revisions"}],"predecessor-version":[{"id":216,"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=\/wp\/v2\/posts\/145\/revisions\/216"}],"wp:attachment":[{"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=145"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.nameless.zanity.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}