Eevee: Implement Overscan option
authorClément Foucault <foucault.clem@gmail.com>
Wed, 31 Oct 2018 17:31:14 +0000 (18:31 +0100)
committerClément Foucault <foucault.clem@gmail.com>
Wed, 31 Oct 2018 17:32:54 +0000 (18:32 +0100)
This option make the internal render size larger than the output size in
order to minimize screenspace effects disapearing at the render edges.

The overscan size added around the render is the maximum dimension
multiplied by the overscan percentage.

release/scripts/startup/bl_ui/properties_render.py
source/blender/blenkernel/intern/scene.c
source/blender/blenloader/intern/versioning_280.c
source/blender/draw/engines/eevee/eevee_private.h
source/blender/draw/engines/eevee/eevee_render.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_scene.c
source/blender/render/extern/include/RE_pipeline.h
source/blender/render/intern/source/initrender.c

index 25e22be53770d2d5e2c15d14d52eda945e29742f..5e39dd5dcdc30bb916846ea066bda9981f875f9f 100644 (file)
@@ -956,13 +956,21 @@ class RENDER_PT_eevee_film(RenderButtonsPanel, Panel):
         layout.use_property_split = True
 
         scene = context.scene
+        props = scene.eevee
         rd = scene.render
 
+        split = layout.split()
+        split.prop(props, "use_overscan")
+        row = split.row()
+        row.active = props.use_overscan
+        row.prop(props, "overscan_size", text="")
+
         col = layout.column()
         col.prop(rd, "filter_size")
         col.prop(rd, "alpha_mode", text="Alpha")
 
 
+
 class RENDER_PT_eevee_hair(RenderButtonsPanel, Panel):
     bl_label = "Hair"
     bl_options = {'DEFAULT_CLOSED'}
index 8fdf207ad687676359bad25913e56734d9fae35c..60b542cd254fd62198b3806bd28d557f390db8cc 100644 (file)
@@ -919,6 +919,8 @@ void BKE_scene_init(Scene *sce)
 
        sce->eevee.light_cache = NULL;
 
+       sce->eevee.overscan = 0.3f;
+
        sce->eevee.flag =
                SCE_EEVEE_VOLUMETRIC_LIGHTS |
                SCE_EEVEE_GTAO_BENT_NORMALS |
index a726b32166bcd983eb110c36496af63baeb04d55..21debc13a2272cd27dfaa1416501e6a7d8787108 100644 (file)
@@ -2226,4 +2226,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
                                | OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC);
                }
        }
+
+       {
+               if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "overscan")) {
+                       for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+                               scene->eevee.overscan = 3.0f;
+                       }
+               }
+       }
 }
index fbabf86074eaa35d9a6bc2b07df878ca90d40997..e732bc8d40d95fcdfdb11f99fa20a526300f6481 100644 (file)
@@ -797,6 +797,8 @@ typedef struct EEVEE_PrivateData {
        float viewmat[4][4], viewinv[4][4];
        float winmat[4][4], wininv[4][4];
        float studiolight_matrix[3][3];
+       float overscan, overscan_pixels;
+       float size_orig[2];
 
        /* Mist Settings */
        float mist_start, mist_inv_dist, mist_falloff;
index 86c20ee54da2de0a97704fbff5d3d729c2361f99..a2c44cbcd38d37119babc64fe998daad83de6c58 100644 (file)
@@ -33,6 +33,8 @@
 #include "DNA_node_types.h"
 #include "DNA_object_types.h"
 
+#include "BKE_camera.h"
+
 #include "BLI_rand.h"
 #include "BLI_rect.h"
 
@@ -54,6 +56,7 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
        EEVEE_FramebufferList *fbl = vedata->fbl;
        EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
        Scene *scene = DEG_get_evaluated_scene(depsgraph);
+       const float *size_orig = DRW_viewport_size_get();
 
        /* Init default FB and render targets:
         * In render mode the default framebuffer is not generated
@@ -62,6 +65,28 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
        DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
        DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
 
+       /* Alloc transient data. */
+       if (!stl->g_data) {
+               stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+       }
+       EEVEE_PrivateData *g_data = stl->g_data;
+       g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f;
+       g_data->valid_double_buffer = 0;
+       copy_v2_v2(g_data->size_orig, size_orig);
+
+       if (scene->eevee.flag & SCE_EEVEE_OVERSCAN) {
+               g_data->overscan = scene->eevee.overscan / 100.0f;
+               g_data->overscan_pixels = roundf(max_ff(size_orig[0], size_orig[1]) * g_data->overscan);
+       }
+       else {
+               g_data->overscan = 0.0f;
+               g_data->overscan_pixels = 0.0f;
+       }
+
+       /* XXX overiding viewport size. Simplify things but is not really 100% safe. */
+       DRW_render_viewport_size_set((int[2]){size_orig[0] + g_data->overscan_pixels * 2.0f,
+                                             size_orig[1] + g_data->overscan_pixels * 2.0f});
+
        /* TODO 32 bit depth */
        DRW_texture_ensure_fullscreen_2D(&dtxl->depth, GPU_DEPTH24_STENCIL8, 0);
        DRW_texture_ensure_fullscreen_2D(&txl->color, GPU_RGBA32F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
@@ -79,14 +104,6 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
                GPU_ATTACHMENT_TEXTURE(txl->color)
        });
 
