Sculpt: Add pose origin preview to the Pose Brush

This commit makes the pose brush easier to control. It also includes a refactor of the pose brush init code.

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D5761
This commit is contained in:
Pablo Dobarro 2019-09-13 16:18:22 +02:00
parent 9be5a94cf3
commit 58214ab52a
4 changed files with 89 additions and 25 deletions

View File

@ -270,6 +270,7 @@ typedef struct SculptSession {
/* Dynamic mesh preview */
int *preview_vert_index_list;
int preview_vert_index_count;
float pose_origin[3];
/* Transform operator */
float pivot_pos[3];

View File

@ -1093,17 +1093,15 @@ static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
return true;
}
static void cursor_draw_point_screen_space(const uint gpuattr,
const ARegion *ar,
const float true_location[3],
const float obmat[4][4])
static void cursor_draw_point_screen_space(
const uint gpuattr, const ARegion *ar, float true_location[3], float obmat[4][4], int size)
{
float translation_vertex_cursor[3], location[3];
copy_v3_v3(location, true_location);
mul_m4_v3(obmat, location);
ED_view3d_project(ar, location, translation_vertex_cursor);
imm_draw_circle_fill_3d(
gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], 3, 10);
gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
}
static void cursor_draw_tiling_preview(const uint gpuattr,
@ -1145,7 +1143,7 @@ static void cursor_draw_tiling_preview(const uint gpuattr,
for (dim = 0; dim < 3; dim++) {
location[dim] = cur[dim] * step[dim] + orgLoc[dim];
}
cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
}
}
}
@ -1166,7 +1164,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
/* Axis Symmetry */
flip_v3_v3(location, true_location, (char)i);
cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
/* Tiling */
cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
@ -1181,7 +1179,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
mul_m4_v3(symm_rot_mat, location);
cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
}
}
}
@ -1215,6 +1213,7 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@ -1338,8 +1337,14 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
if (!ups->stroke_active) {
SculptCursorGeometryInfo gi;
float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin};
int prev_active_vertex_index = ss->active_vertex_index;
bool update_previews = false;
if (sculpt_cursor_geometry_info_update(C, &gi, mouse, true) && !alpha_overlay_active) {
if (prev_active_vertex_index != ss->active_vertex_index) {
update_previews = true;
}
float rds;
if (!BKE_brush_use_locked_size(scene, brush)) {
rds = paint_calc_object_space_radius(&vc, gi.location, BKE_brush_size_get(scene, brush));
@ -1355,6 +1360,16 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds);
}
/* Draw pose brush origin */
if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) {
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
if (update_previews) {
BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false);
sculpt_pose_calc_pose_data(sd, vc.obact, ss, gi.location, rds, ss->pose_origin, NULL);
}
cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5);
}
/* Draw 3D brush cursor */
GPU_matrix_push_projection();
ED_view3d_draw_setup_view(CTX_wm_window(C),
@ -1378,6 +1393,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
GPU_matrix_push();
GPU_matrix_mul(cursor_trans);
GPU_matrix_mul(cursor_rot);
immUniformColor3fvAlpha(outline_col, outline_alpha);
imm_draw_circle_wire_3d(pos, 0, 0, rds, 40);
GPU_matrix_pop();
@ -1390,6 +1406,17 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
sculpt_geometry_preview_lines_draw(pos, ss);
}
}
/* Draw pose brush line preview */
if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) {
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
GPU_line_width(2.0f);
immBegin(GPU_PRIM_LINES, 2);
immVertex3fv(pos, ss->pose_origin);
immVertex3fv(pos, gi.location);
immEnd();
}
GPU_matrix_pop();
GPU_matrix_pop_projection();

View File

