LineArt: Camera Overscan

Expand camera effective region to a portion beyond image frame so strokes won't end right at the border.

Reviewed By: Antonio Vazquez (antoniov)

Differential Revision: https://developer.blender.org/D12049
This commit is contained in:
YimingWu 2021-07-28 19:55:29 +08:00
parent 544ddcdaac
commit 8e9d06f5a0
Notes: blender-bot 2023-02-14 08:28:46 +01:00
Referenced by issue #87739, Line Art further improvement list
6 changed files with 41 additions and 10 deletions

View File

@ -380,6 +380,8 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
return;
}
uiItemR(layout, ptr, "overscan", 0, NULL, ICON_NONE);
uiLayout *col = uiLayoutColumn(layout, true);
uiItemR(col, ptr, "use_remove_doubles", 0, NULL, ICON_NONE);

View File

@ -228,6 +228,8 @@ typedef struct LineartRenderBuffer {
double view_projection[4][4];
double view[4][4];
float overscan;
struct LineartBoundingArea *initial_bounding_areas;
unsigned int bounding_area_count;

View File

@ -2013,7 +2013,10 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_
use_olti->pending = obi;
}
static bool lineart_geometry_check_visible(double (*model_view_proj)[4], Object *use_ob)
static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
double shift_x,
double shift_y,
Object *use_ob)
{
BoundBox *bb = BKE_object_boundbox_get(use_ob);
if (!bb) {
@ -2027,6 +2030,8 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4], Object
copy_v3db_v3fl(co[i], bb->vec[i]);
copy_v3_v3_db(tmp, co[i]);
mul_v4_m4v3_db(co[i], model_view_proj, tmp);
co[i][0] -= shift_x * 2 * co[i][3];
co[i][1] -= shift_y * 2 * co[i][3];
}
bool cond[6] = {true, true, true, true, true, true};
@ -2062,11 +2067,6 @@ static void lineart_main_load_geometries(
int fit = BKE_camera_sensor_fit(cam->sensor_fit, rb->w, rb->h);
double asp = ((double)rb->w / (double)rb->h);
double t_start;
if (G.debug_value == 4000) {
t_start = PIL_check_seconds_timer();
}
int bound_box_discard_count = 0;
if (cam->type == CAM_PERSP) {
@ -2076,14 +2076,20 @@ static void lineart_main_load_geometries(
if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) {
sensor /= asp;
}
double fov = focallength_to_fov(cam->lens, sensor);
const double fov = focallength_to_fov(cam->lens / (1 + rb->overscan), sensor);
lineart_matrix_perspective_44d(proj, fov, asp, cam->clip_start, cam->clip_end);
}
else if (cam->type == CAM_ORTHO) {
double w = cam->ortho_scale / 2;
const double w = cam->ortho_scale / 2;
lineart_matrix_ortho_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end);
}
double t_start;
if (G.debug_value == 4000) {
t_start = PIL_check_seconds_timer();
}
invert_m4_m4(inv, rb->cam_obmat);
mul_m4db_m4db_m4fl_uniq(result, proj, inv);
copy_m4_m4_db(proj, result);
@ -2130,7 +2136,7 @@ static void lineart_main_load_geometries(
continue;
}
if (!lineart_geometry_check_visible(obi->model_view_proj, use_ob)) {
if (!lineart_geometry_check_visible(obi->model_view_proj, rb->shift_x, rb->shift_y, use_ob)) {
if (G.debug_value == 4000) {
bound_box_discard_count++;
}
@ -3023,6 +3029,11 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp;
rb->shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp;
rb->overscan = lmd->overscan;
rb->shift_x /= (1 + rb->overscan);
rb->shift_y /= (1 + rb->overscan);
rb->crease_threshold = cos(M_PI - lmd->crease_threshold);
rb->angle_splitting_threshold = lmd->angle_splitting_threshold;
rb->chaining_image_threshold = lmd->chaining_image_threshold;

View File

@ -307,6 +307,7 @@
.calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES, \
.angle_splitting_threshold = DEG2RAD(60.0f), \
.chaining_image_threshold = 0.001f, \
.overscan = 0.1f,\
}
#define _DNA_DEFAULT_LengthGpencilModifierData \

View File

@ -963,6 +963,12 @@ typedef struct LineartGpencilModifierData {
char source_vertex_group[64];
char vgname[64];
/* Camera focal length is divided by (1 + overscan), before caluclation, which give a wider FOV,
* this doesn't change coordinates range internally (-1, 1), but makes the caluclated frame
* bigger than actual output. This is for the easier shifting calculation. A value of 0.5 means
* the "internal" focal length become 2/3 of the actual camera. */
float overscan;
float opacity;
short thickness;
@ -970,7 +976,7 @@ typedef struct LineartGpencilModifierData {
unsigned char material_mask_bits;
unsigned char intersection_mask;
char _pad[7];
char _pad[3];
/** `0..1` range for cosine angle */
float crease_threshold;

View File

@ -3137,6 +3137,15 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
"Certain settings will be unavailable");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "overscan", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(
prop,
"Overscan",
"A margin to prevent strokes from ending abruptly at the edge of the image");
RNA_def_property_ui_range(prop, 0.0f, 0.5f, 0.01f, 3);
RNA_def_property_range(prop, 0.0f, 0.5f);
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Thickness", "The thickness for the generated strokes");
RNA_def_property_ui_range(prop, 1, 100, 1, 1);