Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for physical light quantity (lumens/lux) #723

Closed
clayjohn opened this issue Apr 17, 2020 · 20 comments
Closed

Implement support for physical light quantity (lumens/lux) #723

clayjohn opened this issue Apr 17, 2020 · 20 comments

Comments

@clayjohn
Copy link
Member

clayjohn commented Apr 17, 2020

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
  1. Would it be preferable to only use physcial light units and remove Godot units altogether?
  2. Do users prefer a ProjectSetting, or a setting on a per-light basis?
@reduz
Copy link
Member

reduz commented Apr 17, 2020

My views on this:

  • All game engines and Blender making this a standard (Although Blender is weird and uses Watts instead of Lux, but we can convert). I think it should be ideal if we use a light model compatible with Blender, so eventually scenes can be lit in Blender and exported in Godot. Artists would greatly appreciate this.
  • For backwards compatibility, we can detect scenes using the old attenuation curves and convert them to a custom curve.

Answering questions:

  • We could probably default to physical light units. If you want to specify a custom falloff curve, then you can do anything you want there.
  • Light curve should be selectable per light.

@reduz
Copy link
Member

reduz commented Apr 17, 2020

Some more points: physical light computation can be complex for a lot of users that don't want to work with realistic 3D, and we should not force it (and probably not force it by default). As such, I suggest we have a "light_units" with two selectable modes in the project setting:

  • Normalized
  • Physical

For Normalized it should be about the same we have now, where lights have a simple "energy" value that is just a multiplier, and the camera exposure multiplier is just a single number.
For Physical we use lux/lumen/etc. and physical camera exposure settings. Both are available as property, but the editor only exposes the one in the current mode.

@reduz
Copy link
Member

reduz commented Apr 17, 2020

Additionally, some effects like Bokeh and Bloom I don't believe it's a good idea to do them in a physically correct way. We should expose them instead in the way they offer more artistic freedom, even if the result can be unrealistic.

@VicentGJ
Copy link

Some more points: physical light computation can be complex for a lot of users that don't want to work with realistic 3D, and we should not force it (and probably not force it by default). As such, I suggest we have a "light_units" with two selectable modes in the project setting:

  • Normalized
  • Physical

For Normalized it should be about the same we have now, where lights have a simple "energy" value that is just a multiplier, and the camera exposure multiplier is just a single number.
For Physical we use lux/lumen/etc. and physical camera exposure settings. Both are available as property, but the editor only exposes the one in the current mode.

What of those light modes you suggest to be the default one?

@reduz
Copy link
Member

reduz commented Apr 17, 2020

@VicentGJ definitely normalized

@Cykyrios
Copy link

Some more points: physical light computation can be complex for a lot of users that don't want to work with realistic 3D, and we should not force it (and probably not force it by default). As such, I suggest we have a "light_units" with two selectable modes in the project setting:

* Normalized

* Physical

For Normalized it should be about the same we have now, where lights have a simple "energy" value that is just a multiplier, and the camera exposure multiplier is just a single number.
For Physical we use lux/lumen/etc. and physical camera exposure settings. Both are available as property, but the editor only exposes the one in the current mode.

I agree with all the points you made, except normalized units being the default. The reason for that is that units are not displayed in the editor (one distance unit is supposed to correspond to one meter, although this is not displayed). That would mean units for lights would not be displayed either, and the only difference between physical and normalized would be the falloff and actual numbers used in the light parameters.
From the user's point of view, they would just have to tweak the values to get the lighting they want, so I believe it would make more sense to have physical units as default (even if that means you would need a value of several thousands to match the current Energy = 1, sensible defaults for room scale would be needed).

@rubenjavier
Copy link

Love the idea.
I would also choose the physical model by default and make it work with watts, this way the numbers are lower (45 - 120) and its more compatible with Blender... ideally you could also choose if you want lumens/lux or watts, for those that come from other engines or architecture, also in case Blender ever upgrade its settings and add lumens/lux, wich in OSS is very possible for someone to add it

@1abinitio1
Copy link

When in the editor, you could add an option to display light units in Ev100.
Unity did this so you can avoid having giant numbers when setting the light intensity.
Not sure what Ev100 actually is, but in practice it works the same way as decibels.
(the difference between 10-20 is much smaller that the difference 100-110)

