LineArt: Custom Camera

Allows line art camera to be different from scene active camera,
useful when baking multiple shots in different angle as
well as for motion graphics effect.

Reviewed By: Antonio Vazquez (antoniov)

Differential Revision: https://developer.blender.org/D12047
This commit is contained in:
YimingWu 2021-10-26 23:37:25 +08:00
parent 773f5065f3
commit efbd36429a
Notes: blender-bot 2023-02-14 11:07:28 +01:00
Referenced by issue #87739, Line Art further improvement list
7 changed files with 84 additions and 16 deletions

View File

@ -264,6 +264,12 @@ static void updateDepsgraph(GpencilModifierData *md,
else {
add_this_collection(ctx->scene->master_collection, ctx, mode);
}
if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) {
DEG_add_object_relation(
ctx->node, lmd->source_camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
DEG_add_object_relation(
ctx->node, lmd->source_camera, DEG_OB_COMP_PARAMETERS, "Line Art Modifier");
}
if (ctx->scene->camera) {
DEG_add_object_relation(
ctx->node, ctx->scene->camera, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
@ -280,6 +286,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
walk(userData, ob, (ID **)&lmd->source_collection, IDWALK_CB_NOP);
walk(userData, ob, (ID **)&lmd->source_object, IDWALK_CB_NOP);
walk(userData, ob, (ID **)&lmd->source_camera, IDWALK_CB_NOP);
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
@ -385,7 +392,12 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
return;
}
uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE);
uiLayout *row = uiLayoutRowWithHeading(layout, false, IFACE_("Custom Camera"));
uiItemR(row, ptr, "use_custom_camera", 0, "", 0);
uiLayout *subrow = uiLayoutRow(row, true);
uiLayoutSetActive(subrow, RNA_boolean_get(ptr, "use_custom_camera"));
uiLayoutSetPropSep(subrow, true);
uiItemR(subrow, ptr, "source_camera", 0, "", ICON_OBJECT_DATA);
uiLayout *col = uiLayoutColumn(layout, true);
@ -684,10 +696,11 @@ static void composition_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemL(layout, IFACE_("Object is shown in front"), ICON_ERROR);
}
uiLayout *row = uiLayoutRow(layout, false);
uiLayoutSetActive(row, !show_in_front);
uiLayout *col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, !show_in_front);
uiItemR(row, ptr, "stroke_depth_offset", UI_ITEM_R_SLIDER, IFACE_("Depth Offset"), ICON_NONE);
uiItemR(col, ptr, "stroke_depth_offset", UI_ITEM_R_SLIDER, IFACE_("Depth Offset"), ICON_NONE);
uiItemR(col, ptr, "offset_towards_custom_camera", 0, IFACE_("Towards Custom Camera"), ICON_NONE);
}
static void panelRegister(ARegionType *region_type)

View File

@ -311,6 +311,7 @@ typedef struct LineartRenderBuffer {
bool cam_is_persp;
float cam_obmat[4][4];
double camera_pos[3];
double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */
double near_clip, far_clip;
float shift_x, shift_y;
float crease_threshold;
@ -595,7 +596,9 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold);
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance);
void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, float dist);
void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
float dist,
bool use_custom_camera);
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);

View File

