Eevee: Lookdev: Cleanup implementation & support for Bloom and TAA

Make Lookdev works with bloom and TAA by rendering it before TAA and fixing
the motion vectors of the lookdev balls.

Rework Lookdev to remove much of its complexity. Use simpler matrices with
more understandable setup code.
This commit is contained in:
Clément Foucault 2019-04-30 22:23:54 +02:00
parent b581f19292
commit e66629c128
Notes: blender-bot 2023-02-14 05:28:01 +01:00
Referenced by issue #64093, Look Dev Preview's balls are huge!
7 changed files with 164 additions and 155 deletions

View File

@ -533,22 +533,30 @@ void EEVEE_draw_alpha_checker(EEVEE_Data *vedata)
}
}
void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
static void EEVEE_velocity_resolve(EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
/* First resolve the velocity. */
if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) {
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
e_data.depth_src = dtxl->depth;
DRW_viewport_matrix_get(effects->velocity_curr_persinv, DRW_MAT_PERSINV);
GPU_framebuffer_bind(fbl->velocity_resolve_fb);
DRW_draw_pass(psl->velocity_resolve);
}
DRW_viewport_matrix_get(effects->velocity_past_persmat, DRW_MAT_PERS);
}
void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
{
EEVEE_TextureList *txl = vedata->txl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
/* only once per frame after the first post process */
effects->swap_double_buffer = ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0);
@ -560,6 +568,14 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
/* Post process stack (order matters) */
EEVEE_motion_blur_draw(vedata);
EEVEE_depth_of_field_draw(vedata);
/* NOTE: Lookdev drawing happens before TAA but after
* motion blur and dof to avoid distortions.
* Velocity resolve use a hack to exclude lookdev
* balls from creating shimering reprojection vectors. */
EEVEE_lookdev_draw(vedata);
EEVEE_velocity_resolve(vedata);
EEVEE_temporal_sampling_draw(vedata);
EEVEE_bloom_draw(vedata);

View File

@ -301,10 +301,6 @@ static void eevee_draw_background(void *vedata)
}
}
/* LookDev */
EEVEE_lookdev_draw_background(vedata);
/* END */
/* Tonemapping and transfer result to default framebuffer. */
bool use_render_settings = stl->g_data->use_color_render_settings;

View File

