godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
86.3k stars 19.2k forks source link

Vulkan: LightmapGI exhibits light bleeding through occluded areas after denoising due to occluded pixels still receiving light #87815

Open lander-vr opened 5 months ago

lander-vr commented 5 months ago

Tested versions

v4.2.1.stable.official [b09f793f5]

System information

Godot v4.2.1.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2060 (NVIDIA; 31.0.15.3758) - AMD Ryzen 5 5600X 6-Core Processor (12 Threads)

Issue description

Continuation on/Reopening of #63437

Pixels inside intersecting or overlapping geometry still receive light. This is an issue when:

Both those situations are fine without denoising, but cause light leaking/bleeding after the rendered result is denoised.

image Before denoising (left) and after (right) with a relatively high texel density and "use textures for bounces" enabled in both. The visible seams between the flat modular meshes is related to #82607

image Inside a wall section with "use textures for bounces" enabled (left) and disabled (right). Note that when disabled there are still pixels visible within the occluded areas that are receiving light.

image Light leaking at a 'reduced' texel density, "use textures for bounces" disabled in both, with denoising disabled (left) and enabled (right). Note the various light leaks, not only on the walls near the ceilings, but on the wall next to the door mesh, and several corners of individual wall-meshes on the far wall.

In this last example I had raised the ceiling meshes slightly to ensure there should be no ambiguity for the lightmapper on whether the interior-side face of the wall should be entirely occluded or not. This did not make a difference in the resulting lightbake.

image Raised ceiling mesh to completely occlude the interior facing side of the wall (left), view from inside the ceiling mesh showing that light is reaching the top of the wall which is expected to be occluded.

Increasing the texel density can unreliably (slightly) alleviate the issue, but is not a legitimate solution since the texel densities used in these tests should be more than sufficient and are representative of what should be expected to work and used in the average project. Also worth noting is that these meshes are imported with a reduced texel size of 0.05 in the first 4 screenshots, and 0.1 in the last 4 screenshots, compared to the default texel size of 0.2

Using custom lightmap UVs with more padding has not made a difference in my tests.

Compared to the average modular game environment (anecdotally, but coming from a professional background in both AAA and indie development as a point of reference), the meshes used in these tests provide a forgiving scenario for the lightmapper to deal with: The meshes are manifold, there is no intricate geometry, and all meshes have plenty of thickness to cover a decent amount of pixels on the lightmap when intersecting or overlapping with other geometry. Taking possible light leaking at the borders of the occluded areas in account (i.e. single pixels bleeding through at intersections), an artist should be able to expect the resolution, overlap and thickness in this scenario to provide a sufficient buffer for the lightmapper to avoid leaking.

This issue is also discussed in #75440

Steps to reproduce

The MRP has "use texture for bounces" disabled, since this seems to just worsen the existing issue and does not seem like the cause.

Minimal reproduction project (MRP)

LightmapGiLeaking.zip

Calinou commented 5 months ago

Can you reproduce this issue when using OIDN as a denoiser?

lander-vr commented 5 months ago

Here are some direct comparison between OIDN and JNLM.

Use texture for bounces disabled, texel size 0.1: image OIDN has less prominent light leaking, however still visible. It also introduces AO-like artifacts at all borders between modular meshes.

Use texture for bounces enabled, texel size 0.1 image Enabling "use texture for bounces" worsens the AO-like artifacts that OIDN produces. In the JNLM bake light leaking is reintroduced in several corners of the room and of some meshes.

Use texture for bounces enabled image From this angle it looks like JNLM at texel size 0.05 produces passable results, however here is a screenshot with an arrow depicting the camera direction and corner we are looking at in the previous images, showing clear light leaking. The reason JNLM at texel size 0.1 doesn't pass here you can see in first screenshot linked. image

I added two cube meshes to the scene and intersected them to see if anything unexpected would happen occlusion-wise, and some pixels within the cube are lit up, which with use texture for bounces disabled doesn't seem like it should be a cause for concern. However, when enabled it does intensify those few pixels which can then cause leaking issues when denoising.

image

patwork commented 3 months ago

Hi, I have created a small project containing several test scenes to verify the correct generation and display of LightmapGI and LightmapProbes.

Godot LightmapGI Tests

The scene that verifies light leaks is called Test 03.

In my case, the boxes are completely closed and it seems to me that regardless of the denoising method, it should be completely black inside.

Toggling "Interior" in the LightmapGI settings doesn't change anything. Only changing "Environment" to "Disabled" removes the influence of the external environment (shouldn't turning on "Interior" work the same?)

patwork commented 3 months ago

This is interesting, I created a box without one face in Blender, normals pointing inside, then I generated UV2 also in Blender, imported into Godot v4.3.dev4.official [df78c0636] and the result is like this (clearly visible brighter edges):

in-godot

UV2 in Blender (UV Lightmap Pack : Margin = 1)

uv2-in-blender

Baked lightmap from Godot (Quality : Ultra, Denoiser: Off, Texel Scale: 4)

baked-exr

After generating new UV2 in Godot (Light Baking : Static Lightmap, Lightmap Texel Size: 0.2):

in-godot2

Baked lightmap from Godot with new UV:

baked-exr2

Calinou commented 3 months ago

It's strange this occurs, considering Godot's UV2 is padded more aggressively.

Does this occur with a MeshInstance3D with a BoxMesh that has Add UV2 enabled in its properties? This procedurally generates UV2 without calling xatlas on import.

patwork commented 3 months ago

OK I'm checking, I just don't know if it is possible to remove one of the faces in the boxmesh to make the test object identical to the one imported from Blender. Anyway:

meshinstance

Baked lightmap:

meshinstance

Looks okayish? Not counting the black pixels in the corner.

pix

I don't know if this is a good test due to the fact that cull mode is probably not supported and the inner faces are illuminated as if they were outer faces (issue #89402)

patwork commented 3 months ago

OK, now same test but with 5 planes, each one with UV2 generated in Godot, LightmapGI with texel size 1. The edges of the planes are adjacent to each other.

planes

Zoomed baked lightmap:

zoom

There is no difference if I turn on or off "use_texture_for_bounces".

When Texel Size is bigger, brighter edges edges become narrower but do not disappear.

Here's use_texture_for_bounces = off, texel size = 8:

tx8