@DarkKilauea
Copy link

I'd actually like to make a case for Physical being the default mode here.

When I'm lighting scenes, I usually like to start with looking up similar light sources on the internet, then using those values in my lights in my scene. This allows me to get a realistic look quickly, which I can then adjust to get the look I'm going for.

Right now, I can't really do that in Godot, leading me to blindly adjust "knobs" until I get the look I'm going for.

So, that answers why the feature should exist, why then should it be the default? For new game developers (like myself) it would be helpful to have units that we can reference to get a good result quickly, especially since we haven't acquired a good feel for the normalized values yet. It would also help developers from other game engines, like Unity and Unreal, to migrate over to Godot. Having new users have to know to go in and flip a switch in order to get the lights to work in a physical manner is one more barrier to trying out the engine that doesn't need to be there. It also lines up better with modeling programs, which seem to be switching over to a more physically correct model for lighting. Having the model match by default will reduce surprises when porting scenes into the engine.

For existing projects, the system should default to Normalized mode for backwards compatibility. Existing users can then migrate over their lights over time if they'd like.

@lawnjelly
Copy link
Member

Kostas Anagnostou's blog post here is quite relevant, in terms of falloff and physical units and validating with mitsuba:
https://interplayoflight.wordpress.com/2020/04/19/validating-physical-light-units/

I know next to nothing about all this, but here are some rambling thoughts:

Point Lights and Sphere Area

As I understand it, the inverse square law is based on how the area of a sphere increases with distance:

Area = 4 * PI * (radius * radius)

So if a given 'power' of light, the Intensity at a given distance is:

I = Power / Area = Power / (4 * PI * (radius * radius))

However, there are few things that jump out:

  • What units are the radius in? If your radius is in metres, the absolute falloff will be different to cm, or km.
  • What happens below distance 1? As the distance moves to zero, the intensity moves to infinity

It might be sensible to standardise that maximum light intensity is occurring at zero distance from the light, and equals:

Power / 1.0

For this you'd equate radius 0.0 with being 0.282094791
i.e.

Area = 4 * PI * (0.282 * 0.282) = 1.0

You could add 0.282 to your game radius to achieve this.

Focused / Directional Lights

Now consider this relationship is for a very specific scenario: A point light.
A point light is assuming that light rays are travelling out in all directions equally.
However, for non point light sources, especially focused light (light a car headlight, torch or laser), this is not true.

If we consider the sun as an extreme example, and if we consider it as a point (rather than having an area):

  • Near the sun the inverse square relationship is very obvious when you look at intensity
  • Further from the sun, on the surface of a planet like earth, the light ray directions are closer to parallel
  • The light on earth becomes more what we think of as a directional light, with parallel rays.
  • Between the sky and the ground on earth, the light falloff is small, because the rays are parallel

In the same way if you consider a torch (flashlight) with focus adjusting:

  • Each position of focus the same light energy is coming from the torch
  • With a wide focus the light is spread over a greater area, the ray angles are further apart, and the falloff is quick with distance
  • with a sharp focus the light is spread over a small area, the ray angles are closer to parallel, and the falloff is low with distance : you can see the torchlight over a greater distance
  • within the beam pattern some areas will be more focused than others. If you look at the torch beam on a surface close to the light it will show relatively more of the unfocused light than when you look far away. This is presumably due to the ray directions.

All this can happen automatically in a ray tracer if you consider ray directions. However for approximations you need some other approach to take into account light focus.

An approximation

One easy approximation is this:
If we consider that the light from the sun in the atmosphere of the earth approximates a directional light (like a focused torch or laser), the important factor is that the distance in terms of inverse square is a long way from the source, and the relative distance involved between e.g. the sky and the ground area are small.

We can achieve the same kind of relationship (varying the focus), simply by varying the earlier offset we used to apply to the radius.

i.e. instead of saying our area 1.0 occurs at:

Area = 4 * PI * (0.282 * 0.282) = 1.0

We might say our 1.0 occurs at

Area = 0.01 * (10.0 * 10.0) = 1.0

I.e. at radius zero from the light source we add 10.0 to the radius, plug into the formula above and get full intensity at zero distance.
At distance 1.0 from the light source add add 10.0 to the radius, plug into the formula and we get:

Area = 0.01 * (11 * 11) = 1.21
Intensity = Power / 1.21