@ -24,6 +24,9 @@
#include "BKE_camera.h"
#include "BKE_studiolight.h"
#include "BLI_rect.h"
#include "BLI_rand.h"
#include "DNA_screen_types.h"
#include "DNA_world_types.h"
@ -62,11 +65,28 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
{
EEVEE_StorageList *stl = vedata->stl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_PrivateData *g_data = stl->g_data;
const DRWContextState *draw_ctx = DRW_context_state_get();
View3D *v3d = draw_ctx->v3d;
Scene *scene = draw_ctx->scene;
/* Viewport / Ball size. */
rcti rect;
ED_region_visible_rect(draw_ctx->ar, &rect);
const int ball_size = max_ii(BLI_rcti_size_x(&rect) * 0.1f, 100.0f) * U.dpi_fac;
if (ball_size != effects->ball_size || rect.xmax != effects->anchor[0] ||
rect.ymin != effects->anchor[1]) {
/* If ball size or anchor point moves, reset TAA to avoid ghosting issue.
* This needs to happen early because we are changing taa_current_sample. */
effects->ball_size = ball_size;
effects->anchor[0] = rect.xmax;
effects->anchor[1] = rect.ymin;
EEVEE_temporal_sampling_reset(vedata);
}
if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) {
StudioLight *sl = BKE_studiolight_find(v3d->shading.lookdev_light,
STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE);
@ -157,56 +177,35 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
}
}
void EEVEE_lookdev_draw_background(EEVEE_Data *vedata)
static void eevee_lookdev_apply_taa(const EEVEE_EffectsInfo *effects,
int ball_size,
float winmat[4][4])
{
if (DRW_state_is_image_render() || ((effects->enabled_effects & EFFECT_TAA) != 0)) {
double ht_point[2];
double ht_offset[2] = {0.0, 0.0};
uint ht_primes[2] = {2, 3};
float ofs[2];
BLI_halton_2d(ht_primes, ht_offset, effects->taa_current_sample, ht_point);
EEVEE_temporal_sampling_offset_calc(ht_point, 1.5f, ofs);
winmat[3][0] += ofs[0] / ball_size;
winmat[3][1] += ofs[1] / ball_size;
}
}
void EEVEE_lookdev_draw(EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
if (psl->lookdev_pass && LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) {
DRW_stats_group_start("Look Dev");
CameraParams params;
BKE_camera_params_init(&params);
View3D *v3d = draw_ctx->v3d;
RegionView3D *rv3d = draw_ctx->rv3d;
ARegion *ar = draw_ctx->ar;
const float *viewport_size = DRW_viewport_size_get();
rcti rect;
ED_region_visible_rect(draw_ctx->ar, &rect);
const float viewport_size_target[2] = {
viewport_size[0] / 4,
viewport_size[1] / 4,
};
const int viewport_inset[2] = {
max_ii(viewport_size_target[0], 300),
max_ii(viewport_size_target[0], 300) / 2, /* intentionally use 'x' here for 'y' value. */
};
/* minimum size for preview spheres viewport */
const float aspect[2] = {
viewport_inset[0] / viewport_size_target[0],
viewport_inset[1] / viewport_size_target[1],
};
BKE_camera_params_from_view3d(&params, draw_ctx->depsgraph, v3d, rv3d);
params.is_ortho = true;
params.ortho_scale = 3.0f;
params.zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
params.offsetx = 0.0f;
params.offsety = 0.0f;
params.shiftx = 0.0f;
params.shifty = 0.0f;
params.clip_start = 0.001f;
params.clip_end = 20.0f;
BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, aspect[0], aspect[1]);
BKE_camera_params_compute_matrix(&params);
if (psl->lookdev_diffuse_pass && LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) {
/* Config renderer. */
EEVEE_CommonUniformBuffer *common = &sldata->common_data;
common->la_num_light = 0;
common->prb_num_planar = 0;
@ -218,34 +217,53 @@ void EEVEE_lookdev_draw_background(EEVEE_Data *vedata)
DRW_uniformbuffer_update(sldata->common_ubo, common);
/* override matrices */
float winmat[4][4];
float winmat_inv[4][4];
copy_m4_m4(winmat, params.winmat);
invert_m4_m4(winmat_inv, winmat);
DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
DRW_viewport_matrix_override_set(winmat_inv, DRW_MAT_WININV);
float viewmat[4][4];
DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
float persmat[4][4];
float persmat_inv[4][4];
mul_m4_m4m4(persmat, winmat, viewmat);
invert_m4_m4(persmat_inv, persmat);
DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
DRW_viewport_matrix_override_set(persmat_inv, DRW_MAT_PERSINV);
DRWMatrixState matstate;
unit_m4(matstate.winmat);
GPUFrameBuffer *fb = effects->final_fb;
GPU_framebuffer_bind(fb);
GPU_framebuffer_viewport_set(
fb, rect.xmax - viewport_inset[0], rect.ymin, viewport_inset[0], viewport_inset[1]);
DRW_draw_pass(psl->lookdev_pass);
eevee_lookdev_apply_taa(effects, effects->ball_size, matstate.winmat);
/* "Remove" view matrix location. Leaving only rotation. */
DRW_viewport_matrix_get(matstate.viewmat, DRW_MAT_VIEW);
zero_v3(matstate.viewmat[3]);
mul_m4_m4m4(matstate.persmat, matstate.winmat, matstate.viewmat);
invert_m4_m4(matstate.wininv, matstate.winmat);
invert_m4_m4(matstate.viewinv, matstate.viewmat);
invert_m4_m4(matstate.persinv, matstate.persmat);
DRW_viewport_matrix_override_set_all(&matstate);
/* Find the right framebuffers to render to. */
GPUFrameBuffer *fb = (effects->target_buffer == fbl->effect_color_fb) ? fbl->main_fb :
fbl->effect_fb;
DRW_stats_group_start("Look Dev");
fb = dfbl->depth_only_fb;
GPU_framebuffer_bind(fb);
GPU_framebuffer_viewport_set(
fb, rect.xmax - viewport_inset[0], rect.ymin, viewport_inset[0], viewport_inset[1]);
DRW_draw_pass(psl->lookdev_pass);
const int ball_margin = effects->ball_size / 6.0f;
float offset[2] = {0.0f, ball_margin};
offset[0] = effects->ball_size + ball_margin;
GPU_framebuffer_viewport_set(fb,
effects->anchor[0] - offset[0],
effects->anchor[1] + offset[1],
effects->ball_size,
effects->ball_size);
DRW_draw_pass(psl->lookdev_diffuse_pass);
offset[0] = (effects->ball_size + ball_margin) +
(ball_margin + effects->ball_size + ball_margin);
GPU_framebuffer_viewport_set(fb,
effects->anchor[0] - offset[0],
effects->anchor[1] + offset[1],
effects->ball_size,
effects->ball_size);
DRW_draw_pass(psl->lookdev_glossy_pass);
DRW_stats_group_end();
DRW_viewport_matrix_override_unset_all();
DRW_stats_group_end();
}
}

