Applying a texture to an object is relatively simple because UV coordinates can be used to project the texture’s pixels onto the object’s surface. The UV coordinates may not be inherently good and your textures may stretch horribly but Stingray knows how to use this information with ease. The challenge with light-based materials is they are based on light sources, which do not have UV coordinates.
Specific to light-based materials, the Light Vector node provides information on the light’s direction as a normalized vector in world space. We need XY values to map our texture as though it was on a canvas, but the Light Vector node only gives us vectors with directions and forces coming out of a single point. What we need is a way to take these outgoing vectors and project them back onto our imaginary canvas. To do that, we can use Dot Product and Construct nodes.
The Dot Product node returns a numeric value equal to the magnitude of the two vectors multiplied together, and then multiplied by the cosine of the angle between them. By making a dot product of the light vectors by the Right axis, all the vectors flatten and align perpendicular to the light’s orientation. This line of values maps each of the vectors to an imaginary X axis, constituting the U in our UV coordinates. We have to repeat the same process with the Up axis to define the Y axis (V in our UV coordinates). Next, we have to use the Construct node to combine the two, creating Vector2.
Let’s add a hardcoded offset to our UV coordinate to make sure it is centered in our light.
We then have to restrain the UV values between 0 and 1 with a Clamp node. This prevents the texture from tiling. Not doing so will make our mask repeat all around the light source and ruin the single IES light effect we’re looking for. Plug this entire operation chain into a sample texture’s UV parameter the texture will accurately project as the light’s intensity.
Directly connecting the texture to the light base material’s Light Color property will make a very weak light since it overrides not only its color but also its intensity. To fix the issue, we can simply multiply our texture by the Light Color node before connecting it to the property.
At this point, the material can be used as is, but let's add one last step to give us a little more control.
By dividing the light vector by a set value at the very start of the whole operations chain, we can control the size of our resulting texture. Ideally, we would control this parameter with the spotlight’s angle falloff but we can’t access that information inside the Shader Graph Editor.
Now that we better understand the logic behind the series of operations required to map a texture to a light’s projection and how to access a light’s properties, we can use them to create better effects.