Thus the intensity drops at a lower rate, and we can vary between a point light and a directional light by changing both the radius offsets and the multiplier, but still guarantee that we will have full 'power' at distance 0.

This is all probably horribly wrong physically but I'm just trying to think of things that might work in a game scenario and be fast and practical. I also have done absolutely zero reading around this so there might be a much better way.

The other cool thing about this kind of technique of focused light is that you can apply it to light profiles mentioned here #715 (e.g. from a lamp shade) and use the intensity in any given direction to also approximately affect the light focus (e.g. the lighter areas can be considered more focused), and get nice volumetric variation in lighting.

@TokisanGames
Copy link

TokisanGames commented Apr 21, 2020

If physical lights were available, I'd only use them. This is like asking if you want to use the older blender internal renderer or cycles? No question about it.

As for units, watts should NOT be used. Electrical power output is not a measure of light output. Lightbulbs provide power consumption, but Blender uses "power output as light" so its not even the same as Lightbulbs. 100 watts through an incandescent, CFL, or LED lights are an order of magnitude different.

Lumens is the unit that should be used for light output. Every physical bulb sold should have this rating and it describes the perceived light output of the light. Lumens refers to photon output. Lux refers to how many lumens hit an object, so it embeds falloff. Since falloff is adjustable, lux is not a good measurement.

With physical lights I should eventually be able to save or have presets so I can define a medium hard shadow, faster falloff LED at 5600 Kelvin, a hard shadow, slow falloff 3200k incandescent, or a softer shadow, slower falloff, 4100k fluorescent.

Here's a really good overview of physically based lights in blender, and describes some important concepts and even has lumen conversion for blender's light wattage output: https://youtu.be/ipqyVWm5JmY

Edit:
Re: bokeh or bloom, artistic freedom is better than mimicking the physical reality of random lenses.

Re: per light setting, I can't imagine why one would want to mix physically based lights and digital fake lights. That's like preparing a fine meal with expensive sauces, then adding ketchup.

@rubenjavier
Copy link

@tinmanjuggernaut I didnt knew that about the watts in blender lights, in that case I change mi vote, I think it should be lumens the default physical units.
off topic but maybe also add a request on blender to add regular lumens as a unit for lights, better for standards and for a blender to godot exporter

@TokisanGames
Copy link

@rubenjavier in the video I posted Jonathan talked about a couple plugins that allow you to insert lumens directly in blender, and displays the formula conversion for blender watts to lumens, so a Godot importer could translate directly without using blender's strange units.

@mindinsomnia

This comment has been minimized.

@Calinou

This comment has been minimized.

@Calinou Calinou changed the title Physical light quantity and falloff Implement physical light quantity and falloff Jul 30, 2020
@Calinou
Copy link
Member

Calinou commented Jan 8, 2021

Physical light falloff was implemented in godotengine/godot#44941. Physical light quantity remains to be implemented, but it will probably be added to a future 4.x release rather than 4.0.

@Calinou Calinou added this to the 4.1 milestone Jan 8, 2021
@Calinou Calinou changed the title Implement physical light quantity and falloff Implement support for physical light quantity (lumens/lux) Jan 8, 2021
@timshannon
Copy link

FWIW, it looks like blender's GLTF exporter currently isn't doing the watts -> lumens conversion correctly (or at all?):

KhronosGroup/glTF-Blender-IO#564

@atirut-w
Copy link

Physical light quantity remains to be implemented

Why couldn't it be implemented alongside the physical falloff?

@Calinou
Copy link
Member

Calinou commented Aug 26, 2021

Why couldn't it be implemented alongside the physical falloff?

Physical light quantity is an entirely different concept from physical light falloff. They can (and should) be implemented independently from each other.

@Calinou
Copy link
Member

Calinou commented Mar 24, 2022

Closing in favor of #4257, which is more up-to-date on the current plans.

Edit: This proposal is now implemented in 4.0: godotengine/godot#63751

@Calinou Calinou closed this as completed Mar 24, 2022
@Calinou Calinou removed this from the 4.1 milestone Mar 24, 2022
@aaronfranke aaronfranke closed this as not planned Won't fix, can't repro, duplicate, stale Sep 18, 2022
@fire fire closed this as completed Sep 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests