EEVEE: Overscan/Border mixed resolution rendering

Mixed resolution rendering had some issues with overscan and border
rendering.

- `render_offset` was in display space and not in render space. Is
  now replaced by the `overscan_extent`.
- `overscan_extent` introduced that stored the overscan of the render
  extent.
- Fixed issues to determine the film sample weight when `scaling_factor`
  was used. It didn't match decompose the actual offset making the
  length of the same to large, what blurred the final samples.

NOTE: there are some other issues related to border rendering which was
already in main before mixed resolution rendering was added. I assume
that viewport render image in camera view still adds an additional
offset, which should be ignored.

Fixes #119510
Fixes #119511

Pull Request: https://projects.blender.org/blender/blender/pulls/119524
This commit is contained in:
Jeroen Bakker 2024-03-18 16:02:57 +01:00
parent ebf12765a6
commit 8945b29762
4 changed files with 17 additions and 12 deletions

@ -151,7 +151,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.render_extent == b.render_extent) && (a.overscan == b.overscan) &&
(a.filter_radius == b.filter_radius) && (a.scaling_factor == b.scaling_factor) &&
(a.background_opacity == b.background_opacity);
}
@ -265,12 +265,11 @@ void Film::init(const int2 &extent, const rcti *output_rect)
data_.offset = int2(output_rect->xmin, output_rect->ymin);
data_.extent_inv = 1.0f / float2(data_.extent);
data_.render_extent = math::divide_ceil(extent, int2(data_.scaling_factor));
data_.render_offset = data_.offset;
data_.overscan = 0;
if (inst_.camera.overscan() != 0.0f) {
int2 overscan = int2(inst_.camera.overscan() * math::max(UNPACK2(data_.render_extent)));
data_.render_extent += overscan * 2;
data_.render_offset += overscan;
data_.overscan = inst_.camera.overscan() * math::max(UNPACK2(data_.render_extent));
data_.render_extent += data_.overscan * 2;
}
/* Disable filtering if sample count is 1. */

@ -262,10 +262,8 @@ struct FilmData {
int2 extent;
/** Offset to convert from Display space to Film space, in pixels. */
int2 offset;
/** Size of the render buffers when rendering the main views, in pixels. */
/** Size of the render buffers including overscan 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.
@ -276,6 +274,11 @@ struct FilmData {
float2 subpixel_offset;
/** Scaling factor to convert texel to uvs. */
float2 extent_inv;
/**
* Number of border pixels on all sides inside the render_extent that do not contribute to the
* final image.
*/
int overscan;
/** Is true if history is valid and can be sampled. Bypass history to resets accumulation. */
bool32_t use_history;
/** Controlled by user in lookdev mode or by render settings. */
@ -328,6 +331,7 @@ struct FilmData {
/** Sum of the weights of all samples in the sample table. */
float samples_weight_total;
int _pad1;
int _pad2;
FilmSample samples[FILM_PRECOMP_SAMPLE_MAX];
};
BLI_STATIC_ASSERT_ALIGN(FilmData, 16)

@ -216,7 +216,7 @@ void ShadingView::update_view()
*/
int2 scaling_factor = int2(inst_.film.scaling_factor_get());
int2 display_extent = inst_.film.display_extent_get();
int2 overscan = inst_.film.get_data().render_offset - inst_.film.get_data().offset;
int overscan = inst_.film.get_data().overscan;
int2 rescaled_render_extent = (extent_ - 2 * overscan) * scaling_factor;
if (rescaled_render_extent != display_extent) {

@ -55,7 +55,8 @@ FilmSample film_sample_get(int sample_n, ivec2 texel_film)
#else
FilmSample film_sample = uniform_buf.film.samples[sample_n];
film_sample.texel += (texel_film / scaling_factor) + uniform_buf.film.render_offset;
film_sample.texel += (texel_film + uniform_buf.film.offset) / scaling_factor +
uniform_buf.film.overscan;
/* Use extend on borders. */
film_sample.texel = clamp(film_sample.texel, ivec2(0, 0), uniform_buf.film.render_extent - 1);
@ -64,9 +65,10 @@ FilmSample film_sample_get(int sample_n, ivec2 texel_film)
if (scaling_factor > 1) {
/* We need to compute the real distance and weight since a sample
* can be used by many final pixel. */
vec2 offset = (vec2(film_sample.texel) + 0.5 - uniform_buf.film.subpixel_offset) *
vec2 offset = (vec2(film_sample.texel - uniform_buf.film.overscan) + 0.5 -
uniform_buf.film.subpixel_offset) *
scaling_factor -
(vec2(texel_film) + 0.5);
(vec2(texel_film + uniform_buf.film.offset) + 0.5);
film_sample.weight = film_filter_weight(uniform_buf.film.filter_radius,
length_squared(offset));
}