@ -3610,13 +3610,26 @@ static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
return false;
}
static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br)
/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
*
* r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't
* be calculated. */
void sculpt_pose_calc_pose_data(Sculpt *sd,
Object *ob,
SculptSession *ss,
float initial_location[3],
float radius,
float *r_pose_origin,
float *r_pose_factor)
{
const bool calc_pose_factor = (r_pose_factor != NULL);
sculpt_vertex_random_access_init(ss);
ss->cache->pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
float pose_origin[3];
float pose_initial_co[3];
copy_v3_v3(ss->cache->pose_initial_co, ss->cache->location);
copy_v3_v3(pose_initial_co, initial_location);
char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char),
"Visited vertices");
@ -3624,13 +3637,14 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br
"not visited vertices stack");
float tot_co = 0;
zero_v3(ss->cache->pose_origin);
zero_v3(pose_origin);
VertexTopologyIterator mevit;
/* Add active vertex and symmetric vertices to the stack. */
const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
for (char i = 0; i <= symm; ++i) {
mevit.v = -1;
if (is_symmetry_iteration_valid(i, symm)) {
float location[3];
flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), (char)i);
@ -3638,8 +3652,9 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br
mevit.v = sculpt_active_vertex_get(ss);
}
else {
mevit.v = sculpt_nearest_vertex_get(
sd, ob, location, ss->cache->radius * ss->cache->radius, false);
if (calc_pose_factor) {
mevit.v = sculpt_nearest_vertex_get(sd, ob, location, radius * radius, false);
}
}
if (mevit.v != -1) {
mevit.it = 1;
@ -3660,19 +3675,19 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br
VertexTopologyIterator new_entry;
new_entry.v = ni.index;
new_entry.it = c_mevit.it + 1;
ss->cache->pose_factor[new_entry.v] = 1.0f;
if (calc_pose_factor) {
r_pose_factor[new_entry.v] = 1.0f;
}
visited_vertices[(int)ni.index] = 1;
if (sculpt_pose_brush_is_vertex_inside_brush_radius(sculpt_vertex_co_get(ss, new_entry.v),
ss->cache->pose_initial_co,
ss->cache->radius,
symm)) {
if (sculpt_pose_brush_is_vertex_inside_brush_radius(
sculpt_vertex_co_get(ss, new_entry.v), pose_initial_co, radius, symm)) {
BLI_stack_push(not_visited_vertices, &new_entry);
}
else {
if (check_vertex_pivot_symmetry(
sculpt_vertex_co_get(ss, new_entry.v), ss->cache->pose_initial_co, symm)) {
sculpt_vertex_co_get(ss, new_entry.v), pose_initial_co, symm)) {
tot_co++;
add_v3_v3(ss->cache->pose_origin, sculpt_vertex_co_get(ss, new_entry.v));
add_v3_v3(pose_origin, sculpt_vertex_co_get(ss, new_entry.v));
}
}
}
@ -3681,15 +3696,26 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br
}
BLI_stack_free(not_visited_vertices);
MEM_freeN(visited_vertices);
if (tot_co > 0) {
mul_v3_fl(ss->cache->pose_origin, 1.0f / (float)tot_co);
mul_v3_fl(pose_origin, 1.0f / (float)tot_co);
}
copy_v3_v3(r_pose_origin, pose_origin);
}
static void sculpt_pose_brush_init(
Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, float initial_location[3], float radius)
{
float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
sculpt_pose_calc_pose_data(
sd, ob, ss, initial_location, radius, ss->cache->pose_origin, pose_factor);
copy_v3_v3(ss->cache->pose_initial_co, initial_location);
ss->cache->pose_factor = pose_factor;
/* Smooth the pose brush factor for cleaner deformation */
PBVHNode **nodes;
PBVH *pbvh = ob->sculpt->pbvh;
int totnode;
@ -5078,7 +5104,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time &&
ss->cache->mirror_symmetry_pass == 0) {
if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
sculpt_pose_brush_init(sd, ob, ss, brush);
sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius);
}
}
@ -5676,6 +5702,9 @@ void sculpt_cache_free(StrokeCache *cache)
if (cache->dial) {
MEM_freeN(cache->dial);
}
if (cache->pose_factor) {
MEM_freeN(cache->pose_factor);
}
MEM_freeN(cache);
}

View File

@ -58,6 +58,13 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
const float mouse[2],
bool use_sampled_normal);
void sculpt_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
void sculpt_pose_calc_pose_data(struct Sculpt *sd,
struct Object *ob,
struct SculptSession *ss,
float initial_location[3],
float radius,
float *r_pose_origin,
float *r_pose_factor);
/* Sculpt PBVH abstraction API */
float *sculpt_vertex_co_get(struct SculptSession *ss, int index);