View File

@ -336,7 +336,10 @@ static char *eevee_get_defines(int options)
BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND_VOLUMETRICS\n");
}
if ((options & VAR_MAT_LOOKDEV) != 0) {
/* Auto config shadow method. Avoid more permutation. */
BLI_assert((options & (VAR_MAT_VSM | VAR_MAT_ESM)) == 0);
BLI_dynstr_append(ds, "#define LOOKDEV\n");
BLI_dynstr_append(ds, "#define SHADOW_ESM\n");
}
str = BLI_dynstr_get_cstring(ds);
@ -995,42 +998,11 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
}
}
/**
* Create a default shading group inside the lookdev pass without standard uniforms.
*/
static struct DRWShadingGroup *EEVEE_lookdev_shading_group_get(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
bool use_ssr,
int shadow_method)
{
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
int options = VAR_MAT_MESH | VAR_MAT_LOOKDEV;
options |= eevee_material_shadow_option(shadow_method);
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
}
if (vedata->psl->lookdev_pass == NULL) {
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS |
DRW_STATE_CULL_BACK;
vedata->psl->lookdev_pass = DRW_pass_create("LookDev Pass", state);
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options],
vedata->psl->lookdev_pass);
/* XXX / WATCH: This creates non persistent binds for the ubos and textures.
* But it's currently OK because the following shgroups does not add any bind. */
add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false);
}
return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->lookdev_pass);
}
void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
/* Create Material Ghash */
{
@ -1044,16 +1016,13 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = NULL;
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
World *wo = scene->world;
const float *col = G_draw.block.colorBackground;
/* LookDev */
EEVEE_lookdev_cache_init(
vedata, &grp, psl->background_pass, stl->g_data->background_alpha, wo, NULL);
/* END */
if (!grp && wo) {
col = &wo->horr;
@ -1184,6 +1153,39 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1);
DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
if (LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) {
DRWShadingGroup *shgrp;
struct GPUBatch *sphere = DRW_cache_sphere_get();
static float color_chrome[3] = {1.0f, 1.0f, 1.0f};
static float color_diffuse[3] = {0.8f, 0.8f, 0.8f};
int options = VAR_MAT_MESH | VAR_MAT_LOOKDEV;
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
}
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS |
DRW_STATE_CULL_BACK;
psl->lookdev_diffuse_pass = DRW_pass_create("LookDev Diffuse Pass", state);
shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_diffuse_pass);
add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, true, true, false, false, false);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_diffuse, 1);
DRW_shgroup_uniform_float_copy(shgrp, "metallic", 0.0f);
DRW_shgroup_uniform_float_copy(shgrp, "specular", 0.5f);
DRW_shgroup_uniform_float_copy(shgrp, "roughness", 1.0f);
DRW_shgroup_call_add(shgrp, sphere, NULL);
psl->lookdev_glossy_pass = DRW_pass_create("LookDev Glossy Pass", state);
shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_glossy_pass);
add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, true, true, false, false, false);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_chrome, 1);
DRW_shgroup_uniform_float_copy(shgrp, "metallic", 1.0f);
DRW_shgroup_uniform_float_copy(shgrp, "roughness", 0.0f);
DRW_shgroup_call_add(shgrp, sphere, NULL);
}
}
#define ADD_SHGROUP_CALL(shgrp, ob, ma, geom, oedata) \
@ -1926,46 +1928,6 @@ void EEVEE_materials_cache_finish(EEVEE_Data *vedata)
{
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
/* Look-Dev */
const DRWContextState *draw_ctx = DRW_context_state_get();
const View3D *v3d = draw_ctx->v3d;
if (LOOK_DEV_OVERLAY_ENABLED(v3d)) {
EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
EEVEE_LightsInfo *linfo = sldata->lights;
struct GPUBatch *sphere = DRW_cache_sphere_get();
static float mat1[4][4];
static float color[3] = {0.8f, 0.8f, 0.8f};
static float metallic_on = 1.0f;
static float metallic_off = 0.00f;
static float specular_off = 0.5f;
static float specular_on = 1.0f;
static float roughness_off = 0.05f;
static float roughness_on = 1.00f;
float view_mat[4][4];
DRW_viewport_matrix_get(view_mat, DRW_MAT_VIEWINV);
DRWShadingGroup *shgrp = EEVEE_lookdev_shading_group_get(
sldata, vedata, false, linfo->shadow_method);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", &metallic_on, 1);
DRW_shgroup_uniform_float(shgrp, "specular", &specular_on, 1);
DRW_shgroup_uniform_float(shgrp, "roughness", &roughness_off, 1);
unit_m4(mat1);
mul_m4_m4m4(mat1, mat1, view_mat);
translate_m4(mat1, -1.5f, 0.0f, -5.0f);
DRW_shgroup_call_add(shgrp, sphere, mat1);
shgrp = EEVEE_lookdev_shading_group_get(sldata, vedata, false, linfo->shadow_method);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", &metallic_off, 1);
DRW_shgroup_uniform_float(shgrp, "specular", &specular_off, 1);
DRW_shgroup_uniform_float(shgrp, "roughness", &roughness_on, 1);
translate_m4(mat1, 3.0f, 0.0f, 0.0f);
DRW_shgroup_call_add(shgrp, sphere, mat1);
}
/* END */
BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN);
}

