Page MenuHome

Filmic not working on rendered frame in EEVEE
Closed, ResolvedPublic

Description

System Information
win10 pro dual 1070

Blender Version
Broken: (example: blender-2.80 0837d19-windows64, 2017 07 12 nightly build)
Worked: (optional)

when pressing the render icon under the viewport and getting a rendered image in the image editor a stark difference occurs in whites being clipped (aka filmic not working)

Image attached for clear explanation.

(My first bug report ever!) 📦
thanks Dalai for twitter encouragement

Event Timeline

Could you please attach the .blend you used to reproduce this issue?

I basically reproduced it (didn't save original, sorry)

Dalai Felinto (dfelinto) triaged this task as Confirmed, Medium priority.

Since this is "offscreen" render related, @Campbell Barton (campbellbarton) may want to take a look as well

The thing is that this offscreen render is using byte buffers. And it output transformed (tonemapped) color to the render result that is transformed again with the color management settings.

Ideally we should output an HDR buffer without color correction but this means transforming all colors from object modes to be linear.

@Clément Foucault (fclem), noticed this double transform too (though there was an issue with off-screen buffers - fixed rB73b142529705e75790a4b9279109763014ca63e6 )

Is rendering float images with HDR reliable with OpenGL3.2?
As in, can we add this with only a few changes to the code?

A short term fix could be to flag the render as having color-management applied.

@Campbell Barton (campbellbarton) Yes it's reliable to render to HDR format, this is the bread and butter of eevee. Though it's really not easy to change:

  1. Make OffscreenBuffer use a float point format (RGBA16F/32F) depending on active render engine (Eevee only).
  2. Make Eevee not do the render transform if he is doing a render.
  3. (optionnal) color of other engines won't be correct. Make them linear (somehow), maybe by changing the colors in the UBO struct.
  1. (optionnal) color of other engines won't be correct. Make them linear (somehow), maybe by changing the colors in the UBO struct.

Note that the issue isn't just transfer function (intensity mapping of scene referred to display referred or vice versa) but also primaries.

Various game engines are flipping or have flipped their reference primaries (IE the colours for each of the red, green, and blue lights) to different coloured lights from BT.709 / sRGB. These include but aren't limited to ACES AP1, REC.2020 and others.

To do a proper conversion:

  1. Identify the transfer function that maps the scene referred values to the display referred and undo it.
  2. Identify the primary lights for source and destination and transform between them.

This can be distilled into a simple OCIO transform, but it requires more information that simply the transfer function.

Quick solution is to disable view transform for OpenGL render (NOT viewport, but the bpy.ops.render.opengl()). This transform is never supposed to be applied on the render result unless you save the file (saving to non-linear format will apply view transform). You can do that by passing NULL as view transform for IMB_colormanagement_setup_glsl_draw_from_space in DRW_transform_to_display(). This will make things to work as it was supposed to in color pipeline in Blender in respect of view transform.

Here's really dirty implementation of the approach:

1diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
2index d5b2944990b..70db4ed4d84 100644
3--- a/source/blender/draw/intern/draw_manager.c
4+++ b/source/blender/draw/intern/draw_manager.c
5@@ -2388,7 +2388,7 @@ void DRW_transform_to_display(GPUTexture *tex)
6 {
7 Scene *scene = DST.draw_ctx.scene;
8 use_ocio = IMB_colormanagement_setup_glsl_draw_from_space(
9- &scene->view_settings, &scene->display_settings, NULL, dither, false);
10+ G.is_rendering ? NULL : &scene->view_settings, &scene->display_settings, NULL, dither, false);
11 }
12
13 if (!use_ocio) {
14diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
15index 47e8a64cb0b..b492f7f2c50 100644
16--- a/source/blender/editors/render/render_opengl.c
17+++ b/source/blender/editors/render/render_opengl.c
18@@ -283,6 +283,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
19 EvaluationContext eval_ctx;
20
21 CTX_data_eval_ctx(C, &eval_ctx);
22+ G.is_rendering = 1;
23
24 if (oglrender->is_sequencer) {
25 SpaceSeq *sseq = oglrender->sseq;
26@@ -387,6 +388,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
27 RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
28 IMB_freeImBuf(ibuf_result);
29 }
30+
31+ G.is_rendering = 0;
32 }
33
34 static void screen_opengl_render_write(OGLRender *oglrender)

There will be some issue with color being clipped, because we store OpenGL render as byte buffer.

Proper solution would be to skip any color management in OpenGL rendering and store OpenGL render result as float buffer in RenderResult in linear space.