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

[4.4 Beta 2] Lightmaps too dim when using directional toggle #102300

Open
ricky-daniel13 opened this issue Feb 1, 2025 · 5 comments · May be fixed by #102723, #103203 or #103204
Open

[4.4 Beta 2] Lightmaps too dim when using directional toggle #102300

ricky-daniel13 opened this issue Feb 1, 2025 · 5 comments · May be fixed by #102723, #103203 or #103204

Comments

@ricky-daniel13
Copy link

ricky-daniel13 commented Feb 1, 2025

Tested versions

  • Reproducible in v4.4.beta2.official [a013481]
  • Not reproducible in v4.3.stable.steam [77dcf97]

System information

Godot v4.4.beta2 - Windows 10 (build 19045) - Multi-window, 2 monitors - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1650 (NVIDIA; 32.0.15.6603) - AMD Ryzen 3 2200G with Radeon Vega Graphics (4 threads)

Issue description

Lightmapping static lights produces way dimmer lights when lightmapping with the "directional" option enabled. Might be a regression of pull request #95888

Before rendering lightmaps
Image

After rendering non-directional lightmaps
Image

After rendering directional lightmaps
Image

Rendering directional lightmaps in stable version 4.3
Image

Steps to reproduce

  • Open the scene "TestScene.tscn"
  • Observe the very dim baked lighting.
  • Click on the Lightmap3D node
  • Under "Data", click to replace the Light Data file, and pick "TestScene.lmbake" (A lightmap baked without the directional option)
  • Observe the almost correctly lit lighting.
  • Disable the Lightmap3D node.
  • Observe the correct lighting.
    (Instead of picking lightmaps, the user can disable the directional toggle and render the lightmap again to observe the same results)

Following this steps on the 4.3 MRP with lightmaps rendered on 4.3 lead to lightmaps without such dramatic differences between them or with the realtime lighting.

Minimal reproduction project (MRP)

4.4 beta 2 MRP:
lightmap4dot4beta2.zip
4.3 MRP:
lightmap4dot3.zip

@BlueCube3310
Copy link
Contributor

See #96114 (comment)

In summary, since 4.0 static lights are baked with a slightly incorrect factor, which makes them appear softer than intended. Before 4.4 the directional lightmaps would be baked with incorrect coefficients that caused the directional data to be too intense, so this issue wasn't noticeable. Since dev-2 the coefficients have been corrected, so this issue has become apparent

@Calinou
Copy link
Member

Calinou commented Feb 10, 2025

I tested #101141 on the MRP and it doesn't appear to resolve the issue. In fact, it introduces another visual issue:

4.4.beta3

Image

PR #101141

Lots of NaN pixels… I've also tried to clear LightmapGIData and bake again to no avail. The issue disappears if you bake with Directional disabled.

Image

With EXR imported as Lossless

Just to show that this isn't caused by VRAM compression.

Image

@Rudolph-B
Copy link
Contributor

There is effectively 2 parts to the problem.

The first is that attenuation based on the angle to the surface normal happen twice. The first time is in trace_direct_light() in lm_compute.glsl when creating the lightmap and then again when sampling the light map in scene_forward_clustered.glsl (Or equivalent for the specific renderer).

Fixing this results in to little attenuation and lights being to bright as can be seen below:

Dynamic Double attenuation Single attenuation Sqrt attenuation #102723
Image Image Image Image

This is caused by L1 spherical harmonics not really being capable of simulating light3D nodes. This is the second problem. This is mostly do to the L0 constant term and only sampling from the upper hemisphere. Relevant code:

ambient_light += lm_light_l0 * en;
ambient_light += lm_light_l1n1 * n.y * (lm_light_l0 * en * 4.0);
ambient_light += lm_light_l1_0 * n.z * (lm_light_l0 * en * 4.0);
ambient_light += lm_light_l1p1 * n.x * (lm_light_l0 * en * 4.0);

In 4.3 we got around this problem by having large SH coefficients, this caused other problems that were fixed in #95888. Tampering with the coefficients would run into similar problems.

Currently I think the best solution we have for 4.4 is to add a warning when people are trying to bake light3D nodes with the directional setting. This warning should state something along the lines of that baking light sources using directional settng is unintended. This at least won't risk breaking any other lighting and I believe to be true since the math doesn't really support it.

Additionally to this we could add square root attenuation (#102723) for when people ignore the warning. This has no basis in math or literature that I could find, but would just result in a bit more visually pleasing lighting while having little impact on the other scenes:

Type Current Sqrt
Static Image Image
Dynamic Image Image

Made using: sh-lightmaps.zip from #96114

@clayjohn
Copy link
Member

clayjohn commented Feb 20, 2025

@Rudolph-B I think the solution might be in https://www.ppsloan.org/publications/StupidSH36.pdf (the "Analytic Models" section on page 10)

I think we are mixing methods for calculating the SH. A lot of our method resembles the way for calculating SH using Monte Carlo estimation over a sphere/hemisphere. But we don't calculate lighting over a sphere/hemisphere, we use analytic calculations for each light type. So I think the SH calculation needs to be adjusted to account for that

also see page 45+ of https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/gdc2018-precomputedgiobalilluminationinfrostbite.pdf

@Rudolph-B
Copy link
Contributor

Rudolph-B commented Feb 23, 2025

@clayjohn I think you are correct we are mixing methods. We would need to handle directly encoding lights a bit differently. The method in StupidSH36 is for lights with an area, where as we us point lights.

I believe the correct coefficients for direct point lights would be L0 = 0 and L1 = 1.0. The resulting math ends up being indistinguishable from the dot product used in trace_direct_light(). This can be seen below:

Dynamic Non-Directional Directional (L1 packing disabled)
Image Image Image

Using two separate sets of SH coefficients would require us to reassess how we do L1 packing. The current method relies on dividing by the L0 coefficient and L0 in being in a specific ratio to L1. Both of these assumptions would no longer be true.

I have made two attempts at resolving this. The first just plainly disables L1 packing. The second attempts two use a sigmoid function to pack the L1 coefficients. This kinda works but it lacks the flexibility of the original method that allowed it to scale to the relative brightness and results in significant artifacts. I'm still trying to find a better method to do this.

I have made draft PRs for these methods that contain a bit more detail. They are still in a rough state and methods have only been implemented for the forward+ renderer so far.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment