Overlay: Flash on Mode Transfer overlay

This implements T87633

This overlay renders a flash animation on the target object when
transfering the mode to it using the mode transfer operator.
This provides visual feedback when switching between objects without
extra overlays that affect the general color and lighting in the scene.

Differences with the design task:

- This uses just a fade out animation instead of a fade in/out animation.
The code is ready for fade in/out, but as the rest of the overlays
(face sets, masks...) change instantly without animation, having a fade
in/out effect gives the impression that the object flashes twice (once
for the face sets, twice for the peak alpha of the flash animation).

- The rendering uses a flat color without fresnel for now, but this can
be improved in the future to make it look more like the shader in the
prototype.

- Not enabled by default (can be enabled in the overlays panel), maybe
the defaults can change for 3.0 to disable fade inactive and enable this
instead.

Reviewed By: jbakker, JulienKaspar

Differential Revision: https://developer.blender.org/D11055
This commit is contained in:
Pablo Dobarro 2021-05-18 01:03:01 +02:00
parent 3e695a27cd
commit dba3fb9e09
9 changed files with 206 additions and 0 deletions

View File

@ -6186,6 +6186,9 @@ class VIEW3D_PT_overlay_geometry(Panel):
sub.active = overlay.show_fade_inactive
sub.prop(overlay, "fade_inactive_alpha", text="Fade Inactive Geometry")
row = col.row(align=True)
row.prop(overlay, "show_mode_transfer", text="Flash on Mode Transfer")
col = layout.column(align=True)
col.active = display_all

View File

@ -149,6 +149,7 @@ set(SRC
engines/overlay/overlay_image.c
engines/overlay/overlay_lattice.c
engines/overlay/overlay_metaball.c
engines/overlay/overlay_mode_transfer.c
engines/overlay/overlay_motion_path.c
engines/overlay/overlay_outline.c
engines/overlay/overlay_paint.c

View File

@ -207,6 +207,7 @@ static void OVERLAY_cache_init(void *vedata)
OVERLAY_armature_cache_init(vedata);
OVERLAY_background_cache_init(vedata);
OVERLAY_fade_cache_init(vedata);
OVERLAY_mode_transfer_cache_init(vedata);
OVERLAY_extra_cache_init(vedata);
OVERLAY_facing_cache_init(vedata);
OVERLAY_gpencil_cache_init(vedata);
@ -323,6 +324,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
!is_select;
const bool draw_fade = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FADE_INACTIVE) &&
overlay_should_fade_object(ob, draw_ctx->obact);
const bool draw_mode_transfer = draw_surface && (pd->overlay.flag & V3D_OVERLAY_MODE_TRANSFER);
const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0;
const bool draw_wires = draw_surface && has_surface &&
(pd->wireframe_mode || !pd->hide_overlays);
@ -349,6 +351,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
if (draw_facing) {
OVERLAY_facing_cache_populate(vedata, ob);
}
if (draw_mode_transfer) {
OVERLAY_mode_transfer_cache_populate(vedata, ob);
}
if (draw_wires) {
OVERLAY_wireframe_cache_populate(vedata, ob, dupli, do_init);
}
@ -504,6 +509,7 @@ static void OVERLAY_cache_finish(void *vedata)
{GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
}
OVERLAY_mode_transfer_cache_finish(vedata);
OVERLAY_antialiasing_cache_finish(vedata);
OVERLAY_armature_cache_finish(vedata);
OVERLAY_image_cache_finish(vedata);
@ -566,6 +572,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_image_draw(vedata);
OVERLAY_fade_draw(vedata);
OVERLAY_facing_draw(vedata);
OVERLAY_mode_transfer_draw(vedata);
OVERLAY_extra_blend_draw(vedata);
OVERLAY_volume_draw(vedata);
@ -605,6 +612,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_fade_infront_draw(vedata);
OVERLAY_facing_infront_draw(vedata);
OVERLAY_mode_transfer_infront_draw(vedata);
if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(fbl->overlay_line_in_front_fb);

View File

@ -0,0 +1,159 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2021, Blender Foundation.
*/
/** \file
* \ingroup draw_engine
*/
#include "BKE_paint.h"
#include "DRW_render.h"
#include "ED_view3d.h"
#include "PIL_time.h"
#include "UI_resources.h"
#include "overlay_private.h"
void OVERLAY_mode_transfer_cache_init(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
pd->mode_transfer.time = PIL_check_seconds_timer();
for (int i = 0; i < 2; i++) {
/* Non Meshes Pass (Camera, empties, lights ...) */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->mode_transfer_ps[i], state | pd->clipping_state);
}
}
#define MODE_TRANSFER_FLASH_LENGTH 0.55f
/* TODO(pablodp606): Remove this option for 3.0 if fade in/out is not used. */
#define MODE_TRANSFER_FLASH_FADE 0.0f
#define MODE_TRANSFER_FLASH_MAX_ALPHA 0.25f
static bool mode_transfer_is_animation_running(const float anim_time)
{
return anim_time >= 0.0f && anim_time <= MODE_TRANSFER_FLASH_LENGTH;
}
static float mode_transfer_alpha_for_animation_time_get(const float anim_time)
{
if (anim_time > MODE_TRANSFER_FLASH_LENGTH) {
return 0.0f;
}
if (anim_time < 0.0f) {
return 0.0f;
}
if (MODE_TRANSFER_FLASH_FADE <= 0.0f) {
return (1.0f - (anim_time / MODE_TRANSFER_FLASH_LENGTH)) * MODE_TRANSFER_FLASH_MAX_ALPHA;
}
const float flash_fade_in_time = MODE_TRANSFER_FLASH_LENGTH * MODE_TRANSFER_FLASH_FADE;
const float flash_fade_out_time = MODE_TRANSFER_FLASH_LENGTH - flash_fade_in_time;
float alpha = 0.0f;
if (anim_time < flash_fade_in_time) {
alpha = anim_time / flash_fade_in_time;
}
else {
const float fade_out_anim_time = anim_time - flash_fade_in_time;
alpha = 1.0f - (fade_out_anim_time / flash_fade_out_time);
}
return alpha * MODE_TRANSFER_FLASH_MAX_ALPHA;
}
void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob)
{
OVERLAY_PrivateData *pd = vedata->stl->pd;
OVERLAY_PassList *psl = vedata->psl;
if (pd->xray_enabled) {
return;
}
const float animation_time = pd->mode_transfer.time -
ob->runtime.overlay_mode_transfer_start_time;
if (!mode_transfer_is_animation_running(animation_time)) {
return;
}
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
!DRW_state_is_image_render();
const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
DRWShadingGroup *mode_transfer_grp[2];
for (int i = 0; i < 2; i++) {
GPUShader *sh = OVERLAY_shader_uniform_color();
mode_transfer_grp[i] = DRW_shgroup_create(sh, psl->mode_transfer_ps[i]);
DRW_shgroup_uniform_block(mode_transfer_grp[i], "globalsBlock", G_draw.block_ubo);
float color[4];
UI_GetThemeColor3fv(TH_VERTEX_SELECT, color);
color[3] = mode_transfer_alpha_for_animation_time_get(animation_time);
srgb_to_linearrgb_v4(color, color);
DRW_shgroup_uniform_vec4_copy(mode_transfer_grp[i], "color", color);
}
if (!pd->use_in_front) {
mode_transfer_grp[IN_FRONT] = mode_transfer_grp[NOT_IN_FRONT];
}
pd->mode_transfer.any_animated = true;
if (use_sculpt_pbvh) {
DRW_shgroup_call_sculpt(mode_transfer_grp[is_xray], ob, false, false);
}
else {
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
DRW_shgroup_call(mode_transfer_grp[is_xray], geom, ob);
}
}
}
void OVERLAY_mode_transfer_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
DRW_draw_pass(psl->mode_transfer_ps[NOT_IN_FRONT]);
}
void OVERLAY_mode_transfer_infront_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
DRW_draw_pass(psl->mode_transfer_ps[IN_FRONT]);
}
void OVERLAY_mode_transfer_cache_finish(OVERLAY_Data *vedata)
{
OVERLAY_PrivateData *pd = vedata->stl->pd;
if (pd->mode_transfer.any_animated) {
DRW_viewport_request_redraw();
}
pd->mode_transfer.any_animated = false;
}

View File

@ -107,6 +107,7 @@ typedef struct OVERLAY_PassList {
DRWPass *gpencil_canvas_ps;
DRWPass *facing_ps[2];
DRWPass *fade_ps[2];
DRWPass *mode_transfer_ps[2];
DRWPass *grid_ps;
DRWPass *image_background_ps;
DRWPass *image_background_scene_ps;
@ -282,6 +283,7 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *extra_grid_grp;
DRWShadingGroup *facing_grp[2];
DRWShadingGroup *fade_grp[2];
DRWShadingGroup *flash_grp[2];
DRWShadingGroup *motion_path_lines_grp;
DRWShadingGroup *motion_path_points_grp;
DRWShadingGroup *outlines_grp;
@ -414,6 +416,10 @@ typedef struct OVERLAY_PrivateData {
struct {
DRWCallBuffer *handle[2];
} mball;
struct {
double time;
bool any_animated;
} mode_transfer;
} OVERLAY_PrivateData; /* Transient data */
typedef struct OVERLAY_StorageList {
@ -607,6 +613,12 @@ void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_fade_draw(OVERLAY_Data *vedata);
void OVERLAY_fade_infront_draw(OVERLAY_Data *vedata);
void OVERLAY_mode_transfer_cache_init(OVERLAY_Data *vedata);
void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_mode_transfer_draw(OVERLAY_Data *vedata);
void OVERLAY_mode_transfer_infront_draw(OVERLAY_Data *vedata);
void OVERLAY_mode_transfer_cache_finish(OVERLAY_Data *vedata);
void OVERLAY_grid_init(OVERLAY_Data *vedata);
void OVERLAY_grid_cache_init(OVERLAY_Data *vedata);
void OVERLAY_grid_draw(OVERLAY_Data *vedata);

View File

@ -30,6 +30,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "PIL_time.h"
#include "BLT_translation.h"
#include "BKE_context.h"
@ -438,6 +440,13 @@ static void object_transfer_mode_reposition_view_pivot(bContext *C, const int mv
ups->last_stroke_valid = true;
}
static void object_overlay_mode_transfer_animation_start(bContext *C, Object *ob_dst)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob_dst_eval = DEG_get_evaluated_object(depsgraph, ob_dst);
ob_dst_eval->runtime.overlay_mode_transfer_start_time = PIL_check_seconds_timer();
}
static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base_dst)
{
Scene *scene = CTX_data_scene(C);
@ -475,6 +484,8 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
ob_dst_orig = DEG_get_original_object(ob_dst);
ED_object_mode_set_ex(C, last_mode, true, op->reports);
object_overlay_mode_transfer_animation_start(C, ob_dst);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_toolsystem_update_from_context_view3d(C);
mode_transfered = true;

View File

@ -144,6 +144,9 @@ typedef struct Object_Runtime {
*/
char is_data_eval_owned;
/** Start time of the mode transfer overlay animation. */
double overlay_mode_transfer_start_time;
/** Axis aligned boundbox (in localspace). */
struct BoundBox *bb;

View File

@ -515,6 +515,7 @@ enum {
V3D_OVERLAY_HIDE_OBJECT_ORIGINS = (1 << 10),
V3D_OVERLAY_STATS = (1 << 11),
V3D_OVERLAY_FADE_INACTIVE = (1 << 12),
V3D_OVERLAY_MODE_TRANSFER = (1 << 13),
};
/** #View3DOverlay.edit_flag */

View File

@ -4129,6 +4129,14 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop, "Fade Inactive Objects", "Fade inactive geometry using the viewport background color");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_mode_transfer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_MODE_TRANSFER);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop,
"Flash on Mode Transfer",
"Flash the target object when tranfering the active mode to it");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "fade_inactive_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overlay.fade_alpha");
RNA_def_property_ui_text(prop, "Opacity", "Strength of the fade effect");