Difference between revisions of "Point Light Attenuation"

From Bakery GPU Lightmapper: Wiki
Jump to navigation Jump to search
(Explanation)
 
(21 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
= Explanation =
 
= Explanation =
 
[[File:Falloff graph.png|thumb|Comparison of different falloff curves]]
 
[[File:Falloff graph.png|thumb|Comparison of different falloff curves]]
 +
[[File:Falloff comp.png|thumb|Perceptual comparison. Range = 20. Light intensity is set to 1 for Unity and 20 for Bakery to make them look as close as possible. Bottom row is tonemapped to compress bright values.]]
 +
[[File:Image8.png|thumb|Effect of Light Range on falloff.<br>Top: Unity (scales).<br>Bottom: Bakery/HDRP/Frostbite/etc (fades slightly).]]
 
In real world, lighting attenuation is governed by the [https://en.wikipedia.org/wiki/Inverse-square_law inverse-square law]:
 
In real world, lighting attenuation is governed by the [https://en.wikipedia.org/wiki/Inverse-square_law inverse-square law]:
 
[[File:Falloff ph.png]]
 
[[File:Falloff ph.png]]
Line 7: Line 9:
  
 
There are multiple ways to solve it.
 
There are multiple ways to solve it.
 
+
<hr>
'''Standard Unity rendering pipeline''' uses a completely fake falloff curve that looks similar to this:
+
'''Standard Unity rendering pipeline''' uses a fake falloff curve that looks similar to this:
 
[[File:Falloff unity.png]]
 
[[File:Falloff unity.png]]
  
 
r = Light Range
 
r = Light Range
  
This is an arbitrary hand-tweaked function. It has a nice property of being exactly 1 in the center, but its falloff is basically always locked and distance-independent. It simply scales the same gradient based on Range parameter. That allowed Unity to even store it inside a texture. A 8-bit texture unfortunately, that also lacks precision and produces visible banding when rendering with gamma correction.
+
This is an arbitrary hand-tweaked function. It does in fact resemble the inverse square curve, except fixed at distance of 5 and then scaled based on Range parameter. It has a nice property of being exactly 1 in the center. Scaling the same gradient allowed Unity to even store it inside a texture. A 8-bit texture unfortunately, that also lacks precision and produces visible banding when rendering with gamma correction.
 
+
<hr>
 
'''Bakery's "physical falloff"''' defaulted to a different formula:
 
'''Bakery's "physical falloff"''' defaulted to a different formula:
 
[[File:Falloff bakery legacy.png]]
 
[[File:Falloff bakery legacy.png]]
  
This function tries to combine best of both worlds, by having 1 at center and falling off exponentially. A similar function is also used in [https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Shaders/Private/DynamicLightingCommon.ush#L64 UE4] (you need access to UE4 github repository to open that link).
+
As Unity, it also has the "+1" part to replace infinity with 1, but its range is unlimited and falls off based on distance. A similar function is also used in [https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Shaders/Private/DynamicLightingCommon.ush#L64 UE4] (you need access to UE4 github repository to open that link).
 
 
However, the "1" constant in this case is arbitrary and will look different depending on scene size/units.
 
  
'''Frostbite and HDRP''' use almost unfiltered inverse-square falloff, but clamp it to prevent dividing by zero ([https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf paper]):  
+
However, the "1" constant is still arbitrary and will look different depending on scene size/units.
 +
<hr>
 +
'''Frostbite and HDRP''' use almost unfiltered inverse-square falloff, but clamp it to prevent dividing by zero:  
 
[[File:Falloff hdrp.png]]
 
[[File:Falloff hdrp.png]]
  
 
s = Light Size
 
s = Light Size
 +
 +
[https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf Frostbite paper]
  
 
In both of these renderers, light size is hardcoded to be 0.01 (1cm), which means brightest value of the untinted light is 10000.
 
In both of these renderers, light size is hardcoded to be 0.01 (1cm), which means brightest value of the untinted light is 10000.
 +
<hr>
 +
Bakery now has an option called '''Falloff min size'''. This is exactly the Light Size used in HDRP/Frostbite formula. With this parameter, new Bakery falloff looks like that:
 +
[[File:Falloff bakery.png]]
 +
 +
With Light Size being 0.01, it looks similar to HDRP formula, except instead of clamping it will slightly rescale the curve. With a value of 1 it works like the original Bakery falloff.
 +
  
Today Bakery has a new option called '''Falloff min size'''. This is exactly the Light Size used in HDRP/Frostbite formula. With this parameter, new Bakery falloff looks like that:
+
{{note|Note that all mentioned renderers also include an additional range-based masking to slightly fade lighting away near the limit, as this is necessary for performance. But if range is set adequately to only kick in where the original falloff is dim, its effect is perceptually negligible}}
[[File:Falloff bakery.png]]
 
  
With Light Size being 0.01, it looks similar to HDRP formula. With a value of 1 it works like the original Bakery falloff.
+
{{note|Keep in mind that physical falloff is not scaled with Range, but mainly influenced by light’s brightness. It is highly recommended to enable tonemapper when using it.}}
  
 
= What value should I use? =
 
= What value should I use? =
 
When matching Bakery light to a HDRP light, Faloff min size will be automatically set to 0.01 to look identical.
 
When matching Bakery light to a HDRP light, Faloff min size will be automatically set to 0.01 to look identical.
This value makes sense if your point light does indeed represent a 1cm emissive surface. However, there are cases when you'd better set it to a higher value:
+
This value makes sense if your point light does indeed represent a 1cm emissive surface. However, there are cases when you can set it to a higher value:
 
* When literally using point lights for larger surfaces (e.g. lamp of a traffic light).
 
* When literally using point lights for larger surfaces (e.g. lamp of a traffic light).
 
* When building for mobile platforms where lightmap compression is limited and cannot represent extremely bright values well; or tonemapping not possible.
 
* When building for mobile platforms where lightmap compression is limited and cannot represent extremely bright values well; or tonemapping not possible.

Latest revision as of 08:07, 24 October 2019

Explanation

Comparison of different falloff curves
Perceptual comparison. Range = 20. Light intensity is set to 1 for Unity and 20 for Bakery to make them look as close as possible. Bottom row is tonemapped to compress bright values.
Effect of Light Range on falloff.
Top: Unity (scales).
Bottom: Bakery/HDRP/Frostbite/etc (fades slightly).

In real world, lighting attenuation is governed by the inverse-square law: Falloff ph.png

However, in computer graphics things are a little trickier. Inverse-square law works for real lights because they have area, hence the projection of this area on receiver geometry gets exponentially smaller with distance. Point lights are an approximation and using the law on them produces one obvious problem: as distance approaches zero, lighting intensity approaches infinity.

There are multiple ways to solve it.


Standard Unity rendering pipeline uses a fake falloff curve that looks similar to this: Falloff unity.png

r = Light Range

This is an arbitrary hand-tweaked function. It does in fact resemble the inverse square curve, except fixed at distance of 5 and then scaled based on Range parameter. It has a nice property of being exactly 1 in the center. Scaling the same gradient allowed Unity to even store it inside a texture. A 8-bit texture unfortunately, that also lacks precision and produces visible banding when rendering with gamma correction.


Bakery's "physical falloff" defaulted to a different formula: Falloff bakery legacy.png

As Unity, it also has the "+1" part to replace infinity with 1, but its range is unlimited and falls off based on distance. A similar function is also used in UE4 (you need access to UE4 github repository to open that link).

However, the "1" constant is still arbitrary and will look different depending on scene size/units.


Frostbite and HDRP use almost unfiltered inverse-square falloff, but clamp it to prevent dividing by zero: Falloff hdrp.png

s = Light Size

Frostbite paper

In both of these renderers, light size is hardcoded to be 0.01 (1cm), which means brightest value of the untinted light is 10000.


Bakery now has an option called Falloff min size. This is exactly the Light Size used in HDRP/Frostbite formula. With this parameter, new Bakery falloff looks like that: Falloff bakery.png

With Light Size being 0.01, it looks similar to HDRP formula, except instead of clamping it will slightly rescale the curve. With a value of 1 it works like the original Bakery falloff.


Bulbgraph.pngNote that all mentioned renderers also include an additional range-based masking to slightly fade lighting away near the limit, as this is necessary for performance. But if range is set adequately to only kick in where the original falloff is dim, its effect is perceptually negligible
Bulbgraph.pngKeep in mind that physical falloff is not scaled with Range, but mainly influenced by light’s brightness. It is highly recommended to enable tonemapper when using it.

What value should I use?

When matching Bakery light to a HDRP light, Faloff min size will be automatically set to 0.01 to look identical. This value makes sense if your point light does indeed represent a 1cm emissive surface. However, there are cases when you can set it to a higher value:

  • When literally using point lights for larger surfaces (e.g. lamp of a traffic light).
  • When building for mobile platforms where lightmap compression is limited and cannot represent extremely bright values well; or tonemapping not possible.