Description
Describe the project you are working on:
The Godot engine. :)
Describe the problem or limitation you are having in your project:
The renderer is currently using arbitrary light units and a user-specified light falloff curve together with an energy multiplier. While this is fine for many use-cases, it makes it very difficult for users to specify physically plausible light values, and it makes it nearly impossible to export a scene from Blender and match the light values.
Describe the feature / enhancement and how it helps to overcome the problem or limitation:
I propose we add a method for switching between arbitrary units and physical units for lights. This could be in a ProjectSetting, or it could be a toggle within the light itself.
The ability to specify physical light values makes it significantly easier to light scenes realistically. For example, standard 45/60 watt household light bulbs produce about 1200 lumens. If the engine works in physical light quanities, users could create an OmniLight3D with 1200 lumens and an appropriate size and then expect it to light up a room-sized room accurately and in a physical plausible way. The current system involves a lot of tweaking and hacks and still may look wrong.
I further propose that we use inverse square falloff with a user tweakable linear falloff curve. Proper inverse square falloff is needed for lights to look realistic and the linear falloff is still needed because, for efficiency, game engines need to limit the distances that lights can project. Falloff could be specified with a Curve resource that is baked into a texture.
Note: other engines are moving towards using physical light units. Unreal and Unity HDRP use Lux and Candela/Lumens; Unreal, Unity HDRP, and Cryengine use inverse square falloff. Blender users inverse square falloff as well, but it uses watts instead of lumens.
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
This proposal would change the UI of Light3D derived nodes to allow switching between Godot units and physical units. DirectionalLight3Ds would use lux (intensity over a square meter of receiving surface), while SpotLight3D and PointLight3D would use lumens/candela (intensity of light source in all directions). If possible, we would just remap these values into Godot units and only use Godot units internally.
Further, this proposal would change the current attenuation parameters for SpotLight3D and OmniLight3D to a curve resource that allows finer artistic control over the falloff curve. We could either default to inverse square falloff, and then replace by the curve when the curve is specified, or we could apply the curve over the inverse square falloff. Internally, We can store an array of falloff curves as they will all be the same dimension (1024x1) and then index them in the shader, making them easy to use and fast to run
If this enhancement will not be used often, can it be worked around with a few lines of script?:
It can't be worked around in script.
Is there a reason why this should be core and not an add-on in the asset library?:
The conversion from lux/luminance to Godot units could be done in an editor-plugin, however, the falloff curve is embedded deep inside the scene shaders. In order to support both properly, we need to edit the engine itself.
User questions
- Would it be preferable to only use physcial light units and remove Godot units altogether?
- Do users prefer a ProjectSetting, or a setting on a per-light basis?