@ -1009,7 +1009,9 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
}
}
void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, float dist)
void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
float dist,
bool use_custom_camera)
{
float dir[3];
float cam[3];
@ -1017,6 +1019,14 @@ void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, float dist
float view_clamp[3];
copy_v3fl_v3db(cam, rb->camera_pos);
copy_v3fl_v3db(view, rb->view_vector);
if (use_custom_camera) {
copy_v3fl_v3db(cam, rb->camera_pos);
}
else {
copy_v3fl_v3db(cam, rb->active_camera_pos);
}
if (rb->cam_is_persp) {
LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {

View File

@ -2998,7 +2998,7 @@ void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
}
}
static LineartCache *lineart_init_cache()
static LineartCache *lineart_init_cache(void)
{
LineartCache *lc = MEM_callocN(sizeof(LineartCache), "Lineart Cache");
return lc;
@ -3016,6 +3016,8 @@ void MOD_lineart_clear_cache(struct LineartCache **lc)
static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
LineartGpencilModifierData *lmd,
Object *camera,
Object *active_camera,
LineartCache *lc)
{
LineartRenderBuffer *rb = MEM_callocN(sizeof(LineartRenderBuffer), "Line Art render buffer");
@ -3024,10 +3026,10 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
lmd->render_buffer_ptr = rb;
lc->rb_edge_types = lmd->edge_types_override;
if (!scene || !scene->camera || !lc) {
if (!scene || !camera || !lc) {
return NULL;
}
Camera *c = scene->camera->data;
Camera *c = camera->data;
double clipping_offset = 0;
if (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) {
@ -3035,8 +3037,11 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
clipping_offset = 0.0001;
}
copy_v3db_v3fl(rb->camera_pos, scene->camera->obmat[3]);
copy_m4_m4(rb->cam_obmat, scene->camera->obmat);
copy_v3db_v3fl(rb->camera_pos, camera->obmat[3]);
if (active_camera) {
copy_v3db_v3fl(rb->active_camera_pos, active_camera->obmat[3]);
}
copy_m4_m4(rb->cam_obmat, camera->obmat);
rb->cam_is_persp = (c->type == CAM_PERSP);
rb->near_clip = c->clip_start + clipping_offset;
rb->far_clip = c->clip_end - clipping_offset;
@ -4082,6 +4087,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartRenderBuffer *rb;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
int intersections_only = 0; /* Not used right now, but preserve for future. */
Object *use_camera;
double t_start;
@ -4091,14 +4097,24 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
BKE_scene_camera_switch_update(scene);
if (!scene->camera) {
return false;
if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) {
if (!lmd->source_camera ||
(use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type !=
OB_CAMERA) {
return false;
}
}
else {
if (!scene->camera) {
return false;
}
use_camera = scene->camera;
}
LineartCache *lc = lineart_init_cache();
*cached_result = lc;
rb = lineart_create_render_buffer(scene, lmd, lc);
rb = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
/* Triangle thread testing data size varies depending on the thread count.
* See definition of LineartTriangleThread for details. */
@ -4118,7 +4134,7 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
/* Get view vector before loading geometries, because we detect feature lines there. */
lineart_main_get_view_vector(rb);
lineart_main_load_geometries(
depsgraph, scene, scene->camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
depsgraph, scene, use_camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
if (!rb->vertex_buffer_pointers.first) {
/* No geometry loaded, return early. */
@ -4191,7 +4207,8 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
}
if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) {
MOD_lineart_chain_offset_towards_camera(rb, lmd->stroke_depth_offset);
MOD_lineart_chain_offset_towards_camera(
rb, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
}
/* Finally transfer the result list into cache. */

View File

@ -978,6 +978,7 @@ typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_BINARY_WEIGHTS = (1 << 2) /* Deprecated, this is removed for lack of use case. */,
LRT_GPENCIL_IS_BAKED = (1 << 3),
LRT_GPENCIL_USE_CACHE = (1 << 4),
LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA = (1 << 5),
} eLineArtGPencilModifierFlags;
typedef enum eLineartGpencilMaskSwitches {
@ -1004,6 +1005,8 @@ typedef struct LineartGpencilModifierData {
short level_start;
short level_end;
struct Object *source_camera;
struct Object *source_object;
struct Collection *source_collection;

View File

@ -49,6 +49,7 @@ typedef enum eLineartMainFlags {
LRT_ALLOW_OVERLAP_EDGE_TYPES = (1 << 14),
LRT_USE_CREASE_ON_SMOOTH_SURFACES = (1 << 15),
LRT_USE_CREASE_ON_SHARP_EDGES = (1 << 16),
LRT_USE_CUSTOM_CAMERA = (1 << 17),
} eLineartMainFlags;
typedef enum eLineartEdgeFlag {

View File

@ -3073,6 +3073,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "use_custom_camera", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_CUSTOM_CAMERA);
RNA_def_property_ui_text(
prop, "Use Custom Camera", "Use custom camera instead of the active camera");
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_fuzzy_intersections", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_INTERSECTION_AS_CONTOUR);
RNA_def_property_ui_text(prop,
@ -3209,6 +3215,21 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 0.5f, 0.001f, 4);
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "offset_towards_custom_camera", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
RNA_def_property_ui_text(prop,
"Offset Towards Custom Camera",
"Offset strokes towards selected camera instead of the active camera");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "source_camera", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop, "Camera Object", "Use specified camera object for generating line art");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
prop = RNA_def_property(srna, "source_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, modifier_lineart_source_type);
RNA_def_property_ui_text(prop, "Source Type", "Line art stroke source type");