Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2021-02-11 05:59:44 +0300
committerClément Foucault <foucault.clem@gmail.com>2021-02-11 06:13:25 +0300
commit7769b89babfab9475770cd3332a4a423d9a0a63a (patch)
tree99938df148a023fc67fb15a6790430b001299aff
parentcccf7387a86bbeff311ecd1c48fa3afbb069f941 (diff)
EEVEE: Depth of Field: Improves jittered camera sampling patterneevee-dof-refactor
Jittered camera now uses an hexaweb sampling pattern that covers the bokeh area better and faster than previous pseudo random solution. The downside is that we need to change the sample count based on the number of rings to fill. We increase the number of samples just to fill the largest ring.
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c168
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c8
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c13
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h12
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c27
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()) {