RenderKit / oidn

Intel® Open Image Denoise library
https://www.openimagedenoise.org/
Apache License 2.0
1.78k stars 164 forks source link

Feature request: masking for lightmap denoising. #112

Closed JFonS closed 1 year ago

JFonS commented 3 years ago

We started using OpenImageDenoise for lightmap denoising in the Godot game engine, and we are having great results so far. However, there's an issue I haven't been able to work around.

Problem

Lightmap textures need some padding between the lightmapped regions in order to avoid bleeding when sampling the texture. When denoising a lightmap, these "void" regions have an effect on the valid lit surfaces and result in darkened edges. darken

Since we already do a dilation step on the lit regions, I tried applying the denoiser on the dilated version of the lightmap, but that creates another problem: when two regions meet each other, there's bleeding between them. bleed

Proposed solutions

Keeping in mind my knowledge on neural networks is limited, I wanted to propose a couple of possible solutions. The first one would be to provide some information on which pixels contain valid information and which ones are just part of the "void" between lit surfaces. The denoiser would then ignore invalid pixels and work on "real" information only. This would allow users to denoise the lightmaps before the dilation step, while still avoiding darkening of the edges.

Another possible solution (probably harder to implement) would be to provide a region ID buffer. Where all pixels belonging to the same region have the same value. The denoiser would then only consider pixels on the same region when denoising a given pixel.

In any case, huge thanks for providing such a nice and FOSS denoiser. Feel free to completely disregard my proposed solutions if they make no sense, but finding a solution to the described problem would be greatly appreciated :)

sfiruch commented 3 years ago

Can't you call the denoiser for each rectangular region separately?

JFonS commented 3 years ago

No, not really... I used a simple cube as an example here, and in this case it would work, but a typical lightmap looks something like this: bake_lmdilate1.png

Elements have arbitrary shapes and they are mixed together with a "void" background that contains no real information but still leaks into the denoised result.

sfiruch commented 3 years ago

I see. Potential workaround with probably terrible performance:

  1. Copy each element into a separate buffer
  2. Fill missing pixels with dilation or some content-aware fill
  3. Denoise the buffer
  4. Copy back, with masking

I think supporting a binary mask (or full support for alpha channels, see #124) would require a slightly different NN architecture, but would be doable. With pre-multiplied alpha, one probably wouldn't have to change that much. Would be a nice feature with many use cases.

atafra commented 3 years ago

Currently I would recommend denoising after dilation. The "bleeding" artifact is more like ringing, which has been significantly alleviated (but not completely fixed) in recent versions of OIDN. I would highly recommend upgrading before trying any other tweaks. Further improvements can be expected in later versions. More complex features what you suggested sound interesting as well but unfortunately these have to wait due to other priorities.