engine
engine copied to clipboard
Physically based light units
Description
Enables the use of physically based light units, by having the physicalUnits enabled on the scene, and setting the luminance (not intensity) parameter on the lights. For spot lights, this also means the strength of the light is dependent on the aperture (outer cone angle), meaning a narrower angle will concentrate its energy on a smaller surface, thus making that area brighter than if it was using a wide angle.
Also contains an example scene showing off physically based light and camera units in a typical scene with a strong sun, sky and a bunch of local lights, called Physical Light Units.
Also fixes support for KHR_punctual_lights where we previously clamped the light intensity.
https://user-images.githubusercontent.com/107400752/188444600-e33f3b28-ec5e-4957-9af6-b04385188f50.mp4
https://user-images.githubusercontent.com/107400752/188445670-17451c9f-35cb-452c-b53f-32888acadabf.mp4
This is fantastic! As a light unit layman I noticed that punctual lights uses candela (lm/sr) but we're using lm here as the unit type. is that correct? what needs to be done as a user to get consistent results?
@MAG-AdrianMeredith We support point lights in lumen. However, you can always write a converter candela -> lumen and feed that value instead. I thought we might want to write a few converters as well, so you'd be able to basically feed whatever value you'd like and you'd get back a value with the units we are using, would that be useful?
Thanks for the update, I'm just wondering what the reason is for not following gltf's definition of lights seems to be a pretty common definition for light intensities https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/README.md
@MAG-AdrianMeredith Ah, so from my understanding, glTF provides light intensities in candela because it represents luminous power per solid angle. From a user perspective, using candela makes little sense since you set the luminous power and either have a point/omni light, for which the angle is a fixed 4 PI, or use a spot light with explicit cone angles.
However, in the glTF, the lights angles are already known, so they can pre calculate that value and therefore provide the implementor with those fixed values. I hope that makes sense 🙂 .
@querielo I implemented your suggestion, huge thanks for all the legwork there! To test it, I used a spot light with a 0 inner angle and 90 degree outer angle, which when having the same luminous power as 1/4 of a point light gave identical light intensity, which makes a lot of sense since a point light could be conceptualised as having 4 x 90 degree spot lights in terms of energy per square meter.
@GSterbrant So its just a terminology thing and they should line up (given similar camera setup) great thats what I thought.
One question, how does IBL and lightmaps fit into this equation? I'm currently testing against this PR in a fork (I've been tasking with supporting physical light units for a project if you haven't noticed already ;) ). Currently enabling this plunges everything into complete darkness (including the gltf_punctual_lights) and boosting the skyboxIntensity settings produces a strange result where it looks like only the specular component is lit.
setting the aperture to 0.05 seems to produce a similar result but is obviously not physically accurate
I'm assuming this is just because its not done yet?
p.s. great work as always everyone
@MAG-AdrianMeredith In this PR, I would suggest the lights-physical-units example which shows off a scene using the GLB with punctual lights and all that. That GLB does have very weak lights, you need to reduce the strength of the IBL, sun, spot, point and area light and turn the exposure settings up to see it.
Would it be possible to post a picture showing off the issues you're seeing?
It seems to me that the default camera sensitivity is two orders of magnitude out from what you'd expect. From what I can see a really bright bulb is around 1000 lumens. in the default settings this wont even cast any light and the example is set to 100000 and is still really dim.
@MAG-AdrianMeredith The default camera settings are adjusted for outdoors lighting like the sun and sky. In proportion to the sun at around 100k-120k lm/m^2, a 100W light bulb is something like 1100/4*PI = 91.6 lm/m^2 given no attenuation, so it makes sense that those settings are poorly adjusted for indoor lighting.
I found this link giving a list of approximate lux (lm/m^2) readings: https://en.wikipedia.org/wiki/Lux.
@MAG-AdrianMeredith So we will definitely need to implement automatic exposure correction to adjust for what I just mentioned. That's going to be a separate PR though 🙂, for which we created this issue: #4650.
Just a note here, that the clustered lights store light colors in 2 bytes per channel (so not full floats). So for physical lights, where the color range is really large, this would mean a pretty low precision. But I suspect in reality this could be just fine.
I added few minor comments. And also:
- search for skyboxIntensity in app-base.js and apply the same to skyboxLuminosity
- in the scene, we have skyboxLuminosity. Do we need some physical treatment of the ambientLight, which is used when the skydome is not set up? ambientLightLuminosity?
One more suggestion. It'd be great to check if the lightmapping tech works with physical lights. Perhaps locally modify the lights-baked-a-o example to use physical lights and see if that works correctly.
Thanks everyone for the comments and help!
This is soooo cool. Can you be explicit about what new API is introduced in the PR description, please?