-       /* Alloc transient data. */
-       if (!stl->g_data) {
-               stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
-       }
-       EEVEE_PrivateData *g_data = stl->g_data;
-       g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f;
-       g_data->valid_double_buffer = 0;
-
        /* Alloc common ubo data. */
        if (sldata->common_ubo == NULL) {
                sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
@@ -102,6 +119,8 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
        RE_GetCameraWindow(engine->re, ob_camera_eval, frame, g_data->winmat);
        RE_GetCameraModelMatrix(engine->re, ob_camera_eval, g_data->viewinv);
 
+       RE_GetCameraWindowWithOverscan(engine->re, g_data->winmat, g_data->overscan);
+
        invert_m4_m4(g_data->viewmat, g_data->viewinv);
        mul_m4_m4m4(g_data->persmat, g_data->winmat, g_data->viewmat);
        invert_m4_m4(g_data->persinv, g_data->persmat);
@@ -189,7 +208,8 @@ static void eevee_render_result_combined(
 
        GPU_framebuffer_bind(vedata->stl->effects->final_fb);
        GPU_framebuffer_read_color(vedata->stl->effects->final_fb,
-                                  rect->xmin, rect->ymin,
+                                  vedata->stl->g_data->overscan_pixels + rect->xmin,
+                                  vedata->stl->g_data->overscan_pixels + rect->ymin,
                                   BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
                                   4, 0, rp->rect);
 
@@ -217,7 +237,8 @@ static void eevee_render_result_subsurface(
 
                GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
                GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
-                                          rect->xmin, rect->ymin,
+                                          vedata->stl->g_data->overscan_pixels + rect->xmin,
+                                          vedata->stl->g_data->overscan_pixels + rect->ymin,
                                           BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
                                           3, 1, rp->rect);
 
@@ -232,7 +253,8 @@ static void eevee_render_result_subsurface(
 
                GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
                GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
-                                          rect->xmin, rect->ymin,
+                                          vedata->stl->g_data->overscan_pixels + rect->xmin,
+                                          vedata->stl->g_data->overscan_pixels + rect->ymin,
                                           BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
                                           3, 0, rp->rect);
 
@@ -266,7 +288,8 @@ static void eevee_render_result_normal(
 
                GPU_framebuffer_bind(vedata->fbl->main_fb);
                GPU_framebuffer_read_color(vedata->fbl->main_fb,
-                                          rect->xmin, rect->ymin,
+                                          g_data->overscan_pixels + rect->xmin,
+                                          g_data->overscan_pixels + rect->ymin,
                                           BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
                                           3, 1, rp->rect);
 
@@ -312,7 +335,8 @@ static void eevee_render_result_z(
 
                GPU_framebuffer_bind(vedata->fbl->main_fb);
                GPU_framebuffer_read_depth(vedata->fbl->main_fb,
-                                          rect->xmin, rect->ymin,
+                                          g_data->overscan_pixels + rect->xmin,
+                                          g_data->overscan_pixels + rect->ymin,
                                           BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
                                           rp->rect);
 
@@ -348,7 +372,8 @@ static void eevee_render_result_mist(
 
                GPU_framebuffer_bind(vedata->fbl->mist_accum_fb);
                GPU_framebuffer_read_color(vedata->fbl->mist_accum_fb,
-                                          rect->xmin, rect->ymin,
+                                          vedata->stl->g_data->overscan_pixels + rect->xmin,
+                                          vedata->stl->g_data->overscan_pixels + rect->ymin,
                                           BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
                                           1, 0, rp->rect);
 
@@ -376,7 +401,8 @@ static void eevee_render_result_occlusion(
 
                GPU_framebuffer_bind(vedata->fbl->ao_accum_fb);
                GPU_framebuffer_read_color(vedata->fbl->ao_accum_fb,
-                                          rect->xmin, rect->ymin,
+                                          vedata->stl->g_data->overscan_pixels + rect->xmin,
+                                          vedata->stl->g_data->overscan_pixels + rect->ymin,
                                           BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
                                           3, 0, rp->rect);
 
@@ -561,6 +587,9 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
        eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata, render_samples);
        eevee_render_result_mist(rl, viewname, rect, vedata, sldata, render_samples);
        eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata, render_samples);
+
+       /* Restore original viewport size. */
+       DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]});
 }
 
 void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
