Fix: EEVEE-Next: Render Region

Fix render regions and make them work with overscan:
- Clarify and improve the naming used by the Film module.
- Convert Display texel coordinates to Film texel coordinates before
  calling `film_process_data`, and convert from Film texel coordinates to
  Render texel coordinates in `film_sample_get`.
- Returns the actual display extent (and not the film extent) in
 `Film::display_extent_get` so the overscan camera matrix is computed
  correctly when using render regions.

Regression caused by 567a2e5a6f.

Pull Request: https://projects.blender.org/blender/blender/pulls/111691
This commit is contained in:
Miguel Pozo 2023-09-01 17:15:38 +02:00
parent 2dc1dcc43e
commit 7e33c405fb
5 changed files with 28 additions and 14 deletions

View File

@ -5,7 +5,7 @@
/** \file
* \ingroup eevee
*
* A film is a full-screen buffer (usually at output extent)
* A film is a buffer (usually at display extent)
* that will be able to accumulate sample in any distorted camera_type
* using a pixel filter.
*
@ -147,6 +147,7 @@ void Film::sync_mist()
inline bool operator==(const FilmData &a, const FilmData &b)
{
return (a.extent == b.extent) && (a.offset == b.offset) &&
(a.render_extent == b.render_extent) && (a.render_offset == b.render_offset) &&
(a.filter_radius == b.filter_radius) && (a.scaling_factor == b.scaling_factor) &&
(a.background_opacity == b.background_opacity);
}
@ -248,21 +249,22 @@ void Film::init(const int2 &extent, const rcti *output_rect)
output_rect = &fallback_rect;
}
display_offset = int2(output_rect->xmin, output_rect->ymin);
display_extent = extent;
FilmData data = data_;
data.extent = int2(BLI_rcti_size_x(output_rect), BLI_rcti_size_y(output_rect));
data.offset = display_offset;
data.offset = int2(output_rect->xmin, output_rect->ymin);
data.extent_inv = 1.0f / float2(data.extent);
/* TODO(fclem): parameter hidden in experimental.
* We need to figure out LOD bias first in order to preserve texture crispiness. */
data.scaling_factor = 1;
data.render_extent = math::divide_ceil(extent, int2(data.scaling_factor));
data.render_offset = data.offset;
if (inst_.camera.overscan() != 0.0f) {
int2 overscan = int2(inst_.camera.overscan() * math::max(UNPACK2(data.render_extent)));
data.render_extent += overscan * 2;
data.offset += overscan;
data.render_offset += overscan;
}
/* Disable filtering if sample count is 1. */
@ -636,7 +638,7 @@ void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx)
float4 clear_color = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(dfbl->default_fb, clear_color);
}
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(display_offset), UNPACK2(data_.extent));
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data.offset), UNPACK2(data_.extent));
}
update_sample_table();
@ -668,7 +670,7 @@ void Film::display()
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(display_offset), UNPACK2(data_.extent));
GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data.offset), UNPACK2(data_.extent));
combined_final_tx_ = inst_.render_buffers.combined_tx;

View File

@ -14,6 +14,16 @@
* - For dynamic scene (if an update is detected), we use a more temporally stable accumulation
* following the Temporal Anti-Aliasing method (a.k.a. Temporal Super-Sampling). This does
* history reprojection and rectification to avoid most of the flickering.
*
* The Film module uses the following terms to refer to different spaces/extents:
*
* - Display: The full output extent (matches the full viewport or the final image resolution).
*
* - Film: The same extent as display, or a subset of it when a Render Region is used.
*
* - Render: The extent used internally by the engine for rendering the main views.
* Equals to the full display extent + overscan (even when a Render Region is used)
* and its resolution can be scaled.
*/
#pragma once
@ -66,7 +76,7 @@ class Film {
PassSimple cryptomatte_post_ps_ = {"Film.Cryptomatte.Post"};
FilmDataBuf data_;
int2 display_offset;
int2 display_extent;
eViewLayerEEVEEPassType enabled_passes_ = eViewLayerEEVEEPassType(0);
@ -97,10 +107,10 @@ class Film {
return data_.render_extent;
}
/** Returns render output resolution. */
/** Returns final output resolution. */
int2 display_extent_get() const
{
return data_.extent;
return display_extent;
}
float2 pixel_jitter_get() const;

View File

@ -229,10 +229,12 @@ BLI_STATIC_ASSERT_ALIGN(FilmSample, 16)
struct FilmData {
/** Size of the film in pixels. */
int2 extent;
/** Offset of the film in the full-res frame, in pixels. */
/** Offset to convert from Display space to Film space, in pixels. */
int2 offset;
/** Extent used by the render buffers when rendering the main views. */
/** Size of the render buffers when rendering the main views, in pixels. */
int2 render_extent;
/** Offset to convert from Film space to Render space, in pixels. */
int2 render_offset;
/**
* Sub-pixel offset applied to the window matrix.
* NOTE: In final film pixel unit.
@ -254,7 +256,7 @@ struct FilmData {
bool1 any_render_pass_2;
/** Controlled by user in lookdev mode or by render settings. */
float background_opacity;
float _pad0;
float _pad0, _pad1, _pad2;
/** Output counts per type. */
int color_len, value_len;
/** Index in color_accum_img or value_accum_img of each pass. -1 if pass is not enabled. */

View File

@ -7,7 +7,7 @@
void main()
{
ivec2 texel_film = ivec2(gl_FragCoord.xy);
ivec2 texel_film = ivec2(gl_FragCoord.xy) - film_buf.offset;
float out_depth;
if (film_buf.display_only) {

View File

@ -59,7 +59,7 @@ FilmSample film_sample_get(int sample_n, ivec2 texel_film)
# endif
FilmSample film_sample = film_buf.samples[sample_n];
film_sample.texel += texel_film + film_buf.offset;
film_sample.texel += texel_film + film_buf.render_offset;
/* Use extend on borders. */
film_sample.texel = clamp(film_sample.texel, ivec2(0, 0), film_buf.render_extent - 1);