View File

@ -276,7 +276,8 @@ typedef struct EEVEE_PassList {
struct DRWPass *transparent_pass;
struct DRWPass *background_pass;
struct DRWPass *update_noise_pass;
struct DRWPass *lookdev_pass;
struct DRWPass *lookdev_glossy_pass;
struct DRWPass *lookdev_diffuse_pass;
} EEVEE_PassList;
typedef struct EEVEE_FramebufferList {
@ -605,6 +606,9 @@ typedef struct EEVEE_EffectsInfo {
float color_checker_light[4];
/* Other */
float prev_persmat[4][4];
/* Lookdev */
int ball_size;
int anchor[2];
/* Bloom */
int bloom_iteration_len;
float source_texel_size[2];
@ -1049,6 +1053,9 @@ void EEVEE_mist_free(void);
/* eevee_temporal_sampling.c */
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
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,
float r_offset[2]);
void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects,
float viewmat[4][4],
float persmat[4][4],
@ -1105,7 +1112,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
float background_alpha,
struct World *world,
EEVEE_LightProbesInfo *pinfo);
void EEVEE_lookdev_draw_background(EEVEE_Data *vedata);
void EEVEE_lookdev_draw(EEVEE_Data *vedata);
/** eevee_engine.c */
void EEVEE_cache_populate(void *vedata, Object *ob);

View File

@ -131,6 +131,14 @@ static void eevee_create_cdf_table_temporal_sampling(void)
e_data.inited = true;
}
void EEVEE_temporal_sampling_offset_calc(const double ht_point[2],
const float filter_size,
float r_offset[2])
{
r_offset[0] = eval_table(e_data.inverted_cdf, (float)(ht_point[0])) * filter_size;
r_offset[1] = eval_table(e_data.inverted_cdf, (float)(ht_point[1])) * filter_size;
}
void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects,
float viewmat[4][4],
float persmat[4][4],
@ -141,13 +149,11 @@ void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects,
Scene *scene = draw_ctx->scene;
RenderData *rd = &scene->r;
float filter_size = rd->gauss; /* Sigh.. Stupid legacy naming. */
float ofs_x = eval_table(e_data.inverted_cdf, (float)(ht_point[0])) * filter_size;
float ofs_y = eval_table(e_data.inverted_cdf, (float)(ht_point[1])) * filter_size;
float ofs[2];
EEVEE_temporal_sampling_offset_calc(ht_point, rd->gauss, ofs);
window_translate_m4(
effects->overide_winmat, persmat, ofs_x / viewport_size[0], ofs_y / viewport_size[1]);
effects->overide_winmat, persmat, ofs[0] / viewport_size[0], ofs[1] / viewport_size[1]);
mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat);
invert_m4_m4(effects->overide_persinv, effects->overide_persmat);
@ -157,6 +163,7 @@ void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects,
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata)
{
vedata->stl->effects->taa_render_sample = 1;
vedata->stl->effects->taa_current_sample = 1;
}
int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)

View File

@ -17,6 +17,9 @@ void main()
outData = uv - uv_history;
/* HACK: Reject lookdev spheres from TAA reprojection. */
outData = (depth > 0.0) ? outData : vec2(0.0);
/* Encode to unsigned normalized 16bit texture. */
outData = outData * 0.5 + 0.5;
}