Page MenuHome
Paste P1098

Sculpt mode pose brush
ActivePublic

Authored by Jeroen Bakker (jbakker) on Sep 13 2019, 9:48 AM.
/* 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);
float pose_origin[3];
float pose_initial_co[3];
copy_v3_v3(pose_initial_co, initial_location);
char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char),
"Visited vertices");
BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
"not visited vertices stack");
float tot_co = 0;
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) {
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);
mevit.v = -1;
if (i == 0) {
mevit.v = sculpt_active_vertex_get(ss);
}
else {
if (calc_pose_factor) {
mevit.v = sculpt_nearest_vertex_get(sd, ob, location, radius * radius, false);
}
}
if (mevit.v != -1) {
mevit.it = 1;
BLI_stack_push(not_visited_vertices, &mevit);
}
}
}
/* Flood fill the internal pose brush factor. Calculate the pose rotation point based on the
* boundaries of the brush factor*/
while (!BLI_stack_is_empty(not_visited_vertices)) {
VertexTopologyIterator c_mevit;
BLI_stack_pop(not_visited_vertices, &c_mevit);
SculptVertexNeighborIter ni;
sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
{
if (visited_vertices[(int)ni.index] == 0) {
VertexTopologyIterator new_entry;
new_entry.v = ni.index;
new_entry.it = c_mevit.it + 1;
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), 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), pose_initial_co, symm)) {
tot_co++;
add_v3_v3(pose_origin, sculpt_vertex_co_get(ss, new_entry.v));
}
}
}
}
sculpt_vertex_neighbors_iter_end(ni)
}
BLI_stack_free(not_visited_vertices);
MEM_freeN(visited_vertices);
if (tot_co > 0) {
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;
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = br,
.nodes = nodes,
};
for (int i = 0; i < 4; i++) {
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
}
}