diff options
6 files changed, 170 insertions, 60 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index a20c443171c..8c0a44b2c9b 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -47,6 +47,8 @@ #include "GPU_texture.h" #include "eevee_private.h" +#define CAMERA_JITTER_RING_DENSITY 6 + static float coc_radius_from_camera_depth(bool is_ortho, EEVEE_EffectsInfo *fx, float camera_depth) { float multiplier = fx->dof_coc_params[0]; @@ -62,53 +64,97 @@ static float coc_radius_from_camera_depth(bool is_ortho, EEVEE_EffectsInfo *fx, } } -static void regular_polygon_sample( - float corners, float rotation, float u, float v, float r_sample[2]) +static float polygon_sides_length(float sides_count) { - /* Sample corner number and reuse u. */ - float corner = floorf(u * corners); - u = u * corners - corner; - /* Uniform sampled triangle weights. */ - u = sqrtf(u); - v = v * u; - u = 1.0f - u; - /* Point in triangle. */ - float angle = M_PI / corners; - float p[2] = {(u + v) * cosf(angle), (u - v) * sinf(angle)}; - /* Rotate. */ - rotation += corner * 2.0f * angle; - float cr = cosf(rotation); - float sr = sinf(rotation); - r_sample[0] = cr * p[0] - sr * p[1]; - r_sample[1] = sr * p[0] + cr * p[1]; + return 2.0 * sin(M_PI / sides_count); +} + +/* Returns intersection ratio between the radius edge at theta and the polygon edge. + * Start first corners at theta == 0. */ +static float circle_to_polygon_radius(float sides_count, float theta) +{ + /* From Graphics Gems from CryENGINE 3 (Siggraph 2013) by Tiago Sousa (slide 36). */ + float side_angle = (2.0f * M_PI) / sides_count; + return cosf(side_angle * 0.5f) / + cosf(theta - side_angle * floorf((sides_count * theta + M_PI) / (2.0f * M_PI))); +} + +/* Remap input angle to have homogenous spacing of points along a polygon edge. + * Expect theta to be in [0..2pi] range. */ +static float circle_to_polygon_angle(float sides_count, float theta) +{ + float side_angle = (2.0f * M_PI) / sides_count; + float halfside_angle = side_angle * 0.5f; + float side = floorf(theta / side_angle); + /* Length of segment from center to the middle of polygon side. */ + float adjacent = circle_to_polygon_radius(sides_count, 0.0f); + + /* This is the relative position of the sample on the polygon half side. */ + float local_theta = theta - side * side_angle; + float ratio = (local_theta - halfside_angle) / halfside_angle; + + float halfside_len = polygon_sides_length(sides_count) * 0.5f; + float opposite = ratio * halfside_len; + + /* NOTE: atan(y_over_x) has output range [-M_PI_2..M_PI_2]. */ + float final_local_theta = atanf(opposite / adjacent); + + return side * side_angle + final_local_theta; +} + +static int dof_jitter_total_sample_count(int ring_density, int ring_count) +{ + return ((ring_count * ring_count + ring_count) / 2) * ring_density + 1; } bool EEVEE_depth_of_field_jitter_get(EEVEE_EffectsInfo *fx, - const double ht_point[2], float r_jitter[2], float *r_focus_distance) { if (fx->dof_jitter_radius == 0.0f) { return false; } - /* Maybe would be better to have another sequence ? */ - r_jitter[0] = ht_point[0]; - r_jitter[1] = ht_point[1]; + + int ring_density = CAMERA_JITTER_RING_DENSITY; + int ring_count = fx->dof_jitter_ring_count; + int sample_count = dof_jitter_total_sample_count(ring_density, ring_count); + + int s = fx->taa_current_sample - 1; + + int ring = 0; + int ring_sample_count = 1; + int ring_sample = 1; + + s = s * (ring_density - 1); + s = s % sample_count; + + int samples_passed = 1; + while (s >= samples_passed) { + ring++; + ring_sample_count = ring * ring_density; + ring_sample = s - samples_passed; + ring_sample = (ring_sample + 1) % ring_sample_count; + samples_passed += ring_sample_count; + } + + r_jitter[0] = (float)ring / ring_count; + r_jitter[1] = (float)ring_sample / ring_sample_count; { /* Bokeh shape parametrisation */ - if (fx->dof_jitter_blades == 0.0f) { - float r = sqrtf(r_jitter[0]); - float T = r_jitter[1] * 2.0f * M_PI; + float r = r_jitter[0]; + float T = r_jitter[1] * 2.0f * M_PI; - r_jitter[0] = r * cosf(T); - r_jitter[1] = r * sinf(T); - } - else { - regular_polygon_sample( - fx->dof_jitter_blades, fx->dof_bokeh_rotation, r_jitter[0], r_jitter[1], r_jitter); + if (fx->dof_jitter_blades >= 3.0f) { + T = circle_to_polygon_angle(fx->dof_jitter_blades, T); + r *= circle_to_polygon_radius(fx->dof_jitter_blades, T); } + T += fx->dof_bokeh_rotation; + + r_jitter[0] = r * cosf(T); + r_jitter[1] = r * sinf(T); + mul_v2_v2(r_jitter, fx->dof_bokeh_aniso); } @@ -118,6 +164,36 @@ bool EEVEE_depth_of_field_jitter_get(EEVEE_EffectsInfo *fx, return true; } +int EEVEE_depth_of_field_sample_count_get(EEVEE_EffectsInfo *fx, + int sample_count, + int *r_ring_count) +{ + if (fx->dof_jitter_radius == 0.0f) { + if (r_ring_count != NULL) { + *r_ring_count = 0; + } + return 1; + } + + if (sample_count == TAA_MAX_SAMPLE) { + /* Special case for viewport continuous rendering. We clamp to a max sample to avoid the + * jittered dof never converging. */ + sample_count = 1024; + } + /* Inversion of dof_jitter_total_sample_count. */ + float x = 2.0f * (sample_count - 1.0f) / CAMERA_JITTER_RING_DENSITY; + /* Solving polynomial. We only search positive solution. */ + float discriminant = 1.0f + 4.0f * x; + int ring_count = ceilf(0.5f * (sqrt(discriminant) - 1.0f)); + + sample_count = dof_jitter_total_sample_count(CAMERA_JITTER_RING_DENSITY, ring_count); + + if (r_ring_count != NULL) { + *r_ring_count = ring_count; + } + return sample_count; +} + int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera) @@ -185,18 +261,24 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), effects->dof_jitter_focus = focus_dist; effects->dof_jitter_blades = blades; - int sample_count = DRW_state_is_image_render() ? stl->g_data->render_tot_samples : - scene_eval->eevee.taa_samples; - /* Set to very high value in case of continuous rendering. */ - sample_count = (sample_count == 0) ? 1024 : sample_count; - - /* Compute a minimal overblur radius to fill the gaps between the samples. - * This is just the simplified form of dividing the area of the bokeh - * by the number of samples. */ - float minimal_overblur = 1.0f / sqrtf(sample_count); - float user_overblur = scene_eval->eevee.bokeh_overblur / 100.0f; - - effects->dof_coc_params[1] *= minimal_overblur + user_overblur; + int sample_count = EEVEE_temporal_sampling_sample_count_get(scene_eval, stl); + sample_count = EEVEE_depth_of_field_sample_count_get( + effects, sample_count, &effects->dof_jitter_ring_count); + + if (effects->dof_jitter_ring_count == 0) { + effects->dof_jitter_radius = 0.0f; + } + else { + /* Compute a minimal overblur radius to fill the gaps between the samples. + * This is just the simplified form of dividing the area of the bokeh + * by the number of samples. */ + float minimal_overblur = 1.0f / sqrtf(sample_count); + float user_overblur = scene_eval->eevee.bokeh_overblur / 100.0f; + + effects->dof_coc_params[1] *= minimal_overblur + user_overblur; + /* Avoid dilating the shape. Overblur only soften. */ + effects->dof_jitter_radius -= effects->dof_coc_params[1]; + } } else { effects->dof_jitter_radius = 0.0f; diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index ca583143572..9d3aaea4adc 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -102,11 +102,9 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, effects->enabled_effects |= EEVEE_occlusion_init(sldata, vedata); effects->enabled_effects |= EEVEE_screen_raytrace_init(sldata, vedata); - if ((effects->enabled_effects & EFFECT_TAA) && effects->taa_current_sample > 1) { - /* Update matrices here because EEVEE_screen_raytrace_init can have reset the - * taa_current_sample. (See T66811) */ - EEVEE_temporal_sampling_update_matrices(vedata); - } + /* Update matrices here because EEVEE_screen_raytrace_init can have reset the + * taa_current_sample. (See T66811) */ + EEVEE_temporal_sampling_update_matrices(vedata); EEVEE_volumes_init(sldata, vedata); EEVEE_subsurface_init(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index c6760de5cfa..0a3c7ddff49 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -456,13 +456,17 @@ static void eevee_render_to_image(void *vedata, } EEVEE_PrivateData *g_data = ved->stl->g_data; - EEVEE_render_modules_init(vedata, engine, depsgraph); - int initial_frame = CFRA; float initial_subframe = SUBFRA; float shuttertime = (do_motion_blur) ? scene->eevee.motion_blur_shutter : 0.0f; int time_steps_tot = (do_motion_blur) ? max_ii(1, scene->eevee.motion_blur_steps) : 1; - g_data->render_tot_samples = divide_ceil_u(scene->eevee.taa_render_samples, time_steps_tot); + g_data->render_timesteps = time_steps_tot; + + EEVEE_render_modules_init(vedata, engine, depsgraph); + + g_data->render_sample_count_per_timestep = EEVEE_temporal_sampling_sample_count_get(scene, + ved->stl); + /* Compute start time. The motion blur will cover `[time ...time + shuttertime]`. */ float time = initial_frame + initial_subframe; switch (scene->eevee.motion_blur_position) { @@ -553,7 +557,8 @@ static void eevee_render_to_image(void *vedata, /* Actual drawing. */ { - EEVEE_renderpasses_output_init(sldata, vedata, g_data->render_tot_samples * time_steps_tot); + EEVEE_renderpasses_output_init( + sldata, vedata, g_data->render_sample_count_per_timestep * time_steps_tot); EEVEE_temporal_sampling_create_view(vedata); EEVEE_render_draw(vedata, engine, render_layer, rect); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 11b4d5e4679..1ad11ab03c7 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -55,6 +55,9 @@ extern struct DrawEngineType draw_engine_eevee_type; #define MAX_BLOOM_STEP 16 #define MAX_AOVS 64 +/* Special value chosen to not be altered by depth of field sample count. */ +#define TAA_MAX_SAMPLE 10000926 + // #define DEBUG_SHADOW_DISTRIBUTION /* Only define one of these. */ @@ -779,6 +782,7 @@ typedef struct EEVEE_EffectsInfo { float dof_jitter_radius; float dof_jitter_blades; float dof_jitter_focus; + int dof_jitter_ring_count; float dof_coc_params[2], dof_coc_near_dist, dof_coc_far_dist; float dof_bokeh_blades, dof_bokeh_rotation, dof_bokeh_aniso[2], dof_bokeh_max_size; float dof_bokeh_aniso_inv[2]; @@ -1079,7 +1083,8 @@ typedef struct EEVEE_PrivateData { /** For rendering planar reflections. */ struct DRWView *planar_views[MAX_PLANAR]; - int render_tot_samples; + int render_timesteps; + int render_sample_count_per_timestep; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ @@ -1317,9 +1322,11 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, O void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_depth_of_field_draw(EEVEE_Data *vedata); bool EEVEE_depth_of_field_jitter_get(EEVEE_EffectsInfo *effects, - const double ht_point[2], float r_jitter[2], float *r_focus_distance); +int EEVEE_depth_of_field_sample_count_get(EEVEE_EffectsInfo *effects, + int sample_count, + int *r_ring_count); /* eevee_bloom.c */ int EEVEE_bloom_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); @@ -1433,6 +1440,7 @@ int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov); /* eevee_temporal_sampling.c */ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata); void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata); +int EEVEE_temporal_sampling_sample_count_get(const Scene *scene, const EEVEE_StorageList *stl); int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_temporal_sampling_offset_calc(const double ht_point[2], const float filter_size, diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index bb974688404..e689ed972f1 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -563,7 +563,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* Sort transparents before the loop. */ DRW_pass_sort_shgroup_z(psl->transparent_pass); - uint tot_sample = stl->g_data->render_tot_samples; + uint tot_sample = stl->g_data->render_sample_count_per_timestep; uint render_samples = 0; /* SSR needs one iteration to start properly. */ diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index f9f2886f3de..8fa7d899b6b 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -155,7 +155,7 @@ void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const dou /* Jitter is in pixel space. Focus distance in world space units. */ float dof_jitter[2], focus_distance; - if (EEVEE_depth_of_field_jitter_get(effects, ht_point, dof_jitter, &focus_distance)) { + if (EEVEE_depth_of_field_jitter_get(effects, dof_jitter, &focus_distance)) { /* Convert to NDC space [-1..1]. */ dof_jitter[0] /= viewport_size[0] * 0.5f; dof_jitter[1] /= viewport_size[1] * 0.5f; @@ -230,6 +230,21 @@ void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata) DRW_view_clip_planes_set(effects->taa_view, NULL, 0); } +int EEVEE_temporal_sampling_sample_count_get(const Scene *scene, const EEVEE_StorageList *stl) +{ + const bool is_render = DRW_state_is_image_render(); + int sample_count = is_render ? scene->eevee.taa_render_samples : scene->eevee.taa_samples; + int timesteps = is_render ? stl->g_data->render_timesteps : 1; + + sample_count = max_ii(0, sample_count); + sample_count = (sample_count == 0) ? TAA_MAX_SAMPLE : sample_count; + sample_count = divide_ceil_u(sample_count, timesteps); + + int dof_sample_count = EEVEE_depth_of_field_sample_count_get(stl->effects, sample_count, NULL); + sample_count = dof_sample_count * divide_ceil_u(sample_count, dof_sample_count); + return sample_count; +} + int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -274,10 +289,12 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data view_is_valid = view_is_valid && (ED_screen_animation_no_scrub(wm) == NULL); } - const bool first_sample_only = EEVEE_renderpasses_only_first_sample_pass_active(vedata); - view_is_valid = view_is_valid && !first_sample_only; - effects->taa_total_sample = first_sample_only ? 1 : scene_eval->eevee.taa_samples; - MAX2(effects->taa_total_sample, 0); + effects->taa_total_sample = EEVEE_temporal_sampling_sample_count_get(scene_eval, stl); + + if (EEVEE_renderpasses_only_first_sample_pass_active(vedata)) { + view_is_valid = false; + effects->taa_total_sample = 1; + } /* Motion blur steps could reset the sampling when camera is animated (see T79970). */ if (!DRW_state_is_scene_render()) { |