Array Brush: Support array editing with the voxel remesher

This commit is contained in:
Pablo Dobarro 2021-07-25 20:36:56 +02:00
parent 89897140cf
commit c1f5ac7cfe
5 changed files with 232 additions and 7 deletions

View File

@ -62,6 +62,7 @@ void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *sour
void BKE_remesh_reproject_vertex_paint(struct Mesh *target, struct Mesh *source);
void BKE_remesh_reproject_sculpt_face_sets(struct Mesh *target, struct Mesh *source);
void BKE_remesh_reproject_materials(struct Mesh *target, struct Mesh *source);
void BKE_mesh_remesh_sculpt_array_update(struct Object *ob, struct Mesh *target, struct Mesh *source);
#ifdef __cplusplus
}

View File

@ -492,6 +492,8 @@ typedef struct SculptArray {
int *copy_index;
int *symmetry_pass;
float *smooth_strength;
} SculptArray;
typedef struct SculptFakeNeighbors {

View File

@ -45,6 +45,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_remesh_voxel.h" /* own include */
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
#include "bmesh_tools.h"
@ -352,6 +353,79 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, Mesh *source)
free_bvhtree_from_mesh(&bvhtree);
}
void BKE_mesh_remesh_sculpt_array_update(Object *ob, Mesh *target, Mesh *source)
{
SculptSession *ss = ob->sculpt;
if (!ss) {
return;
}
SculptArray *array = ss->array;
if (!array) {
return;
}
BVHTreeFromMesh bvhtree = {
.nearest_callback = NULL,
};
BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2);
MVert *target_verts = CustomData_get_layer(&target->vdata, CD_MVERT);
const int target_totvert = target->totvert;
int *target_copy_index = MEM_malloc_arrayN(sizeof(int), target_totvert, "target_copy_index");
int *target_symmertry = MEM_malloc_arrayN(sizeof(int), target_totvert, "target_copy_index");
float (*target_orco)[3] = MEM_malloc_arrayN(target->totvert, sizeof(float) * 3, "array orco");
for (int i = 0; i < target_totvert; i++) {
target_copy_index[i] = -1;
target_symmertry[i] = 0;
copy_v3_v3(target_orco, target->mvert[i].co);
}
for (int i = 0; i < target->totvert; i++) {
float from_co[3];
BVHTreeNearest nearest;
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
copy_v3_v3(from_co, target_verts[i].co);
BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
if (nearest.index != -1) {
target_copy_index[i] = array->copy_index[nearest.index];
target_symmertry[i] = array->symmetry_pass[nearest.index];
}
}
free_bvhtree_from_mesh(&bvhtree);
MEM_freeN(array->copy_index);
MEM_freeN(array->symmetry_pass);
MEM_freeN(array->orco);
array->copy_index = target_copy_index;
array->symmetry_pass = target_symmertry;
array->orco = target_orco;
for (int i = 0; i < target->totvert; i++) {
int array_index = target_copy_index[i];
int array_symm_pass = target_symmertry[i];
if (array_index == -1) {
continue;
}
SculptArrayCopy *copy = &array->copies[array_symm_pass][array_index];
float co[3];
float source_origin_symm[3];
copy_v3_v3(co, target->mvert[i].co);
/* TODO: MAke symmetry work here. */
//flip_v3_v3(source_origin_symm, array->source_origin, array_symm_pass);
mul_v3_m4v3(co, array->source_imat, co);
mul_v3_m4v3(co, copy->imat, co);
sub_v3_v3v3(co, co, source_origin_symm);
copy_v3_v3(array->orco[i], co);
}
}
void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, Mesh *source)
{
BVHTreeFromMesh bvhtree = {

View File

@ -195,6 +195,10 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
BKE_remesh_reproject_vertex_paint(new_mesh, mesh);
}
if (ob->mode == OB_MODE_SCULPT) {
BKE_mesh_remesh_sculpt_array_update(ob, new_mesh, mesh);
}
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
if (smooth_normals) {

View File

@ -513,7 +513,6 @@ static void sculpt_array_update(Object *ob, Brush *brush, SculptArray *array) {
}
for (int copy_index = 0; copy_index < array->num_copies; copy_index++) {
SculptArrayCopy *copy = &array->copies[symm_pass][copy_index];
print_m4("cosa", copy->mat);
invert_m4_m4(copy->imat, copy->mat);
}
}
@ -581,6 +580,104 @@ static void sculpt_array_deform(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
0, totnode, &data, do_array_deform_task_cb_ex, &settings);
}
static void do_array_smooth_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
SculptArray *array = ss->array;
Mesh *mesh = BKE_object_get_original_mesh(data->ob);
bool any_modified = false;
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
int array_index = ARRAY_INSTANCE_ORIGINAL;
int array_symm_pass = 0;
sculpt_vertex_array_data_get(array, vd.index, &array_index, &array_symm_pass);
const float fade = array->smooth_strength[vd.index];
if (fade == 0.0f) {
continue;
}
float smooth_co[3];
SCULPT_neighbor_coords_average(ss, smooth_co, vd.index);
float disp[3];
sub_v3_v3v3(disp, smooth_co, vd.co);
mul_v3_fl(disp, fade);
add_v3_v3(vd.co, disp);
/*
if (array_index == ARRAY_INSTANCE_ORIGINAL) {
continue;
}
bool do_smooth = false;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
int neighbor_array_index = ARRAY_INSTANCE_ORIGINAL;
int neighbor_symm_pass = 0;
sculpt_vertex_array_data_get(array, ni.index, &neighbor_array_index,&neighbor_symm_pass);
if (neighbor_array_index != array_index) {
do_smooth = true;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (!do_smooth) {
continue;
}
*/
any_modified = true;
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BKE_pbvh_vertex_iter_end;
if (any_modified) {
BKE_pbvh_node_mark_update(data->nodes[n]);
}
}
static void sculpt_array_smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) {
/* Threaded loop over nodes. */
SculptSession *ss = ob->sculpt;
SculptArray *array = ss->array;
if (!array) {
return;
}
if (!array->smooth_strength) {
return;
}
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.nodes = nodes,
};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(
0, totnode, &data, do_array_smooth_task_cb_ex, &settings);
}
static void sculpt_array_ensure_original_coordinates(Object *ob, SculptArray *array){
SculptSession *ss = ob->sculpt;
Mesh *sculpt_mesh = BKE_object_get_original_mesh(ob);
@ -690,9 +787,56 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
}
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
SculptArray *array = ss->array;
const int totvert = SCULPT_vertex_count_get(ss);
/* Rebuild smooth strength cache. */
MEM_SAFE_FREE(array->smooth_strength);
array->smooth_strength = MEM_calloc_arrayN(sizeof(float), totvert, "smooth_strength");
for (int i = 0; i < totvert; i++) {
int array_index = ARRAY_INSTANCE_ORIGINAL;
int array_symm_pass = 0;
sculpt_vertex_array_data_get(array, i, &array_index, &array_symm_pass);
if (array_index == ARRAY_INSTANCE_ORIGINAL) {
continue;
}
/* TODO: this can be cached. */
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
int neighbor_array_index = ARRAY_INSTANCE_ORIGINAL;
int neighbor_symm_pass = 0;
sculpt_vertex_array_data_get(array, ni.index, &neighbor_array_index,&neighbor_symm_pass);
if (neighbor_array_index != array_index) {
array->smooth_strength[i] = 1.0f;
break;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
for(int smooth_iterations = 0; smooth_iterations < 4; smooth_iterations++) {
for (int i = 0; i < totvert; i++) {
float avg = array->smooth_strength[i];
int count = 1;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
avg += array->smooth_strength[ni.index];
count++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
array->smooth_strength[i] = avg / count;
}
}
/* Update Array Path Orco. */
SculptArray *array = ss->array;
for (int i = 0; i < array->path.tot_points; i++) {
ScultpArrayPathPoint *point = &array->path.points[i];
copy_v3_v3(point->orco, point->co);
@ -700,7 +844,6 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
array->initial_radial_angle = array->radial_angle;
/* Update Geometry Orco. */
const int totvert = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totvert; i++) {
int array_index = ARRAY_INSTANCE_ORIGINAL;
int array_symm_pass = 0;
@ -715,9 +858,9 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
float source_origin_symm[3];
copy_v3_v3(co, SCULPT_vertex_co_get(ss, i));
flip_v3_v3(source_origin_symm, array->source_origin, array_symm_pass);
mul_v3_m4v3(co, array->source_imat, co);
mul_v3_m4v3(co, copy->imat, co);
sub_v3_v3v3(co, co, source_origin_symm);
mul_v3_m4v3(co, array->source_imat, co);
//sub_v3_v3v3(co, co, source_origin_symm);
copy_v3_v3(array->orco[i], co);
}
@ -757,12 +900,13 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
normalize_v3(brush_co);
normalize_v3_v3(array_disp_co, sculpt_array_delta_from_path(array));
array->radial_angle = angle_signed_on_axis_v3v3_v3(brush_co, array_disp_co, array->normal);
}
sculpt_array_update(ob, brush, ss->array);
sculpt_array_deform(sd, ob, nodes, totnode);
for (int i = 0; i < 5; i++) {
sculpt_array_smooth(sd, ob, nodes, totnode);
}
return;