index 9045fb4353d7ebd9093c3f38b856b4a72bc17abc..ebdce500d3143b747b74f284e472249d6bbd5f96 100644 (file)
@@ -1485,6 +1485,9 @@ typedef struct SceneEEVEE {
 
        struct LightCache *light_cache;
        char light_cache_info[64];
+
+       float overscan;
+       float pad;
 } SceneEEVEE;
 
 /* *************************************************************** */
@@ -2192,6 +2195,7 @@ enum {
        SCE_EEVEE_SHOW_CUBEMAPS                 = (1 << 18),
        SCE_EEVEE_GI_AUTOBAKE                   = (1 << 19),
        SCE_EEVEE_SHADOW_SOFT                   = (1 << 20),
+       SCE_EEVEE_OVERSCAN                              = (1 << 21),
 };
 
 /* SceneEEVEE->shadow_method */
index 8e7075ca91ab729b19148e166e3c3aa588de516f..79f4312f589d41a9985152cdbd638d61b903ca9c 100644 (file)
@@ -6022,6 +6022,23 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
        RNA_def_property_boolean_default(prop, 0);
        RNA_def_property_ui_text(prop, "Soft Shadows", "Randomize shadowmaps origin to create soft shadows");
        RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+       /* Overscan */
+       prop = RNA_def_property(srna, "use_overscan", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_OVERSCAN);
+       RNA_def_property_boolean_default(prop, 0);
+       RNA_def_property_ui_text(prop, "Overscan", "Internally render past the image border to avoid "
+                                                  "screen-space effects disapearing");
+       RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+       prop = RNA_def_property(srna, "overscan_size", PROP_FLOAT, PROP_PERCENTAGE);
+       RNA_def_property_float_sdna(prop, NULL, "overscan");
+       RNA_def_property_float_default(prop, 3.0f);
+       RNA_def_property_ui_text(prop, "Overscan Size", "Percentage of render size to add as overscan to the "
+                                                       "internal render buffers");
+       RNA_def_property_range(prop, 0.0f, 50.0f);
+       RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 2);
+       RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
 }
 
 void RNA_def_scene(BlenderRNA *brna)
index cc2bd01718af3c1d2799bdf0de9b63bd46248083..614a1735f443b7bf6724f40d422fe51ed21132ff 100644 (file)
@@ -335,6 +335,7 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int pas
 #define RE_BAKE_AO                                     2
 
 void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]);
+void RE_GetCameraWindowWithOverscan(struct Render *re, float mat[4][4], float overscan);
 void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_mat[4][4]);
 struct Scene *RE_GetScene(struct Render *re);
 void RE_SetScene(struct Render *re, struct Scene *sce);
index 828d626f9a7a42370c158ad6a472d233adc2e3fc..1420b8feef7e434a7a758d051d8c55332c0a1505 100644 (file)
@@ -195,6 +195,25 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, flo
        copy_m4_m4(mat, re->winmat);
 }
 
+/* Must be called after RE_GetCameraWindow(), does not change re->winmat. */
+void RE_GetCameraWindowWithOverscan(struct Render *re, float mat[4][4], float overscan)
+{
+       CameraParams params;
+       params.is_ortho = re->winmat[3][3] != 0.0f;
+       params.clipsta = re->clipsta;
+       params.clipend = re->clipend;
+       params.viewplane = re->viewplane;
+
+       overscan *= max_ff(BLI_rctf_size_x(&params.viewplane), BLI_rctf_size_y(&params.viewplane));
+
+       params.viewplane.xmin -= overscan;
+       params.viewplane.xmax += overscan;
+       params.viewplane.ymin -= overscan;
+       params.viewplane.ymax += overscan;
+       BKE_camera_params_compute_matrix(&params);
+       copy_m4_m4(mat, params.winmat);
+}
+
 void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4])
 {
        BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_mat);